From 6e87eee2a0494e11610e5535427a9f86ccffa4bb Mon Sep 17 00:00:00 2001 From: Mike Reed Date: Thu, 18 Jan 2018 16:06:54 -0500 Subject: add shadermaskfilter next steps: - gpu impl (will look a lot like shader's asFragProcessor - special-case rect-input (?) - explore stages w/ mtklein Bug: skia:7500 Change-Id: I71089e421d32443a3ddded6967b3e5bc67ed43f2 Reviewed-on: https://skia-review.googlesource.com/95104 Commit-Queue: Mike Reed Reviewed-by: Florin Malita Reviewed-by: Brian Salomon --- src/effects/SkShaderMaskFilter.cpp | 117 +++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/effects/SkShaderMaskFilter.cpp (limited to 'src/effects') 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 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 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 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 SkShaderMaskFilter::Make(sk_sp shader) { + return shader ? sk_sp(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 -- cgit v1.2.3