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