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 "SkBounder.h"
     13 #include "SkDraw.h"
     14 #include "SkRasterClip.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 SK_DEFINE_INST_COUNT(SkMaskFilter)
     24 
     25 bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&,
     26                               SkIPoint*) const {
     27     return false;
     28 }
     29 
     30 static void extractMaskSubset(const SkMask& src, SkMask* dst) {
     31     SkASSERT(src.fBounds.contains(dst->fBounds));
     32 
     33     const int dx = dst->fBounds.left() - src.fBounds.left();
     34     const int dy = dst->fBounds.top() - src.fBounds.top();
     35     dst->fImage = src.fImage + dy * src.fRowBytes + dx;
     36     dst->fRowBytes = src.fRowBytes;
     37     dst->fFormat = src.fFormat;
     38 }
     39 
     40 static void blitClippedMask(SkBlitter* blitter, const SkMask& mask,
     41                             const SkIRect& bounds, const SkIRect& clipR) {
     42     SkIRect r;
     43     if (r.intersect(bounds, clipR)) {
     44         blitter->blitMask(mask, r);
     45     }
     46 }
     47 
     48 static void blitClippedRect(SkBlitter* blitter, const SkIRect& rect, const SkIRect& clipR) {
     49     SkIRect r;
     50     if (r.intersect(rect, clipR)) {
     51         blitter->blitRect(r.left(), r.top(), r.width(), r.height());
     52     }
     53 }
     54 
     55 #if 0
     56 static void dump(const SkMask& mask) {
     57     for (int y = mask.fBounds.top(); y < mask.fBounds.bottom(); ++y) {
     58         for (int x = mask.fBounds.left(); x < mask.fBounds.right(); ++x) {
     59             SkDebugf("%02X", *mask.getAddr8(x, y));
     60         }
     61         SkDebugf("\n");
     62     }
     63     SkDebugf("\n");
     64 }
     65 #endif
     66 
     67 static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR,
     68                               const SkIPoint& center, bool fillCenter,
     69                               const SkIRect& clipR, SkBlitter* blitter) {
     70     int cx = center.x();
     71     int cy = center.y();
     72     SkMask m;
     73 
     74     // top-left
     75     m.fBounds = mask.fBounds;
     76     m.fBounds.fRight = cx;
     77     m.fBounds.fBottom = cy;
     78     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
     79         extractMaskSubset(mask, &m);
     80         m.fBounds.offsetTo(outerR.left(), outerR.top());
     81         blitClippedMask(blitter, m, m.fBounds, clipR);
     82     }
     83 
     84     // top-right
     85     m.fBounds = mask.fBounds;
     86     m.fBounds.fLeft = cx + 1;
     87     m.fBounds.fBottom = cy;
     88     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
     89         extractMaskSubset(mask, &m);
     90         m.fBounds.offsetTo(outerR.right() - m.fBounds.width(), outerR.top());
     91         blitClippedMask(blitter, m, m.fBounds, clipR);
     92     }
     93 
     94     // bottom-left
     95     m.fBounds = mask.fBounds;
     96     m.fBounds.fRight = cx;
     97     m.fBounds.fTop = cy + 1;
     98     if (m.fBounds.width() > 0 && m.fBounds.height() > 0) {
     99         extractMaskSubset(mask, &m);
    100         m.fBounds.offsetTo(outerR.left(), outerR.bottom() - m.fBounds.height());
    101         blitClippedMask(blitter, m, m.fBounds, clipR);
    102     }
    103 
    104     // bottom-right
    105     m.fBounds = mask.fBounds;
    106     m.fBounds.fLeft = cx + 1;
    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.right() - m.fBounds.width(),
    111                            outerR.bottom() - m.fBounds.height());
    112         blitClippedMask(blitter, m, m.fBounds, clipR);
    113     }
    114 
    115     SkIRect innerR;
    116     innerR.set(outerR.left() + cx - mask.fBounds.left(),
    117                outerR.top() + cy - mask.fBounds.top(),
    118                outerR.right() + (cx + 1 - mask.fBounds.right()),
    119                outerR.bottom() + (cy + 1 - mask.fBounds.bottom()));
    120     if (fillCenter) {
    121         blitClippedRect(blitter, innerR, clipR);
    122     }
    123 
    124     const int innerW = innerR.width();
    125     size_t storageSize = (innerW + 1) * (sizeof(int16_t) + sizeof(uint8_t));
    126     SkAutoSMalloc<4*1024> storage(storageSize);
    127     int16_t* runs = (int16_t*)storage.get();
    128     uint8_t* alpha = (uint8_t*)(runs + innerW + 1);
    129 
    130     SkIRect r;
    131     // top
    132     r.set(innerR.left(), outerR.top(), innerR.right(), innerR.top());
    133     if (r.intersect(clipR)) {
    134         int startY = SkMax32(0, r.top() - outerR.top());
    135         int stopY = startY + r.height();
    136         int width = r.width();
    137         for (int y = startY; y < stopY; ++y) {
    138             runs[0] = width;
    139             runs[width] = 0;
    140             alpha[0] = *mask.getAddr8(cx, mask.fBounds.top() + y);
    141             blitter->blitAntiH(r.left(), outerR.top() + y, alpha, runs);
    142         }
    143     }
    144     // bottom
    145     r.set(innerR.left(), innerR.bottom(), innerR.right(), outerR.bottom());
    146     if (r.intersect(clipR)) {
    147         int startY = outerR.bottom() - r.bottom();
    148         int stopY = startY + r.height();
    149         int width = r.width();
    150         for (int y = startY; y < stopY; ++y) {
    151             runs[0] = width;
    152             runs[width] = 0;
    153             alpha[0] = *mask.getAddr8(cx, mask.fBounds.bottom() - y - 1);
    154             blitter->blitAntiH(r.left(), outerR.bottom() - y - 1, alpha, runs);
    155         }
    156     }
    157     // left
    158     r.set(outerR.left(), innerR.top(), innerR.left(), innerR.bottom());
    159     if (r.intersect(clipR)) {
    160         int startX = r.left() - outerR.left();
    161         int stopX = startX + r.width();
    162         int height = r.height();
    163         for (int x = startX; x < stopX; ++x) {
    164             blitter->blitV(outerR.left() + x, r.top(), height,
    165                            *mask.getAddr8(mask.fBounds.left() + x, mask.fBounds.top() + cy));
    166         }
    167     }
    168     // right
    169     r.set(innerR.right(), innerR.top(), outerR.right(), innerR.bottom());
    170     if (r.intersect(clipR)) {
    171         int startX = outerR.right() - r.right();
    172         int stopX = startX + r.width();
    173         int height = r.height();
    174         for (int x = startX; x < stopX; ++x) {
    175             blitter->blitV(outerR.right() - x - 1, r.top(), height,
    176                            *mask.getAddr8(mask.fBounds.right() - x - 1, mask.fBounds.top() + cy));
    177         }
    178     }
    179 }
    180 
    181 static void draw_nine(const SkMask& mask, const SkIRect& outerR,
    182                       const SkIPoint& center, bool fillCenter,
    183                       const SkRasterClip& clip, SkBounder* bounder,
    184                       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() && (!bounder || bounder->doIRect(outerR))) {
    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::filterPath(const SkPath& devPath, const SkMatrix& matrix,
    208                               const SkRasterClip& clip, SkBounder* bounder,
    209                               SkBlitter* blitter, SkPaint::Style style) const {
    210     SkRect rects[2];
    211     int rectCount = 0;
    212     if (SkPaint::kFill_Style == style) {
    213         rectCount = countNestedRects(devPath, rects);
    214     }
    215     if (rectCount > 0) {
    216         NinePatch patch;
    217 
    218         patch.fMask.fImage = NULL;
    219         switch (this->filterRectsToNine(rects, rectCount, matrix,
    220                                         clip.getBounds(), &patch)) {
    221             case kFalse_FilterReturn:
    222                 SkASSERT(NULL == patch.fMask.fImage);
    223                 return false;
    224 
    225             case kTrue_FilterReturn:
    226                 draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter,
    227                           1 == rectCount, clip, bounder, blitter);
    228                 SkMask::FreeImage(patch.fMask.fImage);
    229                 return true;
    230 
    231             case kUnimplemented_FilterReturn:
    232                 SkASSERT(NULL == patch.fMask.fImage);
    233                 // fall through
    234                 break;
    235         }
    236     }
    237 
    238     SkMask  srcM, dstM;
    239 
    240     if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM,
    241                             SkMask::kComputeBoundsAndRenderImage_CreateMode,
    242                             style)) {
    243         return false;
    244     }
    245     SkAutoMaskFreeImage autoSrc(srcM.fImage);
    246 
    247     if (!this->filterMask(&dstM, srcM, matrix, NULL)) {
    248         return false;
    249     }
    250     SkAutoMaskFreeImage autoDst(dstM.fImage);
    251 
    252     // if we get here, we need to (possibly) resolve the clip and blitter
    253     SkAAClipBlitterWrapper wrapper(clip, blitter);
    254     blitter = wrapper.getBlitter();
    255 
    256     SkRegion::Cliperator clipper(wrapper.getRgn(), dstM.fBounds);
    257 
    258     if (!clipper.done() && (bounder == NULL || bounder->doIRect(dstM.fBounds))) {
    259         const SkIRect& cr = clipper.rect();
    260         do {
    261             blitter->blitMask(dstM, cr);
    262             clipper.next();
    263         } while (!clipper.done());
    264     }
    265 
    266     return true;
    267 }
    268 
    269 SkMaskFilter::FilterReturn
    270 SkMaskFilter::filterRectsToNine(const SkRect[], int count, const SkMatrix&,
    271                                 const SkIRect& clipBounds, NinePatch*) const {
    272     return kUnimplemented_FilterReturn;
    273 }
    274 
    275 #if SK_SUPPORT_GPU
    276 bool SkMaskFilter::asNewEffect(GrEffectRef** effect, GrTexture*) const {
    277     return false;
    278 }
    279 
    280 bool SkMaskFilter::canFilterMaskGPU(const SkRect& devBounds,
    281                                     const SkIRect& clipBounds,
    282                                     const SkMatrix& ctm,
    283                                     SkRect* maskRect) const {
    284     return false;
    285 }
    286 
    287 bool SkMaskFilter::filterMaskGPU(GrContext* context,
    288                                  const SkBitmap& srcBM,
    289                                  const SkRect& maskRect,
    290                                  SkBitmap* resultBM) const {
    291     SkAutoTUnref<GrTexture> src;
    292     bool canOverwriteSrc = false;
    293     if (NULL == srcBM.getTexture()) {
    294         GrTextureDesc desc;
    295         // Needs to be a render target to be overwritten in filterMaskGPU
    296         desc.fFlags     = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
    297         desc.fConfig    = SkBitmapConfig2GrPixelConfig(srcBM.config());
    298         desc.fWidth     = srcBM.width();
    299         desc.fHeight    = srcBM.height();
    300 
    301         // TODO: right now this is exact to guard against out of bounds reads
    302         // by the filter code. More thought needs to be devoted to the
    303         // "filterMaskGPU" contract and then enforced (i.e., clamp the code
    304         // in "filterMaskGPU" so it never samples beyond maskRect)
    305         GrAutoScratchTexture ast(context, desc, GrContext::kExact_ScratchTexMatch);
    306         if (NULL == ast.texture()) {
    307             return false;
    308         }
    309 
    310         SkAutoLockPixels alp(srcBM);
    311         ast.texture()->writePixels(0, 0, srcBM.width(), srcBM.height(),
    312                                    desc.fConfig,
    313                                    srcBM.getPixels(), srcBM.rowBytes());
    314 
    315         src.reset(ast.detach());
    316         canOverwriteSrc = true;
    317     } else {
    318         src.reset((GrTexture*) srcBM.getTexture());
    319         src.get()->ref();
    320     }
    321     GrTexture* dst;
    322 
    323     bool result = this->filterMaskGPU(src, maskRect, &dst, canOverwriteSrc);
    324     if (!result) {
    325         return false;
    326     }
    327 
    328     resultBM->setConfig(srcBM.config(), dst->width(), dst->height());
    329     resultBM->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (dst)))->unref();
    330     dst->unref();
    331     return true;
    332 }
    333 
    334 bool SkMaskFilter::filterMaskGPU(GrTexture* src,
    335                                  const SkRect& maskRect,
    336                                  GrTexture** result,
    337                                  bool canOverwriteSrc) const {
    338     return false;
    339 }
    340 #endif
    341 
    342 void SkMaskFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
    343     SkMask  srcM, dstM;
    344 
    345     srcM.fImage = NULL;
    346     src.roundOut(&srcM.fBounds);
    347     srcM.fRowBytes = 0;
    348     srcM.fFormat = SkMask::kA8_Format;
    349 
    350     SkIPoint margin;    // ignored
    351     if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) {
    352         dst->set(dstM.fBounds);
    353     } else {
    354         dst->set(srcM.fBounds);
    355     }
    356 }
    357