diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkMaskFilter.cpp | 56 | ||||
-rw-r--r-- | src/effects/SkBlurMaskFilter.cpp | 105 |
2 files changed, 104 insertions, 57 deletions
diff --git a/src/core/SkMaskFilter.cpp b/src/core/SkMaskFilter.cpp index 90925f1ff0..e02717824e 100644 --- a/src/core/SkMaskFilter.cpp +++ b/src/core/SkMaskFilter.cpp @@ -66,9 +66,10 @@ static void dump(const SkMask& mask) { #endif static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR, + const SkIPoint& center, bool fillCenter, const SkIRect& clipR, SkBlitter* blitter) { - int cx = mask.fBounds.centerX(); - int cy = mask.fBounds.centerY(); + int cx = center.x(); + int cy = center.y(); SkMask m; // top-left @@ -109,7 +110,9 @@ static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR, outerR.top() + cy - mask.fBounds.top(), outerR.right() + (cx + 1 - mask.fBounds.right()), outerR.bottom() + (cy + 1 - mask.fBounds.bottom())); - blitClippedRect(blitter, innerR, clipR); + if (fillCenter) { + blitClippedRect(blitter, innerR, clipR); + } const int innerW = innerR.width(); size_t storageSize = (innerW + 1) * (sizeof(int16_t) + sizeof(uint8_t)); @@ -169,6 +172,7 @@ static void draw_nine_clipped(const SkMask& mask, const SkIRect& outerR, } static void draw_nine(const SkMask& mask, const SkIRect& outerR, + const SkIPoint& center, bool fillCenter, const SkRasterClip& clip, SkBounder* bounder, SkBlitter* blitter) { // if we get here, we need to (possibly) resolve the clip and blitter @@ -180,33 +184,45 @@ static void draw_nine(const SkMask& mask, const SkIRect& outerR, if (!clipper.done() && (!bounder || bounder->doIRect(outerR))) { const SkIRect& cr = clipper.rect(); do { - draw_nine_clipped(mask, outerR, cr, blitter); + draw_nine_clipped(mask, outerR, center, fillCenter, cr, blitter); clipper.next(); } while (!clipper.done()); } } +static int countNestedRects(const SkPath& path, SkRect rects[2]) { + if (path.isNestedRects(rects)) { + return 2; + } + return path.isRect(&rects[0]); +} + bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix, const SkRasterClip& clip, SkBounder* bounder, SkBlitter* blitter, SkPaint::Style style) { - SkRect rect; - if (!SK_IGNORE_FAST_BLURRECT && - devPath.isRect(&rect) && SkPaint::kFill_Style == style) { - SkMask mask; - SkIRect outerBounds; - - mask.fImage = NULL; - switch (this->filterRectToNine(rect, matrix, clip.getBounds(), &mask, - &outerBounds)) { + SkRect rects[2]; + int rectCount = 0; + if (!SK_IGNORE_FAST_BLURRECT && SkPaint::kFill_Style == style) { + rectCount = countNestedRects(devPath, rects); + } + if (rectCount > 0) { + NinePatch patch; + + patch.fMask.fImage = NULL; + switch (this->filterRectsToNine(rects, rectCount, matrix, + clip.getBounds(), &patch)) { case kFalse_FilterReturn: - SkASSERT(!mask.fImage); + SkASSERT(NULL == patch.fMask.fImage); return false; + case kTrue_FilterReturn: - draw_nine(mask, outerBounds, clip, bounder, blitter); - SkMask::FreeImage(mask.fImage); + draw_nine(patch.fMask, patch.fOuterRect, patch.fCenter, + 1 == rectCount, clip, bounder, blitter); + SkMask::FreeImage(patch.fMask.fImage); return true; + case kUnimplemented_FilterReturn: - SkASSERT(!mask.fImage); + SkASSERT(NULL == patch.fMask.fImage); // fall through break; } @@ -244,10 +260,8 @@ bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix, } SkMaskFilter::FilterReturn -SkMaskFilter::filterRectToNine(const SkRect&, const SkMatrix&, - const SkIRect& clipBounds, - SkMask* ninePatchMask, - SkIRect* outerRect) { +SkMaskFilter::filterRectsToNine(const SkRect[], int count, const SkMatrix&, + const SkIRect& clipBounds, NinePatch*) { return kUnimplemented_FilterReturn; } diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp index c42bd8c9ed..467af23204 100644 --- a/src/effects/SkBlurMaskFilter.cpp +++ b/src/effects/SkBlurMaskFilter.cpp @@ -27,10 +27,9 @@ public: SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl) protected: - virtual FilterReturn filterRectToNine(const SkRect&, const SkMatrix&, - const SkIRect& clipBounds, - SkMask* ninePatchMask, - SkIRect* outerRect) SK_OVERRIDE; + virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&, + const SkIRect& clipBounds, + NinePatch*) SK_OVERRIDE; private: SkScalar fRadius; @@ -104,8 +103,8 @@ bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, #include "SkCanvas.h" -static bool drawRectIntoMask(const SkRect& r, SkMask* mask) { - r.roundOut(&mask->fBounds); +static bool drawRectsIntoMask(const SkRect rects[], int count, SkMask* mask) { + rects[0].roundOut(&mask->fBounds); mask->fRowBytes = SkAlign4(mask->fBounds.width()); mask->fFormat = SkMask::kA8_Format; size_t size = mask->computeImageSize(); @@ -122,24 +121,37 @@ static bool drawRectIntoMask(const SkRect& r, SkMask* mask) { bitmap.setPixels(mask->fImage); SkCanvas canvas(bitmap); - canvas.translate(-SkScalarFloorToScalar(r.left()), - -SkScalarFloorToScalar(r.top())); + canvas.translate(-SkIntToScalar(mask->fBounds.left()), + -SkIntToScalar(mask->fBounds.top())); SkPaint paint; paint.setAntiAlias(true); - canvas.drawRect(r, paint); + if (1 == count) { + canvas.drawRect(rects[0], paint); + } else { + // todo: do I need a fast way to do this? + SkPath path; + path.addRect(rects[0]); + path.addRect(rects[1]); + path.setFillType(SkPath::kEvenOdd_FillType); + canvas.drawPath(path, paint); + } return true; } SkMaskFilter::FilterReturn -SkBlurMaskFilterImpl::filterRectToNine(const SkRect& rect, const SkMatrix& matrix, - const SkIRect& clipBounds, - SkMask* ninePatchMask, - SkIRect* outerRect) { +SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count, + const SkMatrix& matrix, + const SkIRect& clipBounds, + NinePatch* patch) { + if (count < 1 || count > 2) { + return kUnimplemented_FilterReturn; + } + SkIPoint margin; SkMask srcM, dstM; - rect.roundOut(&srcM.fBounds); + rects[0].roundOut(&srcM.fBounds); srcM.fImage = NULL; srcM.fFormat = SkMask::kA8_Format; srcM.fRowBytes = 0; @@ -161,35 +173,56 @@ SkBlurMaskFilterImpl::filterRectToNine(const SkRect& rect, const SkMatrix& matri * Thus, in this case, we inset by a total of 5 (on each side) beginning * with our outer-rect (dstM.fBounds) */ - SkRect smallR = rect; - { - // +3 is from +1 for each edge (to account for possible fractional pixel - // edges, and +1 to make room for a center rol/col. - int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 3; - int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 3; - // we want the inset amounts to be integral, so we don't change any - // fractional phase on the fRight or fBottom of our smallR. - SkScalar dx = SkIntToScalar(srcM.fBounds.width() - smallW); - SkScalar dy = SkIntToScalar(srcM.fBounds.height() - smallH); - if (dx < 0 || dy < 0) { - // we're too small, relative to our blur, to break into nine-patch, - // so we ask to have our normal filterMask() be called. - return kUnimplemented_FilterReturn; - } - SkASSERT(dx >= 0 && dy >= 0); - smallR.set(rect.left(), rect.top(), rect.right() - dx, rect.bottom() - dy); - SkASSERT(!smallR.isEmpty()); + SkRect smallR[2]; + SkIPoint center; + + // +2 is from +1 for each edge (to account for possible fractional edges + int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 2; + int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 2; + SkIRect innerIR; + + if (1 == count) { + innerIR = srcM.fBounds; + center.set(smallW, smallH); + } else { + SkASSERT(2 == count); + rects[1].roundIn(&innerIR); + center.set(smallW + (innerIR.left() - srcM.fBounds.left()), + smallH + (innerIR.top() - srcM.fBounds.top())); + } + + // +1 so we get a clean, stretchable, center row/col + smallW += 1; + smallH += 1; + + // we want the inset amounts to be integral, so we don't change any + // fractional phase on the fRight or fBottom of our smallR. + const SkScalar dx = SkIntToScalar(innerIR.width() - smallW); + const SkScalar dy = SkIntToScalar(innerIR.height() - smallH); + if (dx < 0 || dy < 0) { + // we're too small, relative to our blur, to break into nine-patch, + // so we ask to have our normal filterMask() be called. + return kUnimplemented_FilterReturn; + } + + smallR[0].set(rects[0].left(), rects[0].top(), rects[0].right() - dx, rects[0].bottom() - dy); + SkASSERT(!smallR[0].isEmpty()); + if (2 == count) { + smallR[1].set(rects[1].left(), rects[1].top(), + rects[1].right() - dx, rects[1].bottom() - dy); + SkASSERT(!smallR[1].isEmpty()); } - if (!drawRectIntoMask(smallR, &srcM)) { + if (!drawRectsIntoMask(smallR, count, &srcM)) { return kFalse_FilterReturn; } - if (!this->filterMask(ninePatchMask, srcM, matrix, &margin)) { + if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) { return kFalse_FilterReturn; } - ninePatchMask->fBounds.offsetTo(0, 0); - *outerRect = dstM.fBounds; + patch->fMask.fBounds.offsetTo(0, 0); + patch->fOuterRect = dstM.fBounds; + patch->fCenter = center; return kTrue_FilterReturn; } |