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