aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/shadermaskfilter.cpp57
-rw-r--r--gn/effects.gni1
-rw-r--r--gn/gm.gni1
-rw-r--r--include/effects/SkShaderMaskFilter.h24
-rw-r--r--src/effects/SkShaderMaskFilter.cpp117
-rw-r--r--src/ports/SkGlobalInitialization_default.cpp2
6 files changed, 202 insertions, 0 deletions
diff --git a/gm/shadermaskfilter.cpp b/gm/shadermaskfilter.cpp
new file mode 100644
index 0000000000..35d8fd7040
--- /dev/null
+++ b/gm/shadermaskfilter.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 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 "sk_tool_utils.h"
+#include "SkCanvas.h"
+#include "SkImage.h"
+#include "SkShaderMaskFilter.h"
+
+static void draw_masked_image(SkCanvas* canvas, const SkImage* image, SkScalar x, SkScalar y,
+ const SkImage* mask) {
+ SkMatrix matrix = SkMatrix::MakeScale(SkIntToScalar(image->width()) / mask->width(),
+ SkIntToScalar(image->height() / mask->height()));
+ SkPaint paint;
+ paint.setMaskFilter(SkShaderMaskFilter::Make(mask->makeShader(&matrix)));
+ canvas->drawImage(image, x, y, &paint);
+}
+
+#include "SkGradientShader.h"
+static sk_sp<SkShader> make_shader(const SkRect& r) {
+ const SkPoint pts[] = {
+ { r.fLeft, r.fTop }, { r.fRight, r.fBottom },
+ };
+ const SkColor colors[] = { 0, SK_ColorWHITE };
+ return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kRepeat_TileMode);
+}
+
+DEF_SIMPLE_GM(shadermaskfilter_gradient, canvas, 512, 512) {
+ SkRect r = { 0, 0, 100, 150 };
+ auto shader = make_shader(r);
+ auto mf = SkShaderMaskFilter::Make(shader);
+
+ canvas->translate(20, 20);
+ canvas->scale(2, 2);
+
+ SkPaint paint;
+ paint.setMaskFilter(mf);
+ paint.setColor(SK_ColorRED);
+ canvas->drawOval(r, paint);
+}
+
+#include "Resources.h"
+DEF_SIMPLE_GM(shadermaskfilter_image, canvas, 512, 512) {
+ canvas->scale(1.25f, 1.25f);
+
+ auto image = GetResourceAsImage("images/mandrill_128.png");
+ auto mask = GetResourceAsImage("images/color_wheel.png");
+
+ canvas->drawImage(image, 10, 10, nullptr);
+ canvas->drawImage(mask, 10 + image->width() + 10.f, 10, nullptr);
+
+ draw_masked_image(canvas, image.get(), 10, 10 + image->height() + 10.f, mask.get());
+}
diff --git a/gn/effects.gni b/gn/effects.gni
index da0ce8c06b..09fac9f474 100644
--- a/gn/effects.gni
+++ b/gn/effects.gni
@@ -52,6 +52,7 @@ skia_effects_sources = [
"$_src/effects/SkPaintImageFilter.cpp",
"$_src/effects/SkPictureImageFilter.cpp",
"$_src/effects/SkRRectsGaussianEdgeMaskFilter.cpp",
+ "$_src/effects/SkShaderMaskFilter.cpp",
"$_src/effects/SkTableColorFilter.cpp",
"$_src/effects/SkTableMaskFilter.cpp",
"$_src/effects/SkTileImageFilter.cpp",
diff --git a/gn/gm.gni b/gn/gm.gni
index 38aaff3fa8..a19d4074aa 100644
--- a/gn/gm.gni
+++ b/gn/gm.gni
@@ -263,6 +263,7 @@ gm_sources = [
"$_gm/samplerstress.cpp",
"$_gm/savelayer.cpp",
"$_gm/scaledstrokes.cpp",
+ "$_gm/shadermaskfilter.cpp",
"$_gm/shadertext.cpp",
"$_gm/shadertext2.cpp",
"$_gm/shadertext3.cpp",
diff --git a/include/effects/SkShaderMaskFilter.h b/include/effects/SkShaderMaskFilter.h
new file mode 100644
index 0000000000..4ebc4fc468
--- /dev/null
+++ b/include/effects/SkShaderMaskFilter.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkShaderMaskFilter_DEFINED
+#define SkShaderMaskFilter_DEFINED
+
+#include "SkMaskFilter.h"
+
+class SkShader;
+
+class SK_API SkShaderMaskFilter {
+public:
+ static sk_sp<SkMaskFilter> Make(sk_sp<SkShader> shader);
+
+private:
+ static void InitializeFlattenables();
+ friend class SkFlattenable;
+};
+
+#endif
diff --git a/src/effects/SkShaderMaskFilter.cpp b/src/effects/SkShaderMaskFilter.cpp
new file mode 100644
index 0000000000..8693751899
--- /dev/null
+++ b/src/effects/SkShaderMaskFilter.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCanvas.h"
+#include "SkReadBuffer.h"
+#include "SkShaderMaskFilter.h"
+#include "SkShader.h"
+#include "SkString.h"
+
+class SkShaderMF : public SkMaskFilter {
+public:
+ SkShaderMF(sk_sp<SkShader> shader) : fShader(std::move(shader)) {}
+
+ SkMask::Format getFormat() const override { return SkMask::kA8_Format; }
+
+ bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
+ SkIPoint* margin) const override;
+
+ void computeFastBounds(const SkRect& src, SkRect* dst) const override {
+ *dst = src;
+ }
+
+ bool asABlur(BlurRec*) const override { return false; }
+
+ SK_TO_STRING_OVERRIDE()
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkShaderMF)
+
+private:
+ sk_sp<SkShader> fShader;
+
+ SkShaderMF(SkReadBuffer&);
+ void flatten(SkWriteBuffer&) const override;
+
+ friend class SkShaderMaskFilter;
+
+ typedef SkMaskFilter INHERITED;
+};
+
+#ifndef SK_IGNORE_TO_STRING
+void SkShaderMF::toString(SkString* str) const {
+ str->set("SkShaderMF:");
+}
+#endif
+
+sk_sp<SkFlattenable> SkShaderMF::CreateProc(SkReadBuffer& buffer) {
+ return SkShaderMaskFilter::Make(buffer.readShader());
+}
+
+void SkShaderMF::flatten(SkWriteBuffer& buffer) const {
+ buffer.writeFlattenable(fShader.get());
+}
+
+static void rect_memcpy(void* dst, size_t dstRB, const void* src, size_t srcRB,
+ size_t copyBytes, int rows) {
+ for (int i = 0; i < rows; ++i) {
+ memcpy(dst, src, copyBytes);
+ dst = (char*)dst + dstRB;
+ src = (const char*)src + srcRB;
+ }
+}
+
+bool SkShaderMF::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm,
+ SkIPoint* margin) const {
+ SkASSERT(src.fFormat == SkMask::kA8_Format);
+
+ if (margin) {
+ margin->set(0, 0);
+ }
+ dst->fBounds = src.fBounds;
+ dst->fRowBytes = src.fBounds.width(); // need alignment?
+ dst->fFormat = SkMask::kA8_Format;
+
+ if (src.fImage == nullptr) {
+ dst->fImage = nullptr;
+ return true;
+ }
+ size_t size = dst->computeImageSize();
+ if (0 == size) {
+ return false; // too big to allocate, abort
+ }
+
+ // Allocate and initialize dst image with a copy of the src image
+ dst->fImage = SkMask::AllocImage(size);
+ rect_memcpy(dst->fImage, dst->fRowBytes, src.fImage, src.fRowBytes,
+ src.fBounds.width() * sizeof(uint8_t), src.fBounds.height());
+
+ // Now we have a dst-mask, just need to setup a canvas and draw into it
+ SkBitmap bitmap;
+ if (!bitmap.installMaskPixels(*dst)) {
+ return false;
+ }
+
+ SkPaint paint;
+ paint.setShader(fShader);
+ // this blendmode is the trick: we only draw the shader where the mask is
+ paint.setBlendMode(SkBlendMode::kSrcIn);
+
+ SkCanvas canvas(bitmap);
+ canvas.translate(-SkIntToScalar(dst->fBounds.fLeft), -SkIntToScalar(dst->fBounds.fTop));
+ canvas.concat(ctm);
+ canvas.drawPaint(paint);
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+sk_sp<SkMaskFilter> SkShaderMaskFilter::Make(sk_sp<SkShader> shader) {
+ return shader ? sk_sp<SkMaskFilter>(new SkShaderMF(std::move(shader))) : nullptr;
+}
+
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShaderMaskFilter)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkShaderMF)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
diff --git a/src/ports/SkGlobalInitialization_default.cpp b/src/ports/SkGlobalInitialization_default.cpp
index c1256ef85c..a98083aa7f 100644
--- a/src/ports/SkGlobalInitialization_default.cpp
+++ b/src/ports/SkGlobalInitialization_default.cpp
@@ -37,6 +37,7 @@
#include "SkPerlinNoiseShader.h"
#include "SkPictureImageFilter.h"
#include "SkRRectsGaussianEdgeMaskFilter.h"
+#include "SkShaderMaskFilter.h"
#include "SkTableColorFilter.h"
#include "SkTileImageFilter.h"
#include "SkToSRGBColorFilter.h"
@@ -64,6 +65,7 @@ void SkFlattenable::PrivateInitializer::InitEffects() {
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkEmbossMaskFilter)
SkBlurMaskFilter::InitializeFlattenables();
SkRRectsGaussianEdgeMaskFilter::InitializeFlattenables();
+ SkShaderMaskFilter::InitializeFlattenables();
// DrawLooper
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerDrawLooper)