Home | History | Annotate | Download | only in core
      1 
      2 /*
      3  * Copyright 2006 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #include "SkMaskFilter.h"
     11 #include "SkBlitter.h"
     12 #include "SkDraw.h"
     13 #include "SkCachedData.h"
     14 #include "SkRasterClip.h"
     15 #include "SkRRect.h"
     16 #include "SkTypes.h"
     17 
     18 #if SK_SUPPORT_GPU
     19 #include "GrTexture.h"
     20 #include "SkGr.h"
     21 #include "SkGrPixelRef.h"
     22 #endif
     23 
     24 SkMaskFilter::NinePatch::~NinePatch() {
     25     if (fCache) {
     26         SkASSERT((const void*)fMask.fImage == fCache->data());
     27         fCache->unref();
     28     } else {
     29         SkMask::FreeImage(fMask.fImage);
     30     }
     31 }
     32 
     33 bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&,
     34                               SkIPoint*) const {
     35     return false;
     36 }
     37 
     38 bool SkMaskFilter::asABlur(BlurRec*) const {
     39     return false;
     40 }
     41 
     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 
     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 
     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 
     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         int startX = r.left() - outerR.left();
    173         int stopX = startX + r.width();
    174         int height = r.height();
    175         for (int x = startX; x < stopX; ++x) {
    176             blitter->blitV(outerR.left() + x, r.top(), height,
    177                            *mask.getAddr8(mask.fBounds.left() + x, mask.fBounds.top() + cy));
    178         }
    179     }
    180     // right
    181     r.set(innerR.right(), innerR.top(), outerR.right(), innerR.bottom());
    182     if (r.intersect(clipR)) {
    183         int startX = outerR.right() - r.right();
    184         int stopX = startX + r.width();
    185         int height = r.height();
    186         for (int x = startX; x < stopX; ++x) {
    187             blitter->blitV(outerR.right() - x - 1, r.top(), height,
    188                            *mask.getAddr8(mask.fBounds.right() - x - 1, mask.fBounds.top() + cy));
    189         }
    190     }
    191 }
    192 
    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 
    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 
    217 bool SkMaskFilter::filterRRect(const SkRRect& devRRect, const SkMatrix& matrix,
    218                                const SkRasterClip& clip, SkBlitter* blitter,
    219                                SkPaint::Style style) 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 = NULL;
    225     if (kTrue_FilterReturn != this->filterRRectToNine(devRRect, matrix,
    226                                                       clip.getBounds(),
    227                                                       &patch)) {
    228         SkASSERT(NULL == patch.fMask.fImage);
    229         return false;
    230     }
    231     draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, true, clip, blitter);
    232     return true;
    233 }
    234 
    235 bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix,
    236                               const SkRasterClip& clip, SkBlitter* blitter,
    237                               SkPaint::Style style) const {
    238     SkRect rects[2];
    239     int rectCount = 0;
    240     if (SkPaint::kFill_Style == 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(NULL == 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(NULL == 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, NULL)) {
    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 SkMaskFilter::FilterReturn
    295 SkMaskFilter::filterRRectToNine(const SkRRect&, const SkMatrix&,
    296                                 const SkIRect& clipBounds, NinePatch*) const {
    297     return kUnimplemented_FilterReturn;
    298 }
    299 
    300 SkMaskFilter::FilterReturn
    301 SkMaskFilter::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 bool SkMaskFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&) const {
    308     return false;
    309 }
    310 
    311 bool SkMaskFilter::canFilterMaskGPU(const SkRect& devBounds,
    312                                     const SkIRect& clipBounds,
    313                                     const SkMatrix& ctm,
    314                                     SkRect* maskRect) const {
    315     return false;
    316 }
    317 
    318  bool SkMaskFilter::directFilterMaskGPU(GrContext* context,
    319                                         GrRenderTarget* rt,
    320                                         GrPaint* grp,
    321                                         const GrClip&,
    322                                         const SkMatrix& viewMatrix,
    323                                         const SkStrokeRec& strokeRec,
    324                                         const SkPath& path) const {
    325     return false;
    326 }
    327 
    328 
    329 bool SkMaskFilter::directFilterRRectMaskGPU(GrContext* context,
    330                                             GrRenderTarget* rt,
    331                                             GrPaint* grp,
    332                                             const GrClip&,
    333                                             const SkMatrix& viewMatrix,
    334                                             const SkStrokeRec& strokeRec,
    335                                             const SkRRect& rrect) const {
    336     return false;
    337 }
    338 
    339 bool SkMaskFilter::filterMaskGPU(GrTexture* src,
    340                                  const SkMatrix& ctm,
    341                                  const SkRect& maskRect,
    342                                  GrTexture** result,
    343                                  bool canOverwriteSrc) const {
    344     return false;
    345 }
    346 #endif
    347 
    348 void SkMaskFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
    349     SkMask  srcM, dstM;
    350 
    351     srcM.fImage = NULL;
    352     srcM.fBounds = src.roundOut();
    353     srcM.fRowBytes = 0;
    354     srcM.fFormat = SkMask::kA8_Format;
    355 
    356     SkIPoint margin;    // ignored
    357     if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) {
    358         dst->set(dstM.fBounds);
    359     } else {
    360         dst->set(srcM.fBounds);
    361     }
    362 }
    363