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 "include/core/SkCanvas.h" |
9 | #include "include/core/SkString.h" |
10 | #include "include/effects/SkShaderMaskFilter.h" |
11 | #include "src/core/SkMaskFilterBase.h" |
12 | #include "src/core/SkReadBuffer.h" |
13 | #include "src/shaders/SkShaderBase.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 "src/gpu/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 | |