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