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 "SkMaskFilter.h"
      9 
     10 #include "SkAutoMalloc.h"
     11 #include "SkBlitter.h"
     12 #include "SkCachedData.h"
     13 #include "SkDraw.h"
     14 #include "SkPath.h"
     15 #include "SkRRect.h"
     16 #include "SkRasterClip.h"
     17 
     18 #if SK_SUPPORT_GPU
     19 #include "GrTextureProxy.h"
     20 #endif
     21 
     22 SkMaskFilter::NinePatch::~NinePatch() {
     23     if (fCache) {
     24         SkASSERT((const void*)fMask.fImage == fCache->data());
     25         fCache->unref();
     26     } else {
     27         SkMask::FreeImage(fMask.fImage);
     28     }
     29 }
     30 
     31 bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&,
     32                               SkIPoint*) const {
     33     return false;
     34 }
     35 
     36 bool SkMaskFilter::asABlur(BlurRec*) const {
     37     return false;
     38 }
     39 
     40 static void extractMaskSubset(const SkMask& src, SkMask* dst) {
     41     SkASSERT(src.fBounds.contains(dst->fBounds));
     42 
     43     const int dx = dst->fBounds.left() - src.fBounds.left();
     44     const int dy = dst->fBounds.top() - src.fBounds.top();
     45     dst->fImage = src.fImage + dy * src.fRowBytes + dx;
     46     dst->fRowBytes = src.fRowBytes;
     47     dst->fFormat = src.fFormat;
     48 }
     49 
     50 static void blitClippedMask(SkBlitter* blitter, const SkMask& mask,
     51                             const SkIRect& bounds, const SkIRect& clipR) {
     52     SkIRect r;
     53     if (r.intersect(bounds, clipR)) {
     54         blitter->blitMask(mask, r);
     55     }
     56 }
     57 
     58 static void blitClippedRect(SkBlitter* blitter, const SkIRect& rect, const SkIRect& clipR) {
     59     SkIRect r;
     60     if (r.intersect(rect, clipR)) {
     61         blitter->blitRect(r.left(), r.top(), r.width(), r.height());
     62     }
     63 }
     64 
     65 #if 0
     66 static void dump(const SkMask& mask) {
     67     for (int y = mask.fBounds.top(); y < mask.fBounds.bottom(); ++y) {
     68         for (int x = mask.fBounds.left(); x < mask.fBounds.right(); ++x) {
     69             SkDebugf("%02X", *mask.getAddr8(x, y));
     70         }
     71         SkDebugf("\n");
     72     }
     73     SkDebugf("\n");
     74 }
     75 #endif
     76 
     77 static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR,
     78                               const SkIPoint& center, bool fillCenter,
     79                               const SkIRect& clipR, SkBlitter* blitter) {
     80     int cx = center.x();
     81     int cy = center.y();
     82     SkMask m;
     83 
     84     // top-left
     85     m.fBounds = mask.fBounds;
     86     m.fBounds.fRight = cx;
     87     m.fBounds.fBottom = cy;
     88     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
     89         extractMaskSubset(mask, &m);
     90         m.fBounds.offsetTo(outerR.left(), outerR.top());
     91         blitClippedMask(blitter, m, m.fBounds, clipR);
     92     }
     93 
     94     // top-right
     95     m.fBounds = mask.fBounds;
     96     m.fBounds.fLeft = cx + 1;
     97     m.fBounds.fBottom = cy;
     98     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
     99         extractMaskSubset(mask, &m);
    100         m.fBounds.offsetTo(outerR.right() - m.fBounds.width(), outerR.top());
    101         blitClippedMask(blitter, m, m.fBounds, clipR);
    102     }
    103 
    104     // bottom-left
    105     m.fBounds = mask.fBounds;
    106     m.fBounds.fRight = cx;
    107     m.fBounds.fTop = cy + 1;
    108     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
    109         extractMaskSubset(mask, &m);
    110         m.fBounds.offsetTo(outerR.left(), outerR.bottom() - m.fBounds.height());
    111         blitClippedMask(blitter, m, m.fBounds, clipR);
    112     }
    113 
    114     // bottom-right
    115     m.fBounds = mask.fBounds;
    116     m.fBounds.fLeft = cx + 1;
    117     m.fBounds.fTop = cy + 1;
    118     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
    119         extractMaskSubset(mask, &m);
    120         m.fBounds.offsetTo(outerR.right() - m.fBounds.width(),
    121                            outerR.bottom() - m.fBounds.height());
    122         blitClippedMask(blitter, m, m.fBounds, clipR);
    123     }
    124 
    125     SkIRect innerR;
    126     innerR.set(outerR.left() + cx - mask.fBounds.left(),
    127                outerR.top() + cy - mask.fBounds.top(),
    128                outerR.right() + (cx + 1 - mask.fBounds.right()),
    129                outerR.bottom() + (cy + 1 - mask.fBounds.bottom()));
    130     if (fillCenter) {
    131         blitClippedRect(blitter, innerR, clipR);
    132     }
    133 
    134     const int innerW = innerR.width();
    135     size_t storageSize = (innerW + 1) * (sizeof(int16_t) + sizeof(uint8_t));
    136     SkAutoSMalloc<4*1024> storage(storageSize);
    137     int16_t* runs = (int16_t*)storage.get();
    138     uint8_t* alpha = (uint8_t*)(runs + innerW + 1);
    139 
    140     SkIRect r;
    141     // top
    142     r.set(innerR.left(), outerR.top(), innerR.right(), innerR.top());
    143     if (r.intersect(clipR)) {
    144         int startY = SkMax32(0, r.top() - outerR.top());
    145         int stopY = startY + r.height();
    146         int width = r.width();
    147         for (int y = startY; y < stopY; ++y) {
    148             runs[0] = width;
    149             runs[width] = 0;
    150             alpha[0] = *mask.getAddr8(cx, mask.fBounds.top() + y);
    151             blitter->blitAntiH(r.left(), outerR.top() + y, alpha, runs);
    152         }
    153     }
    154     // bottom
    155     r.set(innerR.left(), innerR.bottom(), innerR.right(), outerR.bottom());
    156     if (r.intersect(clipR)) {
    157         int startY = outerR.bottom() - r.bottom();
    158         int stopY = startY + r.height();
    159         int width = r.width();
    160         for (int y = startY; y < stopY; ++y) {
    161             runs[0] = width;
    162             runs[width] = 0;
    163             alpha[0] = *mask.getAddr8(cx, mask.fBounds.bottom() - y - 1);
    164             blitter->blitAntiH(r.left(), outerR.bottom() - y - 1, alpha, runs);
    165         }
    166     }
    167     // left
    168     r.set(outerR.left(), innerR.top(), innerR.left(), innerR.bottom());
    169     if (r.intersect(clipR)) {
    170         SkMask m;
    171         m.fImage = mask.getAddr8(mask.fBounds.left() + r.left() - outerR.left(),
    172                                  mask.fBounds.top() + cy);
    173         m.fBounds = r;
    174         m.fRowBytes = 0;    // so we repeat the scanline for our height
    175         m.fFormat = SkMask::kA8_Format;
    176         blitter->blitMask(m, r);
    177     }
    178     // right
    179     r.set(innerR.right(), innerR.top(), outerR.right(), innerR.bottom());
    180     if (r.intersect(clipR)) {
    181         SkMask m;
    182         m.fImage = mask.getAddr8(mask.fBounds.right() - outerR.right() + r.left(),
    183                                  mask.fBounds.top() + cy);
    184         m.fBounds = r;
    185         m.fRowBytes = 0;    // so we repeat the scanline for our height
    186         m.fFormat = SkMask::kA8_Format;
    187         blitter->blitMask(m, r);
    188     }
    189 }
    190 
    191 static void draw_nine(const SkMask& mask, const SkIRect& outerR, const SkIPoint& center,
    192                       bool fillCenter, const SkRasterClip& clip, SkBlitter* blitter) {
    193     // if we get here, we need to (possibly) resolve the clip and blitter
    194     SkAAClipBlitterWrapper wrapper(clip, blitter);
    195     blitter = wrapper.getBlitter();
    196 
    197     SkRegion::Cliperator clipper(wrapper.getRgn(), outerR);
    198 
    199     if (!clipper.done()) {
    200         const SkIRect& cr = clipper.rect();
    201         do {
    202             draw_nine_clipped(mask, outerR, center, fillCenter, cr, blitter);
    203             clipper.next();
    204         } while (!clipper.done());
    205     }
    206 }
    207 
    208 static int countNestedRects(const SkPath& path, SkRect rects[2]) {
    209     if (path.isNestedFillRects(rects)) {
    210         return 2;
    211     }
    212     return path.isRect(&rects[0]);
    213 }
    214 
    215 bool SkMaskFilter::filterRRect(const SkRRect& devRRect, const SkMatrix& matrix,
    216                                const SkRasterClip& clip, SkBlitter* blitter) const {
    217     // Attempt to speed up drawing by creating a nine patch. If a nine patch
    218     // cannot be used, return false to allow our caller to recover and perform
    219     // the drawing another way.
    220     NinePatch patch;
    221     patch.fMask.fImage = nullptr;
    222     if (kTrue_FilterReturn != this->filterRRectToNine(devRRect, matrix,
    223                                                       clip.getBounds(),
    224                                                       &patch)) {
    225         SkASSERT(nullptr == patch.fMask.fImage);
    226         return false;
    227     }
    228     draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, true, clip, blitter);
    229     return true;
    230 }
    231 
    232 bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix,
    233                               const SkRasterClip& clip, SkBlitter* blitter,
    234                               SkStrokeRec::InitStyle style) const {
    235     SkRect rects[2];
    236     int rectCount = 0;
    237     if (SkStrokeRec::kFill_InitStyle == style) {
    238         rectCount = countNestedRects(devPath, rects);
    239     }
    240     if (rectCount > 0) {
    241         NinePatch patch;
    242 
    243         switch (this->filterRectsToNine(rects, rectCount, matrix, clip.getBounds(), &patch)) {
    244             case kFalse_FilterReturn:
    245                 SkASSERT(nullptr == patch.fMask.fImage);
    246                 return false;
    247 
    248             case kTrue_FilterReturn:
    249                 draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, 1 == rectCount, clip,
    250                           blitter);
    251                 return true;
    252 
    253             case kUnimplemented_FilterReturn:
    254                 SkASSERT(nullptr == patch.fMask.fImage);
    255                 // fall through
    256                 break;
    257         }
    258     }
    259 
    260     SkMask  srcM, dstM;
    261 
    262     if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM,
    263                             SkMask::kComputeBoundsAndRenderImage_CreateMode,
    264                             style)) {
    265         return false;
    266     }
    267     SkAutoMaskFreeImage autoSrc(srcM.fImage);
    268 
    269     if (!this->filterMask(&dstM, srcM, matrix, nullptr)) {
    270         return false;
    271     }
    272     SkAutoMaskFreeImage autoDst(dstM.fImage);
    273 
    274     // if we get here, we need to (possibly) resolve the clip and blitter
    275     SkAAClipBlitterWrapper wrapper(clip, blitter);
    276     blitter = wrapper.getBlitter();
    277 
    278     SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds);
    279 
    280     if (!clipper.done()) {
    281         const SkIRect& cr = clipper.rect();
    282         do {
    283             blitter->blitMask(dstM, cr);
    284             clipper.next();
    285         } while (!clipper.done());
    286     }
    287 
    288     return true;
    289 }
    290 
    291 SkMaskFilter::FilterReturn
    292 SkMaskFilter::filterRRectToNine(const SkRRect&, const SkMatrix&,
    293                                 const SkIRect& clipBounds, NinePatch*) const {
    294     return kUnimplemented_FilterReturn;
    295 }
    296 
    297 SkMaskFilter::FilterReturn
    298 SkMaskFilter::filterRectsToNine(const SkRect[], int count, const SkMatrix&,
    299                                 const SkIRect& clipBounds, NinePatch*) const {
    300     return kUnimplemented_FilterReturn;
    301 }
    302 
    303 #if SK_SUPPORT_GPU
    304 bool SkMaskFilter::canFilterMaskGPU(const SkRRect& devRRect,
    305                                     const SkIRect& clipBounds,
    306                                     const SkMatrix& ctm,
    307                                     SkRect* maskRect) const {
    308     return false;
    309 }
    310 
    311 bool SkMaskFilter::directFilterMaskGPU(GrContext*,
    312                                        GrRenderTargetContext* renderTargetContext,
    313                                        GrPaint&&,
    314                                        const GrClip&,
    315                                        const SkMatrix& viewMatrix,
    316                                        const SkStrokeRec& strokeRec,
    317                                        const SkPath& path) const {
    318     return false;
    319 }
    320 
    321 bool SkMaskFilter::directFilterRRectMaskGPU(GrContext*,
    322                                             GrRenderTargetContext* renderTargetContext,
    323                                             GrPaint&&,
    324                                             const GrClip&,
    325                                             const SkMatrix& viewMatrix,
    326                                             const SkStrokeRec& strokeRec,
    327                                             const SkRRect& rrect,
    328                                             const SkRRect& devRRect) const {
    329     return false;
    330 }
    331 
    332 sk_sp<GrTextureProxy> SkMaskFilter::filterMaskGPU(GrContext*,
    333                                                   sk_sp<GrTextureProxy> srcProxy,
    334                                                   const SkMatrix& ctm,
    335                                                   const SkIRect& maskRect) const {
    336     return nullptr;
    337 }
    338 #endif
    339 
    340 void SkMaskFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
    341     SkMask  srcM, dstM;
    342 
    343     srcM.fBounds = src.roundOut();
    344     srcM.fRowBytes = 0;
    345     srcM.fFormat = SkMask::kA8_Format;
    346 
    347     SkIPoint margin;    // ignored
    348     if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) {
    349         dst->set(dstM.fBounds);
    350     } else {
    351         dst->set(srcM.fBounds);
    352     }
    353 }
    354