LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkMaskFilter.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 185 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 19 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13