1 /*
2  * Copyright 2006 The Android Open Source Project
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 "src/core/SkMaskFilterBase.h"
9 
10 #include "include/core/SkPath.h"
11 #include "include/core/SkRRect.h"
12 #include "src/core/SkAutoMalloc.h"
13 #include "src/core/SkBlitter.h"
14 #include "src/core/SkBlurPriv.h"
15 #include "src/core/SkCachedData.h"
16 #include "src/core/SkCoverageModePriv.h"
17 #include "src/core/SkDraw.h"
18 #include "src/core/SkPathPriv.h"
19 #include "src/core/SkRasterClip.h"
20 #include "src/core/SkReadBuffer.h"
21 #include "src/core/SkWriteBuffer.h"
22 
23 #if SK_SUPPORT_GPU
24 #include "src/gpu/GrFragmentProcessor.h"
25 #include "src/gpu/GrTextureProxy.h"
26 #include "src/gpu/effects/GrXfermodeFragmentProcessor.h"
27 #include "src/gpu/text/GrSDFMaskFilter.h"
28 #endif
29 
~NinePatch()30 SkMaskFilterBase::NinePatch::~NinePatch() {
31     if (fCache) {
32         SkASSERT((const void*)fMask.fImage == fCache->data());
33         fCache->unref();
34     } else {
35         SkMask::FreeImage(fMask.fImage);
36     }
37 }
38 
asABlur(BlurRec *) const39 bool SkMaskFilterBase::asABlur(BlurRec*) const {
40     return false;
41 }
42 
extractMaskSubset(const SkMask & src,SkMask * dst)43 static void extractMaskSubset(const SkMask& src, SkMask* dst) {
44     SkASSERT(src.fBounds.contains(dst->fBounds));
45 
46     const int dx = dst->fBounds.left() - src.fBounds.left();
47     const int dy = dst->fBounds.top() - src.fBounds.top();
48     dst->fImage = src.fImage + dy * src.fRowBytes + dx;
49     dst->fRowBytes = src.fRowBytes;
50     dst->fFormat = src.fFormat;
51 }
52 
blitClippedMask(SkBlitter * blitter,const SkMask & mask,const SkIRect & bounds,const SkIRect & clipR)53 static void blitClippedMask(SkBlitter* blitter, const SkMask& mask,
54                             const SkIRect& bounds, const SkIRect& clipR) {
55     SkIRect r;
56     if (r.intersect(bounds, clipR)) {
57         blitter->blitMask(mask, r);
58     }
59 }
60 
blitClippedRect(SkBlitter * blitter,const SkIRect & rect,const SkIRect & clipR)61 static void blitClippedRect(SkBlitter* blitter, const SkIRect& rect, const SkIRect& clipR) {
62     SkIRect r;
63     if (r.intersect(rect, clipR)) {
64         blitter->blitRect(r.left(), r.top(), r.width(), r.height());
65     }
66 }
67 
68 #if 0
69 static void dump(const SkMask& mask) {
70     for (int y = mask.fBounds.top(); y < mask.fBounds.bottom(); ++y) {
71         for (int x = mask.fBounds.left(); x < mask.fBounds.right(); ++x) {
72             SkDebugf("%02X", *mask.getAddr8(x, y));
73         }
74         SkDebugf("\n");
75     }
76     SkDebugf("\n");
77 }
78 #endif
79 
draw_nine_clipped(const SkMask & mask,const SkIRect & outerR,const SkIPoint & center,bool fillCenter,const SkIRect & clipR,SkBlitter * blitter)80 static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR,
81                               const SkIPoint& center, bool fillCenter,
82                               const SkIRect& clipR, SkBlitter* blitter) {
83     int cx = center.x();
84     int cy = center.y();
85     SkMask m;
86 
87     // top-left
88     m.fBounds = mask.fBounds;
89     m.fBounds.fRight = cx;
90     m.fBounds.fBottom = cy;
91     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
92         extractMaskSubset(mask, &m);
93         m.fBounds.offsetTo(outerR.left(), outerR.top());
94         blitClippedMask(blitter, m, m.fBounds, clipR);
95     }
96 
97     // top-right
98     m.fBounds = mask.fBounds;
99     m.fBounds.fLeft = cx + 1;
100     m.fBounds.fBottom = cy;
101     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
102         extractMaskSubset(mask, &m);
103         m.fBounds.offsetTo(outerR.right() - m.fBounds.width(), outerR.top());
104         blitClippedMask(blitter, m, m.fBounds, clipR);
105     }
106 
107     // bottom-left
108     m.fBounds = mask.fBounds;
109     m.fBounds.fRight = cx;
110     m.fBounds.fTop = cy + 1;
111     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
112         extractMaskSubset(mask, &m);
113         m.fBounds.offsetTo(outerR.left(), outerR.bottom() - m.fBounds.height());
114         blitClippedMask(blitter, m, m.fBounds, clipR);
115     }
116 
117     // bottom-right
118     m.fBounds = mask.fBounds;
119     m.fBounds.fLeft = cx + 1;
120     m.fBounds.fTop = cy + 1;
121     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
122         extractMaskSubset(mask, &m);
123         m.fBounds.offsetTo(outerR.right() - m.fBounds.width(),
124                            outerR.bottom() - m.fBounds.height());
125         blitClippedMask(blitter, m, m.fBounds, clipR);
126     }
127 
128     SkIRect innerR;
129     innerR.setLTRB(outerR.left() + cx - mask.fBounds.left(),
130                    outerR.top() + cy - mask.fBounds.top(),
131                    outerR.right() + (cx + 1 - mask.fBounds.right()),
132                    outerR.bottom() + (cy + 1 - mask.fBounds.bottom()));
133     if (fillCenter) {
134         blitClippedRect(blitter, innerR, clipR);
135     }
136 
137     const int innerW = innerR.width();
138     size_t storageSize = (innerW + 1) * (sizeof(int16_t) + sizeof(uint8_t));
139     SkAutoSMalloc<4*1024> storage(storageSize);
140     int16_t* runs = (int16_t*)storage.get();
141     uint8_t* alpha = (uint8_t*)(runs + innerW + 1);
142 
143     SkIRect r;
144     // top
145     r.setLTRB(innerR.left(), outerR.top(), innerR.right(), innerR.top());
146     if (r.intersect(clipR)) {
147         int startY = SkMax32(0, r.top() - outerR.top());
148         int stopY = startY + r.height();
149         int width = r.width();
150         for (int y = startY; y < stopY; ++y) {
151             runs[0] = width;
152             runs[width] = 0;
153             alpha[0] = *mask.getAddr8(cx, mask.fBounds.top() + y);
154             blitter->blitAntiH(r.left(), outerR.top() + y, alpha, runs);
155         }
156     }
157     // bottom
158     r.setLTRB(innerR.left(), innerR.bottom(), innerR.right(), outerR.bottom());
159     if (r.intersect(clipR)) {
160         int startY = outerR.bottom() - r.bottom();
161         int stopY = startY + r.height();
162         int width = r.width();
163         for (int y = startY; y < stopY; ++y) {
164             runs[0] = width;
165             runs[width] = 0;
166             alpha[0] = *mask.getAddr8(cx, mask.fBounds.bottom() - y - 1);
167             blitter->blitAntiH(r.left(), outerR.bottom() - y - 1, alpha, runs);
168         }
169     }
170     // left
171     r.setLTRB(outerR.left(), innerR.top(), innerR.left(), innerR.bottom());
172     if (r.intersect(clipR)) {
173         SkMask m;
174         m.fImage = mask.getAddr8(mask.fBounds.left() + r.left() - outerR.left(),
175                                  mask.fBounds.top() + cy);
176         m.fBounds = r;
177         m.fRowBytes = 0;    // so we repeat the scanline for our height
178         m.fFormat = SkMask::kA8_Format;
179         blitter->blitMask(m, r);
180     }
181     // right
182     r.setLTRB(innerR.right(), innerR.top(), outerR.right(), innerR.bottom());
183     if (r.intersect(clipR)) {
184         SkMask m;
185         m.fImage = mask.getAddr8(mask.fBounds.right() - outerR.right() + r.left(),
186                                  mask.fBounds.top() + cy);
187         m.fBounds = r;
188         m.fRowBytes = 0;    // so we repeat the scanline for our height
189         m.fFormat = SkMask::kA8_Format;
190         blitter->blitMask(m, r);
191     }
192 }
193 
draw_nine(const SkMask & mask,const SkIRect & outerR,const SkIPoint & center,bool fillCenter,const SkRasterClip & clip,SkBlitter * blitter)194 static void draw_nine(const SkMask& mask, const SkIRect& outerR, const SkIPoint& center,
195                       bool fillCenter, const SkRasterClip& clip, SkBlitter* blitter) {
196     // if we get here, we need to (possibly) resolve the clip and blitter
197     SkAAClipBlitterWrapper wrapper(clip, blitter);
198     blitter = wrapper.getBlitter();
199 
200     SkRegion::Cliperator clipper(wrapper.getRgn(), outerR);
201 
202     if (!clipper.done()) {
203         const SkIRect& cr = clipper.rect();
204         do {
205             draw_nine_clipped(mask, outerR, center, fillCenter, cr, blitter);
206             clipper.next();
207         } while (!clipper.done());
208     }
209 }
210 
countNestedRects(const SkPath & path,SkRect rects[2])211 static int countNestedRects(const SkPath& path, SkRect rects[2]) {
212     if (SkPathPriv::IsNestedFillRects(path, rects)) {
213         return 2;
214     }
215     return path.isRect(&rects[0]);
216 }
217 
filterRRect(const SkRRect & devRRect,const SkMatrix & matrix,const SkRasterClip & clip,SkBlitter * blitter) const218 bool SkMaskFilterBase::filterRRect(const SkRRect& devRRect, const SkMatrix& matrix,
219                                    const SkRasterClip& clip, SkBlitter* blitter) const {
220     // Attempt to speed up drawing by creating a nine patch. If a nine patch
221     // cannot be used, return false to allow our caller to recover and perform
222     // the drawing another way.
223     NinePatch patch;
224     patch.fMask.fImage = nullptr;
225     if (kTrue_FilterReturn != this->filterRRectToNine(devRRect, matrix,
226                                                       clip.getBounds(),
227                                                       &patch)) {
228         SkASSERT(nullptr == patch.fMask.fImage);
229         return false;
230     }
231     draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, true, clip, blitter);
232     return true;
233 }
234 
filterPath(const SkPath & devPath,const SkMatrix & matrix,const SkRasterClip & clip,SkBlitter * blitter,SkStrokeRec::InitStyle style) const235 bool SkMaskFilterBase::filterPath(const SkPath& devPath, const SkMatrix& matrix,
236                                   const SkRasterClip& clip, SkBlitter* blitter,
237                                   SkStrokeRec::InitStyle style) const {
238     SkRect rects[2];
239     int rectCount = 0;
240     if (SkStrokeRec::kFill_InitStyle == style) {
241         rectCount = countNestedRects(devPath, rects);
242     }
243     if (rectCount > 0) {
244         NinePatch patch;
245 
246         switch (this->filterRectsToNine(rects, rectCount, matrix, clip.getBounds(), &patch)) {
247             case kFalse_FilterReturn:
248                 SkASSERT(nullptr == patch.fMask.fImage);
249                 return false;
250 
251             case kTrue_FilterReturn:
252                 draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, 1 == rectCount, clip,
253                           blitter);
254                 return true;
255 
256             case kUnimplemented_FilterReturn:
257                 SkASSERT(nullptr == patch.fMask.fImage);
258                 // fall through
259                 break;
260         }
261     }
262 
263     SkMask  srcM, dstM;
264 
265     if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM,
266                             SkMask::kComputeBoundsAndRenderImage_CreateMode,
267                             style)) {
268         return false;
269     }
270     SkAutoMaskFreeImage autoSrc(srcM.fImage);
271 
272     if (!this->filterMask(&dstM, srcM, matrix, nullptr)) {
273         return false;
274     }
275     SkAutoMaskFreeImage autoDst(dstM.fImage);
276 
277     // if we get here, we need to (possibly) resolve the clip and blitter
278     SkAAClipBlitterWrapper wrapper(clip, blitter);
279     blitter = wrapper.getBlitter();
280 
281     SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds);
282 
283     if (!clipper.done()) {
284         const SkIRect& cr = clipper.rect();
285         do {
286             blitter->blitMask(dstM, cr);
287             clipper.next();
288         } while (!clipper.done());
289     }
290 
291     return true;
292 }
293 
294 SkMaskFilterBase::FilterReturn
filterRRectToNine(const SkRRect &,const SkMatrix &,const SkIRect & clipBounds,NinePatch *) const295 SkMaskFilterBase::filterRRectToNine(const SkRRect&, const SkMatrix&,
296                                     const SkIRect& clipBounds, NinePatch*) const {
297     return kUnimplemented_FilterReturn;
298 }
299 
300 SkMaskFilterBase::FilterReturn
filterRectsToNine(const SkRect[],int count,const SkMatrix &,const SkIRect & clipBounds,NinePatch *) const301 SkMaskFilterBase::filterRectsToNine(const SkRect[], int count, const SkMatrix&,
302                                     const SkIRect& clipBounds, NinePatch*) const {
303     return kUnimplemented_FilterReturn;
304 }
305 
306 #if SK_SUPPORT_GPU
307 std::unique_ptr<GrFragmentProcessor>
asFragmentProcessor(const GrFPArgs & args) const308 SkMaskFilterBase::asFragmentProcessor(const GrFPArgs& args) const {
309     auto fp = this->onAsFragmentProcessor(args);
310     if (fp) {
311         SkASSERT(this->hasFragmentProcessor());
312     } else {
313         SkASSERT(!this->hasFragmentProcessor());
314     }
315     return fp;
316 }
hasFragmentProcessor() const317 bool SkMaskFilterBase::hasFragmentProcessor() const {
318     return this->onHasFragmentProcessor();
319 }
320 
321 std::unique_ptr<GrFragmentProcessor>
onAsFragmentProcessor(const GrFPArgs &) const322 SkMaskFilterBase::onAsFragmentProcessor(const GrFPArgs&) const {
323     return nullptr;
324 }
onHasFragmentProcessor() const325 bool SkMaskFilterBase::onHasFragmentProcessor() const { return false; }
326 
canFilterMaskGPU(const GrShape & shape,const SkIRect & devSpaceShapeBounds,const SkIRect & clipBounds,const SkMatrix & ctm,SkIRect * maskRect) const327 bool SkMaskFilterBase::canFilterMaskGPU(const GrShape& shape,
328                                         const SkIRect& devSpaceShapeBounds,
329                                         const SkIRect& clipBounds,
330                                         const SkMatrix& ctm,
331                                         SkIRect* maskRect) const {
332     return false;
333 }
334 
directFilterMaskGPU(GrRecordingContext *,GrRenderTargetContext *,GrPaint &&,const GrClip &,const SkMatrix & viewMatrix,const GrShape &) const335 bool SkMaskFilterBase::directFilterMaskGPU(GrRecordingContext*,
336                                            GrRenderTargetContext*,
337                                            GrPaint&&,
338                                            const GrClip&,
339                                            const SkMatrix& viewMatrix,
340                                            const GrShape&) const {
341     return false;
342 }
343 
filterMaskGPU(GrRecordingContext *,sk_sp<GrTextureProxy> srcProxy,GrColorType srcColorType,SkAlphaType srcAlphaType,const SkMatrix & ctm,const SkIRect & maskRect) const344 sk_sp<GrTextureProxy> SkMaskFilterBase::filterMaskGPU(GrRecordingContext*,
345                                                       sk_sp<GrTextureProxy> srcProxy,
346                                                       GrColorType srcColorType,
347                                                       SkAlphaType srcAlphaType,
348                                                       const SkMatrix& ctm,
349                                                       const SkIRect& maskRect) const {
350     return nullptr;
351 }
352 #endif
353 
computeFastBounds(const SkRect & src,SkRect * dst) const354 void SkMaskFilterBase::computeFastBounds(const SkRect& src, SkRect* dst) const {
355     SkMask  srcM, dstM;
356 
357     srcM.fBounds = src.roundOut();
358     srcM.fRowBytes = 0;
359     srcM.fFormat = SkMask::kA8_Format;
360 
361     SkIPoint margin;    // ignored
362     if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) {
363         dst->set(dstM.fBounds);
364     } else {
365         dst->set(srcM.fBounds);
366     }
367 }
368 
369 ///////////////////////////////////////////////////////////////////////////////////////////////////
370 
join(const T & a,const T & b)371 template <typename T> static inline T join(const T& a, const T& b) {
372     T r = a;
373     r.join(b);
374     return r;
375 }
sect(const T & a,const T & b)376 template <typename T> static inline T sect(const T& a, const T& b) {
377     T r = a;
378     return r.intersect(b) ? r : T::MakeEmpty();
379 }
380 
381 class SkComposeMF : public SkMaskFilterBase {
382 public:
SkComposeMF(sk_sp<SkMaskFilter> outer,sk_sp<SkMaskFilter> inner)383     SkComposeMF(sk_sp<SkMaskFilter> outer, sk_sp<SkMaskFilter> inner)
384         : fOuter(std::move(outer))
385         , fInner(std::move(inner))
386     {
387         SkASSERT(as_MFB(fOuter)->getFormat() == SkMask::kA8_Format);
388         SkASSERT(as_MFB(fInner)->getFormat() == SkMask::kA8_Format);
389     }
390 
391     bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, SkIPoint*) const override;
392 
computeFastBounds(const SkRect & src,SkRect * dst) const393     void computeFastBounds(const SkRect& src, SkRect* dst) const override {
394         SkRect tmp;
395         as_MFB(fInner)->computeFastBounds(src, &tmp);
396         as_MFB(fOuter)->computeFastBounds(tmp, dst);
397     }
398 
getFormat() const399     SkMask::Format getFormat() const override { return SkMask::kA8_Format; }
400 
401 protected:
402 #if SK_SUPPORT_GPU
onAsFragmentProcessor(const GrFPArgs & args) const403     std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs& args) const override{
404         std::unique_ptr<GrFragmentProcessor> array[2] = {
405             as_MFB(fInner)->asFragmentProcessor(args),
406             as_MFB(fOuter)->asFragmentProcessor(args),
407         };
408         if (!array[0] || !array[1]) {
409             return nullptr;
410         }
411         return GrFragmentProcessor::RunInSeries(array, 2);
412     }
413 
onHasFragmentProcessor() const414     bool onHasFragmentProcessor() const override {
415         return as_MFB(fInner)->hasFragmentProcessor() && as_MFB(fOuter)->hasFragmentProcessor();
416     }
417 #endif
418 
419 private:
420     SK_FLATTENABLE_HOOKS(SkComposeMF)
421 
422     sk_sp<SkMaskFilter> fOuter;
423     sk_sp<SkMaskFilter> fInner;
424 
425     void flatten(SkWriteBuffer&) const override;
426 
427     friend class SkMaskFilter;
428 
429     typedef SkMaskFilterBase INHERITED;
430 };
431 
filterMask(SkMask * dst,const SkMask & src,const SkMatrix & ctm,SkIPoint * margin) const432 bool SkComposeMF::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm,
433                              SkIPoint* margin) const {
434     SkIPoint innerMargin;
435     SkMask innerMask;
436 
437     if (!as_MFB(fInner)->filterMask(&innerMask, src, ctm, &innerMargin)) {
438         return false;
439     }
440     if (!as_MFB(fOuter)->filterMask(dst, innerMask, ctm, margin)) {
441         return false;
442     }
443     if (margin) {
444         margin->fX += innerMargin.fX;
445         margin->fY += innerMargin.fY;
446     }
447     sk_free(innerMask.fImage);
448     return true;
449 }
450 
flatten(SkWriteBuffer & buffer) const451 void SkComposeMF::flatten(SkWriteBuffer & buffer) const {
452     buffer.writeFlattenable(fOuter.get());
453     buffer.writeFlattenable(fInner.get());
454 }
455 
CreateProc(SkReadBuffer & buffer)456 sk_sp<SkFlattenable> SkComposeMF::CreateProc(SkReadBuffer& buffer) {
457     auto outer = buffer.readMaskFilter();
458     auto inner = buffer.readMaskFilter();
459     if (!buffer.validate(outer && inner)) {
460         return nullptr;
461     }
462     return SkMaskFilter::MakeCompose(std::move(outer), std::move(inner));
463 }
464 
465 ///////////////////////////////////////////////////////////////////////////////////////////////////
466 
467 class SkCombineMF : public SkMaskFilterBase {
468 public:
SkCombineMF(sk_sp<SkMaskFilter> dst,sk_sp<SkMaskFilter> src,SkCoverageMode mode)469     SkCombineMF(sk_sp<SkMaskFilter> dst, sk_sp<SkMaskFilter> src, SkCoverageMode mode)
470         : fDst(std::move(dst))
471         , fSrc(std::move(src))
472         , fMode(mode)
473     {
474         SkASSERT(as_MFB(fSrc)->getFormat() == SkMask::kA8_Format);
475         SkASSERT(as_MFB(fDst)->getFormat() == SkMask::kA8_Format);
476     }
477 
478     bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&, SkIPoint*) const override;
479 
computeFastBounds(const SkRect & src,SkRect * dst) const480     void computeFastBounds(const SkRect& src, SkRect* dst) const override {
481         SkRect srcR, dstR;
482         as_MFB(fSrc)->computeFastBounds(src, &srcR);
483         as_MFB(fDst)->computeFastBounds(src, &dstR);
484         *dst = join(srcR, dstR);
485     }
486 
getFormat() const487     SkMask::Format getFormat() const override { return SkMask::kA8_Format; }
488 
489     SK_FLATTENABLE_HOOKS(SkCombineMF)
490 
491 protected:
492 #if SK_SUPPORT_GPU
onAsFragmentProcessor(const GrFPArgs & args) const493     std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs& args) const override{
494         auto src = as_MFB(fSrc)->asFragmentProcessor(args);
495         auto dst = as_MFB(fDst)->asFragmentProcessor(args);
496         if (!src || !dst) {
497             return nullptr;
498         }
499         return GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(src), std::move(dst),
500                                                       SkUncorrelatedCoverageModeToBlendMode(fMode));
501     }
502 
onHasFragmentProcessor() const503     bool onHasFragmentProcessor() const override {
504         return as_MFB(fSrc)->hasFragmentProcessor() && as_MFB(fDst)->hasFragmentProcessor();
505     }
506 #endif
507 
508 private:
509     sk_sp<SkMaskFilter> fDst;
510     sk_sp<SkMaskFilter> fSrc;
511     SkCoverageMode      fMode;
512 
513     void flatten(SkWriteBuffer&) const override;
514 
515     friend class SkMaskFilter;
516 
517     typedef SkMaskFilterBase INHERITED;
518 };
519 
520 #include "src/core/SkSafeMath.h"
521 
522 class DrawIntoMask : public SkDraw {
523 public:
524     // we ignore the offset of the mask->fBounds
DrawIntoMask(SkMask * mask)525     DrawIntoMask(SkMask* mask) {
526         int w = mask->fBounds.width();
527         int h = mask->fBounds.height();
528         size_t size = SkSafeMath::Mul(w, h);
529         mask->fFormat = SkMask::kA8_Format;
530         mask->fImage = SkMask::AllocImage(size, SkMask::kZeroInit_Alloc);
531         mask->fRowBytes = w;
532 
533         SkAssertResult(fDst.reset(*mask));
534 
535         fMatrixStorage.reset();
536         fMatrix = &fMatrixStorage;
537 
538         fRCStorage.setRect({ 0, 0, w, h });
539         fRC = &fRCStorage;
540     }
541 
drawAsBitmap(const SkMask & m,const SkPaint & p)542     void drawAsBitmap(const SkMask& m, const SkPaint& p) {
543         SkBitmap b;
544         b.installMaskPixels(m);
545         this->drawSprite(b, m.fBounds.fLeft, m.fBounds.fTop, p);
546     }
547 
548 private:
549     SkMatrix        fMatrixStorage;
550     SkRasterClip    fRCStorage;
551 };
552 
join(const SkIRect & src,const SkIRect & dst,SkCoverageMode mode)553 static SkIRect join(const SkIRect& src, const SkIRect& dst, SkCoverageMode mode) {
554     switch (mode) {
555         case SkCoverageMode::kUnion:                return join(src, dst);
556         case SkCoverageMode::kIntersect:            return sect(src, dst);
557         case SkCoverageMode::kDifference:           return src;
558         case SkCoverageMode::kReverseDifference:    return dst;
559         case SkCoverageMode::kXor:                  return join(src, dst);
560     }
561     // not reached
562     return { 0, 0, 0, 0 };
563 }
564 
filterMask(SkMask * dst,const SkMask & src,const SkMatrix & ctm,SkIPoint * margin) const565 bool SkCombineMF::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm,
566                              SkIPoint* margin) const {
567     SkIPoint srcP, dstP;
568     SkMask srcM, dstM;
569 
570     if (!as_MFB(fSrc)->filterMask(&srcM, src, ctm, &srcP)) {
571         return false;
572     }
573     if (!as_MFB(fDst)->filterMask(&dstM, src, ctm, &dstP)) {
574         return false;
575     }
576 
577     dst->fBounds = join(srcM.fBounds, dstM.fBounds, fMode);
578     dst->fFormat = SkMask::kA8_Format;
579     if (src.fImage == nullptr) {
580         dst->fImage = nullptr;
581         return true;
582     }
583 
584     DrawIntoMask md(dst);
585     SkPaint      p;
586 
587     p.setBlendMode(SkBlendMode::kSrc);
588     dstM.fBounds.offset(-dst->fBounds.fLeft, -dst->fBounds.fTop);
589     md.drawAsBitmap(dstM, p);
590     p.setBlendMode(SkUncorrelatedCoverageModeToBlendMode(fMode));
591     srcM.fBounds.offset(-dst->fBounds.fLeft, -dst->fBounds.fTop);
592     md.drawAsBitmap(srcM, p);
593 
594     sk_free(srcM.fImage);
595     sk_free(dstM.fImage);
596     return true;
597 }
598 
flatten(SkWriteBuffer & buffer) const599 void SkCombineMF::flatten(SkWriteBuffer & buffer) const {
600     buffer.writeFlattenable(fDst.get());
601     buffer.writeFlattenable(fSrc.get());
602     buffer.write32(static_cast<uint32_t>(fMode));
603 }
604 
CreateProc(SkReadBuffer & buffer)605 sk_sp<SkFlattenable> SkCombineMF::CreateProc(SkReadBuffer& buffer) {
606     auto dst = buffer.readMaskFilter();
607     auto src = buffer.readMaskFilter();
608     SkCoverageMode mode = buffer.read32LE(SkCoverageMode::kLast);
609     if (!buffer.validate(dst && src)) {
610         return nullptr;
611     }
612     return SkMaskFilter::MakeCombine(std::move(dst), std::move(src), mode);
613 }
614 
615 ///////////////////////////////////////////////////////////////////////////////////////////////////
616 
617 class SkMatrixMF : public SkMaskFilterBase {
618 public:
SkMatrixMF(sk_sp<SkMaskFilter> filter,const SkMatrix & lm)619     SkMatrixMF(sk_sp<SkMaskFilter> filter, const SkMatrix& lm)
620         : fFilter(std::move(filter))
621         , fLM(lm)
622     {}
623 
filterMask(SkMask * dst,const SkMask & src,const SkMatrix & ctm,SkIPoint * margin) const624     bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix& ctm,
625                     SkIPoint* margin) const override {
626         return as_MFB(fFilter)->filterMask(dst, src, SkMatrix::Concat(ctm, fLM), margin);
627     }
628 
computeFastBounds(const SkRect & src,SkRect * dst) const629     void computeFastBounds(const SkRect& src, SkRect* dst) const override {
630         *dst = src;
631         SkRect tmp;
632         fLM.mapRect(&tmp, src);
633         as_MFB(fFilter)->computeFastBounds(tmp, dst);
634     }
635 
getFormat() const636     SkMask::Format getFormat() const override { return as_MFB(fFilter)->getFormat(); }
637 
638     SK_FLATTENABLE_HOOKS(SkMatrixMF)
639 
640 protected:
641 #if SK_SUPPORT_GPU
onAsFragmentProcessor(const GrFPArgs & args) const642     std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(const GrFPArgs& args) const override{
643         return as_MFB(fFilter)->asFragmentProcessor(GrFPArgs::WithPostLocalMatrix(args, fLM));
644     }
645 
onHasFragmentProcessor() const646     bool onHasFragmentProcessor() const override {
647         return as_MFB(fFilter)->hasFragmentProcessor();
648     }
649 #endif
650 
651 private:
652     sk_sp<SkMaskFilter> fFilter;
653     const SkMatrix      fLM;
654 
flatten(SkWriteBuffer & buffer) const655     void flatten(SkWriteBuffer& buffer) const override {
656         buffer.writeMatrix(fLM);
657         buffer.writeFlattenable(fFilter.get());
658     }
659 
660     friend class SkMaskFilter;
661     typedef SkMaskFilterBase INHERITED;
662 };
663 
CreateProc(SkReadBuffer & buffer)664 sk_sp<SkFlattenable> SkMatrixMF::CreateProc(SkReadBuffer& buffer) {
665     SkMatrix m;
666     buffer.readMatrix(&m);
667     auto filter = buffer.readMaskFilter();
668     return filter ? filter->makeWithMatrix(m) : nullptr;
669 }
670 
671 ///////////////////////////////////////////////////////////////////////////////////////////////////
672 
MakeCompose(sk_sp<SkMaskFilter> outer,sk_sp<SkMaskFilter> inner)673 sk_sp<SkMaskFilter> SkMaskFilter::MakeCompose(sk_sp<SkMaskFilter> outer,
674                                               sk_sp<SkMaskFilter> inner) {
675     if (!outer) {
676         return inner;
677     }
678     if (!inner) {
679         return outer;
680     }
681     if (as_MFB(inner)->getFormat() != SkMask::kA8_Format ||
682         as_MFB(outer)->getFormat() != SkMask::kA8_Format) {
683         return nullptr;
684     }
685     return sk_sp<SkMaskFilter>(new SkComposeMF(std::move(outer), std::move(inner)));
686 }
687 
MakeCombine(sk_sp<SkMaskFilter> dst,sk_sp<SkMaskFilter> src,SkCoverageMode mode)688 sk_sp<SkMaskFilter> SkMaskFilter::MakeCombine(sk_sp<SkMaskFilter> dst, sk_sp<SkMaskFilter> src,
689                                               SkCoverageMode mode) {
690     if (!dst) {
691         return src;
692     }
693     if (!src) {
694         return dst;
695     }
696 
697     if (as_MFB(dst)->getFormat() != SkMask::kA8_Format ||
698         as_MFB(src)->getFormat() != SkMask::kA8_Format) {
699         return nullptr;
700     }
701     return sk_sp<SkMaskFilter>(new SkCombineMF(std::move(dst), std::move(src), mode));
702 }
703 
makeWithMatrix(const SkMatrix & lm) const704 sk_sp<SkMaskFilter> SkMaskFilter::makeWithMatrix(const SkMatrix& lm) const {
705     sk_sp<SkMaskFilter> me = sk_ref_sp(const_cast<SkMaskFilter*>(this));
706     if (lm.isIdentity()) {
707         return me;
708     }
709     return sk_sp<SkMaskFilter>(new SkMatrixMF(std::move(me), lm));
710 }
711 
RegisterFlattenables()712 void SkMaskFilter::RegisterFlattenables() {
713     SK_REGISTER_FLATTENABLE(SkMatrixMF);
714     SK_REGISTER_FLATTENABLE(SkComposeMF);
715     SK_REGISTER_FLATTENABLE(SkCombineMF);
716     sk_register_blur_maskfilter_createproc();
717 #if SK_SUPPORT_GPU
718     gr_register_sdf_maskfilter_createproc();
719 #endif
720 }
721