1 /* 2 * Copyright 2018 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkCanvas.h" 9 #include "SkMaskFilterBase.h" 10 #include "SkReadBuffer.h" 11 #include "SkShaderMaskFilter.h" 12 #include "SkShaderBase.h" 13 #include "SkString.h" 14 15 class SkShaderMF : public SkMaskFilterBase { 16 public: 17 SkShaderMF(sk_sp<SkShader> shader) : fShader(std::move(shader)) {} 18 19 SkMask::Format getFormat() const override { return SkMask::kA8_Format; } 20 21 bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, 22 SkIPoint* margin) const override; 23 24 void computeFastBounds(const SkRect& src, SkRect* dst) const override { 25 *dst = src; 26 } 27 28 bool asABlur(BlurRec*) const override { return false; } 29 30 protected: 31 #if SK_SUPPORT_GPU 32 std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs&) const override; 33 bool onHasFragmentProcessor() const override; 34 #endif 35 36 private: 37 SK_FLATTENABLE_HOOKS(SkShaderMF) 38 39 sk_sp<SkShader> fShader; 40 41 SkShaderMF(SkReadBuffer&); 42 void flatten(SkWriteBuffer&) const override; 43 44 friend class SkShaderMaskFilter; 45 46 typedef SkMaskFilter INHERITED; 47 }; 48 49 sk_sp<SkFlattenable> SkShaderMF::CreateProc(SkReadBuffer& buffer) { 50 return SkShaderMaskFilter::Make(buffer.readShader()); 51 } 52 53 void SkShaderMF::flatten(SkWriteBuffer& buffer) const { 54 buffer.writeFlattenable(fShader.get()); 55 } 56 57 static void rect_memcpy(void* dst, size_t dstRB, const void* src, size_t srcRB, 58 size_t copyBytes, int rows) { 59 for (int i = 0; i < rows; ++i) { 60 memcpy(dst, src, copyBytes); 61 dst = (char*)dst + dstRB; 62 src = (const char*)src + srcRB; 63 } 64 } 65 66 bool SkShaderMF::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm, 67 SkIPoint* margin) const { 68 if (src.fFormat != SkMask::kA8_Format) { 69 return false; 70 } 71 72 if (margin) { 73 margin->set(0, 0); 74 } 75 dst->fBounds = src.fBounds; 76 dst->fRowBytes = src.fBounds.width(); // need alignment? 77 dst->fFormat = SkMask::kA8_Format; 78 79 if (src.fImage == nullptr) { 80 dst->fImage = nullptr; 81 return true; 82 } 83 size_t size = dst->computeImageSize(); 84 if (0 == size) { 85 return false; // too big to allocate, abort 86 } 87 88 // Allocate and initialize dst image with a copy of the src image 89 dst->fImage = SkMask::AllocImage(size); 90 rect_memcpy(dst->fImage, dst->fRowBytes, src.fImage, src.fRowBytes, 91 src.fBounds.width() * sizeof(uint8_t), src.fBounds.height()); 92 93 // Now we have a dst-mask, just need to setup a canvas and draw into it 94 SkBitmap bitmap; 95 if (!bitmap.installMaskPixels(*dst)) { 96 return false; 97 } 98 99 SkPaint paint; 100 paint.setShader(fShader); 101 paint.setFilterQuality(SkFilterQuality::kLow_SkFilterQuality); 102 // this blendmode is the trick: we only draw the shader where the mask is 103 paint.setBlendMode(SkBlendMode::kSrcIn); 104 105 SkCanvas canvas(bitmap); 106 canvas.translate(-SkIntToScalar(dst->fBounds.fLeft), -SkIntToScalar(dst->fBounds.fTop)); 107 canvas.concat(ctm); 108 canvas.drawPaint(paint); 109 return true; 110 } 111 112 /////////////////////////////////////////////////////////////////////////////////////////////////// 113 #if SK_SUPPORT_GPU 114 #include "GrFragmentProcessor.h" 115 116 std::unique_ptr<GrFragmentProcessor> SkShaderMF::onAsFragmentProcessor(const GrFPArgs& args) const { 117 return GrFragmentProcessor::MulInputByChildAlpha(as_SB(fShader)->asFragmentProcessor(args)); 118 } 119 120 bool SkShaderMF::onHasFragmentProcessor() const { 121 return true; 122 } 123 124 #endif 125 /////////////////////////////////////////////////////////////////////////////////////////////////// 126 127 sk_sp<SkMaskFilter> SkShaderMaskFilter::Make(sk_sp<SkShader> shader) { 128 return shader ? sk_sp<SkMaskFilter>(new SkShaderMF(std::move(shader))) : nullptr; 129 } 130 131 void SkShaderMaskFilter::RegisterFlattenables() { SK_REGISTER_FLATTENABLE(SkShaderMF); } 132