aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--fuzz/FuzzCanvas.cpp4
-rw-r--r--gm/gaussianedge.cpp222
-rw-r--r--gm/reveal.cpp17
-rw-r--r--gn/effects.gni2
-rw-r--r--gn/gm.gni1
-rw-r--r--samplecode/SampleAndroidShadows.cpp1
-rwxr-xr-xsamplecode/SampleShadowUtils.cpp1
-rw-r--r--src/effects/SkGaussianEdgeShader.cpp95
-rw-r--r--src/effects/SkGaussianEdgeShader.h27
-rw-r--r--src/ports/SkGlobalInitialization_default.cpp2
10 files changed, 369 insertions, 3 deletions
diff --git a/fuzz/FuzzCanvas.cpp b/fuzz/FuzzCanvas.cpp
index fb90c06305..aec9173a16 100644
--- a/fuzz/FuzzCanvas.cpp
+++ b/fuzz/FuzzCanvas.cpp
@@ -38,6 +38,7 @@
#include "SkDiscretePathEffect.h"
#include "SkDisplacementMapEffect.h"
#include "SkDropShadowImageFilter.h"
+#include "SkGaussianEdgeShader.h"
#include "SkGradientShader.h"
#include "SkHighContrastFilter.h"
#include "SkImageSource.h"
@@ -381,8 +382,7 @@ static sk_sp<SkShader> make_fuzz_shader(Fuzz* fuzz, int depth) {
}
// EFFECTS:
case 9:
- // Deprecated SkGaussianEdgeShader
- return nullptr;
+ return SkGaussianEdgeShader::Make();
case 10: {
constexpr int kMaxColors = 12;
SkPoint pts[2];
diff --git a/gm/gaussianedge.cpp b/gm/gaussianedge.cpp
new file mode 100644
index 0000000000..eca8495821
--- /dev/null
+++ b/gm/gaussianedge.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkColorFilter.h"
+#include "SkGaussianEdgeShader.h"
+#include "SkRRect.h"
+
+//#define VIZ 1
+
+#ifdef VIZ
+#include "SkStroke.h"
+
+static void draw_stroke(SkCanvas* canvas, const SkRRect& rr, const SkPaint& p, SkColor color) {
+ SkPath output;
+
+ if (SkPaint::kFill_Style == p.getStyle()) {
+ output.addRRect(rr);
+ } else {
+ SkPath input;
+ input.addRRect(rr);
+
+ SkStroke stroke(p);
+ stroke.strokePath(input, &output);
+ }
+
+ SkPaint paint;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(color);
+
+ canvas->drawPath(output, paint);
+}
+
+static void extract_pts(const SkBitmap& bm, SkTDArray<SkPoint>* pts,
+ int xOff, int width) {
+ pts->rewind();
+
+ for (int x = 0; x < width; ++x) {
+ SkColor color = bm.getColor(xOff+x, 0);
+
+ pts->append()->set(SkIntToScalar(x), 255.0f-SkColorGetB(color));
+ if (x > 0 && x < width-1) {
+ pts->append()->set(SkIntToScalar(x), 255.0f-SkColorGetB(color));
+ }
+ }
+}
+
+static void draw_row(SkCanvas* canvas, int row, int width) {
+ SkPaint paint;
+ paint.setAntiAlias(true);
+
+ SkBitmap readback;
+
+ if (!canvas->readPixels(SkIRect::MakeXYWH(0, row, width, 1), &readback)) {
+ return;
+ }
+
+ SkTDArray<SkPoint> pts;
+ pts.setReserve(width/3);
+
+ extract_pts(readback, &pts, 0, width/3);
+ paint.setColor(SK_ColorRED);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, pts.count(), pts.begin(), paint);
+
+ extract_pts(readback, &pts, width/3, width/3);
+ paint.setColor(SK_ColorGREEN);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, pts.count(), pts.begin(), paint);
+
+ extract_pts(readback, &pts, 2*width/3, width/3);
+ paint.setColor(SK_ColorBLUE);
+ canvas->drawPoints(SkCanvas::kLines_PointMode, pts.count(), pts.begin(), paint);
+}
+#endif
+
+namespace skiagm {
+
+// This GM exercises the SkGaussianEdgeShader.
+// It draws three columns showing filled, stroked, and stroke and filled rendering.
+// It draws three rows showing a blur radius smaller than, equal to
+// and, finally, double the RRect's corner radius
+// In VIZ mode an extra column is drawn showing the blur ramps (they should all line up).
+class GaussianEdgeGM : public GM {
+public:
+ GaussianEdgeGM() {
+ this->setBGColor(SK_ColorWHITE);
+ }
+
+protected:
+
+ SkString onShortName() override {
+ return SkString("gaussianedge");
+ }
+
+ SkISize onISize() override {
+ int numCols = kNumBaseCols;
+#ifdef VIZ
+ numCols++;
+#endif
+
+ return SkISize::Make(kPad + numCols*(kCellWidth+kPad),
+ kPad + kNumRows*(kCellWidth+kPad));
+ }
+
+ static void DrawRow(SkCanvas* canvas, int blurRad, int midLine) {
+ SkAutoCanvasRestore acr(canvas, true);
+
+ SkRRect rrects[kNumBaseCols];
+ SkPaint paints[kNumBaseCols];
+
+ {
+ const SkRect r = SkRect::MakeIWH(kRRSize, kRRSize);
+ const SkRRect baseRR = SkRRect::MakeRectXY(r,
+ SkIntToScalar(kRRRad),
+ SkIntToScalar(kRRRad));
+
+ SkPaint basePaint;
+ basePaint.setAntiAlias(true);
+ basePaint.setColor(SkColorSetARGB(255, (4 * blurRad) >> 8, (4 * blurRad) & 0xff, 0));
+ basePaint.setShader(SkGaussianEdgeShader::Make());
+ basePaint.setColorFilter(SkColorFilter::MakeModeFilter(SK_ColorRED,
+ SkBlendMode::kModulate));
+
+ //----
+ paints[0] = basePaint;
+ rrects[0] = baseRR;
+
+ //----
+ paints[1] = basePaint;
+ paints[1].setStyle(SkPaint::kStroke_Style);
+
+ rrects[1] = baseRR;
+ if (blurRad/2.0f < kRRRad) {
+ rrects[1].inset(blurRad/2.0f, blurRad/2.0f);
+ paints[1].setStrokeWidth(SkIntToScalar(blurRad));
+ } else {
+ SkScalar inset = kRRRad - 0.5f;
+ rrects[1].inset(inset, inset);
+ SkScalar pad = blurRad/2.0f - inset;
+ paints[1].setStrokeWidth(blurRad + 2.0f * pad);
+ paints[1].setColor(SkColorSetARGB(255, (4 * blurRad) >> 8, (4 * blurRad) & 0xff,
+ (int)(4.0f*pad)));
+ }
+
+ //----
+ paints[2] = basePaint;
+ paints[2].setStyle(SkPaint::kStrokeAndFill_Style);
+
+ rrects[2] = baseRR;
+ if (blurRad/2.0f < kRRRad) {
+ rrects[2].inset(blurRad/2.0f, blurRad/2.0f);
+ paints[2].setStrokeWidth(SkIntToScalar(blurRad));
+ } else {
+ SkScalar inset = kRRRad - 0.5f;
+ rrects[2].inset(inset, inset);
+ SkScalar pad = blurRad/2.0f - inset;
+ paints[2].setStrokeWidth(blurRad + 2.0f * pad);
+ paints[2].setColor(SkColorSetARGB(255, (4 * blurRad) >> 8, (4 * blurRad) & 0xff,
+ (int)(4.0f*pad)));
+ }
+ }
+
+ //----
+ canvas->save();
+ // draw the shadows
+ for (int i = 0; i < kNumBaseCols; ++i) {
+ canvas->drawRRect(rrects[i], paints[i]);
+ canvas->translate(SkIntToScalar(kCellWidth+kPad), 0.0f);
+ }
+
+#ifdef VIZ
+ // draw the visualization of the shadow ramps
+ draw_row(canvas, midLine, 3*(kRRSize+kPad));
+#endif
+ canvas->restore();
+
+#ifdef VIZ
+ const SkColor colors[kNumBaseCols] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
+
+ // circle back and draw the stroked geometry (they would mess up the viz otherwise)
+ for (int i = 0; i < kNumBaseCols; ++i) {
+ draw_stroke(canvas, rrects[i], paints[i], colors[i]);
+ canvas->translate(SkIntToScalar(kCellWidth+kPad), 0.0f);
+ }
+#endif
+ }
+
+ void onDraw(SkCanvas* canvas) override {
+ GrRenderTargetContext* renderTargetContext =
+ canvas->internal_private_accessTopLayerRenderTargetContext();
+ if (!renderTargetContext) {
+ skiagm::GM::DrawGpuOnlyMessage(canvas);
+ return;
+ }
+
+ const int blurRadii[kNumRows] = { kRRRad/2, kRRRad, 2*kRRRad };
+
+ canvas->translate(SkIntToScalar(kPad), SkIntToScalar(kPad));
+ for (int i = 0; i < kNumRows; ++i) {
+ DrawRow(canvas, blurRadii[i], kPad+(i*kRRSize)+kRRSize/2);
+ canvas->translate(0.0f, SkIntToScalar(kCellWidth+kPad));
+ }
+ }
+
+private:
+ static const int kNumRows = 3;
+ static const int kNumBaseCols = 3;
+ static const int kPad = 5;
+ static const int kRRSize = 256;
+ static const int kRRRad = 64;
+ static const int kCellWidth = kRRSize;
+
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+DEF_GM(return new GaussianEdgeGM;)
+}
diff --git a/gm/reveal.cpp b/gm/reveal.cpp
index a793b2da54..3e465556ad 100644
--- a/gm/reveal.cpp
+++ b/gm/reveal.cpp
@@ -9,6 +9,7 @@
#include "sk_tool_utils.h"
#include "SkAnimTimer.h"
#include "SkBlurMaskFilter.h"
+#include "SkGaussianEdgeShader.h"
#include "SkRRectsGaussianEdgeMaskFilter.h"
#include "SkPath.h"
#include "SkPathOps.h"
@@ -313,6 +314,7 @@ namespace skiagm {
class RevealGM : public GM {
public:
enum Mode {
+ kGaussianEdge_Mode,
kBlurMask_Mode,
kRRectsGaussianEdge_Mode,
@@ -384,7 +386,20 @@ protected:
// The goal is to replace this clipped draw (which clips the
// shadow) with a draw using the geometric clip
- if (kBlurMask_Mode == fMode) {
+ if (kGaussianEdge_Mode == fMode) {
+ canvas->save();
+ clipObj->clip(canvas);
+
+ // Draw with GaussianEdgeShader
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ // G channel is an F6.2 radius
+ int iBlurRad = (int)(4.0f * fBlurRadius);
+ paint.setColor(SkColorSetARGB(255, iBlurRad >> 8, iBlurRad & 0xFF, 0));
+ paint.setShader(SkGaussianEdgeShader::Make());
+ drawObj->draw(canvas, paint);
+ canvas->restore();
+ } else if (kBlurMask_Mode == fMode) {
SkPath clippedPath;
SkScalar sigma = fBlurRadius / 4.0f;
diff --git a/gn/effects.gni b/gn/effects.gni
index 61b1b39424..3fd8e531a6 100644
--- a/gn/effects.gni
+++ b/gn/effects.gni
@@ -38,6 +38,8 @@ skia_effects_sources = [
"$_src/effects/SkEmbossMask_Table.h",
"$_src/effects/SkEmbossMaskFilter.cpp",
"$_src/effects/SkImageSource.cpp",
+ "$_src/effects/SkGaussianEdgeShader.cpp",
+ "$_src/effects/SkGaussianEdgeShader.h",
"$_src/effects/SkHighContrastFilter.cpp",
"$_src/effects/SkLayerDrawLooper.cpp",
"$_src/effects/SkLayerRasterizer.cpp",
diff --git a/gn/gm.gni b/gn/gm.gni
index 3f670dd5b1..2eb9a1659e 100644
--- a/gn/gm.gni
+++ b/gn/gm.gni
@@ -135,6 +135,7 @@ gm_sources = [
"$_gm/gammaencodedpremul.cpp",
"$_gm/gammatext.cpp",
"$_gm/gamut.cpp",
+ "$_gm/gaussianedge.cpp",
"$_gm/getpostextpath.cpp",
"$_gm/giantbitmap.cpp",
"$_gm/glyph_pos.cpp",
diff --git a/samplecode/SampleAndroidShadows.cpp b/samplecode/SampleAndroidShadows.cpp
index 0f133404e8..5b070642bb 100644
--- a/samplecode/SampleAndroidShadows.cpp
+++ b/samplecode/SampleAndroidShadows.cpp
@@ -12,6 +12,7 @@
#include "SkColorFilter.h"
#include "SkCamera.h"
#include "SkCanvas.h"
+#include "SkGaussianEdgeShader.h"
#include "SkPath.h"
#include "SkPathOps.h"
#include "SkPoint3.h"
diff --git a/samplecode/SampleShadowUtils.cpp b/samplecode/SampleShadowUtils.cpp
index c37d8d2b28..8d8a0aeaf6 100755
--- a/samplecode/SampleShadowUtils.cpp
+++ b/samplecode/SampleShadowUtils.cpp
@@ -12,6 +12,7 @@
#include "SkColorFilter.h"
#include "SkCamera.h"
#include "SkCanvas.h"
+#include "SkGaussianEdgeShader.h"
#include "SkPath.h"
#include "SkPathOps.h"
#include "SkPoint3.h"
diff --git a/src/effects/SkGaussianEdgeShader.cpp b/src/effects/SkGaussianEdgeShader.cpp
new file mode 100644
index 0000000000..c710b949d3
--- /dev/null
+++ b/src/effects/SkGaussianEdgeShader.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkGaussianEdgeShader.h"
+#include "SkReadBuffer.h"
+#include "SkWriteBuffer.h"
+
+class SkArenaAlloc;
+
+ /** \class SkGaussianEdgeShaderImpl
+ This subclass of shader applies a Gaussian to shadow edge
+
+ If the primitive supports an implicit distance to the edge, the radius of the blur is specified
+ by r & g values of the color in 14.2 fixed point. For spot shadows, we increase the stroke width
+ to set the shadow against the shape. This pad is specified by b, also in 6.2 fixed point.
+
+ When not using implicit distance, then b in the input color represents the input to the
+ blur function.
+ */
+class SkGaussianEdgeShaderImpl : public SkShaderBase {
+public:
+ SkGaussianEdgeShaderImpl() {}
+
+ bool isOpaque() const override;
+
+#if SK_SUPPORT_GPU
+ sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
+#endif
+
+ SK_TO_STRING_OVERRIDE()
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkGaussianEdgeShaderImpl)
+
+protected:
+ void flatten(SkWriteBuffer&) const override;
+ Context* onMakeContext(const ContextRec& rec, SkArenaAlloc* storage) const override {
+ return nullptr;
+ }
+private:
+ friend class SkGaussianEdgeShader;
+
+ typedef SkShaderBase INHERITED;
+};
+
+////////////////////////////////////////////////////////////////////////////
+
+#if SK_SUPPORT_GPU
+
+#include "effects/GrBlurredEdgeFragmentProcessor.h"
+
+////////////////////////////////////////////////////////////////////////////
+
+sk_sp<GrFragmentProcessor> SkGaussianEdgeShaderImpl::asFragmentProcessor(const AsFPArgs&) const {
+ return GrBlurredEdgeFP::Make(GrBlurredEdgeFP::kGaussian_Mode);
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////
+
+bool SkGaussianEdgeShaderImpl::isOpaque() const {
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+#ifndef SK_IGNORE_TO_STRING
+void SkGaussianEdgeShaderImpl::toString(SkString* str) const {
+ str->appendf("GaussianEdgeShader: ()");
+}
+#endif
+
+sk_sp<SkFlattenable> SkGaussianEdgeShaderImpl::CreateProc(SkReadBuffer& buf) {
+ return sk_make_sp<SkGaussianEdgeShaderImpl>();
+}
+
+void SkGaussianEdgeShaderImpl::flatten(SkWriteBuffer& buf) const {
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+sk_sp<SkShader> SkGaussianEdgeShader::Make() {
+ return sk_make_sp<SkGaussianEdgeShaderImpl>();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGaussianEdgeShader)
+SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkGaussianEdgeShaderImpl)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
+
+///////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/SkGaussianEdgeShader.h b/src/effects/SkGaussianEdgeShader.h
new file mode 100644
index 0000000000..f0554dd0a7
--- /dev/null
+++ b/src/effects/SkGaussianEdgeShader.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkGaussianEdgeShader_DEFINED
+#define SkGaussianEdgeShader_DEFINED
+
+#include "SkShaderBase.h"
+
+class SK_API SkGaussianEdgeShader {
+public:
+ /** Returns a shader that applies a Gaussian blur depending on distance to the edge
+ * Currently this is only useable with Circle and RRect shapes on the GPU backend.
+ * Raster will draw nothing.
+ */
+ static sk_sp<SkShader> Make();
+
+ SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
+
+private:
+ SkGaussianEdgeShader(); // can't be instantiated
+};
+
+#endif
diff --git a/src/ports/SkGlobalInitialization_default.cpp b/src/ports/SkGlobalInitialization_default.cpp
index de9b61ae9c..8052417ca8 100644
--- a/src/ports/SkGlobalInitialization_default.cpp
+++ b/src/ports/SkGlobalInitialization_default.cpp
@@ -22,6 +22,7 @@
#include "SkDisplacementMapEffect.h"
#include "SkDropShadowImageFilter.h"
#include "../../src/effects/SkEmbossMaskFilter.h"
+#include "../../src/effects/SkGaussianEdgeShader.h"
#include "SkGradientShader.h"
#include "SkHighContrastFilter.h"
#include "SkImageSource.h"
@@ -91,6 +92,7 @@ void SkFlattenable::PrivateInitializer::InitEffects() {
SkGradientShader::InitializeFlattenables();
SkLightingShader::InitializeFlattenables();
SkNormalSource::InitializeFlattenables();
+ SkGaussianEdgeShader::InitializeFlattenables();
// PathEffect
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkArcToPathEffect)