Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(177)

Unified Diff: src/effects/SkBlurMaskFilter.cpp

Issue 48623006: Add ability to ninepatch blurred rounded rectangle (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/effects/SkBlurMaskFilter.cpp
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index 6a5a39778cb73a6b1bdeeaf62a221437da389c34..227be9d35a6a7db336c241231fbf10a95cc5ae60 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -11,6 +11,7 @@
#include "SkGpuBlurUtils.h"
#include "SkFlattenableBuffers.h"
#include "SkMaskFilter.h"
+#include "SkRRect.h"
#include "SkRTConf.h"
#include "SkStringUtils.h"
#include "SkStrokeRec.h"
@@ -52,6 +53,10 @@ protected:
const SkIRect& clipBounds,
NinePatch*) const SK_OVERRIDE;
+ virtual FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&,
+ const SkIRect& clipBounds,
+ NinePatch*) const SK_OVERRIDE;
+
bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix,
SkIPoint* margin, SkMask::CreateMode createMode) const;
@@ -155,39 +160,62 @@ bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
#include "SkCanvas.h"
-static bool drawRectsIntoMask(const SkRect rects[], int count, SkMask* mask) {
- rects[0].roundOut(&mask->fBounds);
+static SkCanvas* prepare_to_draw_into_mask(const SkRect& bounds, SkMask* mask) {
+ SkASSERT(mask != NULL);
+
+ bounds.roundOut(&mask->fBounds);
mask->fRowBytes = SkAlign4(mask->fBounds.width());
mask->fFormat = SkMask::kA8_Format;
- size_t size = mask->computeImageSize();
+ const size_t size = mask->computeImageSize();
mask->fImage = SkMask::AllocImage(size);
if (NULL == mask->fImage) {
- return false;
+ return NULL;
}
- sk_bzero(mask->fImage, size);
+ // FIXME: use sk_calloc in AllocImage?
+ sk_bzero(mask->fImage, size);
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kA8_Config,
mask->fBounds.width(), mask->fBounds.height(),
mask->fRowBytes);
bitmap.setPixels(mask->fImage);
- SkCanvas canvas(bitmap);
- canvas.translate(-SkIntToScalar(mask->fBounds.left()),
- -SkIntToScalar(mask->fBounds.top()));
+ SkCanvas* canvas = SkNEW_ARGS(SkCanvas, (bitmap));
scroggo 2013/10/30 22:51:31 In trying to share code, I've added an allocation!
robertphillips 2013/10/31 00:24:58 Can you just set up the mask then return true or f
scroggo 2013/11/01 21:45:46 I could, but that means I'm still duplicating code
+ canvas->translate(-SkIntToScalar(mask->fBounds.left()),
+ -SkIntToScalar(mask->fBounds.top()));
+ return canvas;
+}
+
+static bool draw_rrect_into_mask(const SkRRect rrect, SkMask* mask) {
+ SkAutoTUnref<SkCanvas> canvas(prepare_to_draw_into_mask(rrect.rect(), mask));
+ if (NULL == canvas.get()) {
+ return false;
+ }
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ canvas->drawRRect(rrect, paint);
+ return true;
+}
+
+static bool drawRectsIntoMask(const SkRect rects[], int count, SkMask* mask) {
+ SkAutoTUnref<SkCanvas> canvas(prepare_to_draw_into_mask(rects[0], mask));
+ if (NULL == canvas.get()) {
+ return false;
+ }
SkPaint paint;
paint.setAntiAlias(true);
if (1 == count) {
- canvas.drawRect(rects[0], paint);
+ 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);
+ canvas->drawPath(path, paint);
}
return true;
}
@@ -197,6 +225,105 @@ static bool rect_exceeds(const SkRect& r, SkScalar v) {
r.width() > v || r.height() > v;
}
+SkMaskFilter::FilterReturn
+SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& matrix,
+ const SkIRect& clipBounds,
+ NinePatch* patch) const {
+ switch (rrect.getType()) {
+ case SkRRect::kUnknown_Type:
+ // Unknown should never be returned.
+ SkASSERT(false);
+ // Fall through.
+ case SkRRect::kEmpty_Type:
+ // Nothing to draw.
+ return kFalse_FilterReturn;
+
+ case SkRRect::kRect_Type:
robertphillips 2013/10/31 00:24:58 I think we should assert here (that the RRect isn'
scroggo 2013/11/01 21:45:46 Done.
+ // Fall through.
+ case SkRRect::kOval_Type:
+ // The nine patch special case does not handle ovals, and we
+ // already have code for rectangles.
+ return kUnimplemented_FilterReturn;
+
+ case SkRRect::kSimple_Type:
+ // Fall through.
+ case SkRRect::kComplex_Type:
+ // These can take advantage of this fast path.
+ break;
+ }
+
+ // TODO: report correct metrics for innerstyle, where we do not grow the
+ // total bounds, but we do need an inset the size of our blur-radius
+ if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) {
+ return kUnimplemented_FilterReturn;
+ }
+
+ // TODO: take clipBounds into account to limit our coordinates up front
+ // for now, just skip too-large src rects (to take the old code path).
+ if (rect_exceeds(rrect.rect(), SkIntToScalar(32767))) {
+ return kUnimplemented_FilterReturn;
+ }
+
+ SkIPoint margin;
+ SkMask srcM, dstM;
+ rrect.rect().roundOut(&srcM.fBounds);
+ srcM.fImage = NULL;
+ srcM.fFormat = SkMask::kA8_Format;
+ srcM.fRowBytes = 0;
+
+ if (!this->filterMask(&dstM, srcM, matrix, &margin)) {
+ return kFalse_FilterReturn;
+ }
+
robertphillips 2013/10/31 13:30:31 Does this behave correctly if the RR is 100x100 wi
scroggo 2013/11/01 21:45:46 No. Latest patch fixes this. Thank you for the sug
+ // Now we figure out the appropriate width and height of the stretchy
+ // rectangle.
+ const SkVector& UL = rrect.radii(SkRRect::kUpperLeft_Corner);
+ const SkVector& UR = rrect.radii(SkRRect::kUpperRight_Corner);
+ const SkVector& LR = rrect.radii(SkRRect::kLowerRight_Corner);
+ const SkVector& LL = rrect.radii(SkRRect::kLowerLeft_Corner);
+
+ // The smaller rectangle must be large enough to include the larger
+ // radius of all four sides, plus some extra for stretching.
+ const SkScalar maxLeftXRadius = SkTMax(UL.fX, LL.fX);
+ const SkScalar maxRightXRadius = SkTMax(UR.fX, LR.fX);
+
robertphillips 2013/10/31 00:24:58 I think there should be a +3 in here and maybe mak
scroggo 2013/11/01 21:45:46 Done.
+ if (maxLeftXRadius + maxRightXRadius >= rrect.rect().width()) {
+ // There is no valid piece to stretch.
+ return kUnimplemented_FilterReturn;
+ }
+
+ const SkScalar maxTopYRadius = SkTMax(UL.fY, UR.fY);
+ const SkScalar maxBottomYRadius = SkTMax(LL.fY, LR.fY);
+
robertphillips 2013/10/31 00:24:58 Here too
scroggo 2013/11/01 21:45:46 Done.
+ if (maxTopYRadius + maxBottomYRadius >= rrect.rect().height()) {
+ // There is no valid piece to stretch.
+ return kUnimplemented_FilterReturn;
+ }
+
+ // Add some extra space to make sure we have a stretch row/col
robertphillips 2013/10/31 00:24:58 Are the x & y values correct? Can they be 0 & 0?
scroggo 2013/11/01 21:45:46 The x and y values are irrelevant. I have switched
+ SkRect smallR = SkRect::MakeXYWH(rrect.rect().left(), rrect.rect().top(),
+ maxLeftXRadius + maxRightXRadius + SkIntToScalar(3),
+ maxTopYRadius + maxBottomYRadius + SkIntToScalar(3));
+
+ SkRRect smallRR;
robertphillips 2013/10/31 00:24:58 Maybe change setRectRadii to setAllRadii?
scroggo 2013/11/01 21:45:46 I think the current name makes sense. It sets both
+ smallRR.setRectRadii(smallR, rrect.getAllRadii());
+
+ if (!draw_rrect_into_mask(smallRR, &srcM)) {
+ return kFalse_FilterReturn;
+ }
+
+ if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
+ return kFalse_FilterReturn;
+ }
+
+ patch->fMask.fBounds.offsetTo(0, 0);
+ patch->fOuterRect = dstM.fBounds;
+ // Stretch just beyond the radii.
+ patch->fCenter.fX = SkScalarCeilToInt(maxLeftXRadius) + 1;
+ patch->fCenter.fY = SkScalarCeilToInt(maxTopYRadius) + 1;
+ return kTrue_FilterReturn;
+}
+
#ifdef SK_IGNORE_FAST_RECT_BLUR
SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", false, "Use the faster analytic blur approach for ninepatch rects" );
#else

Powered by Google App Engine
This is Rietveld 408576698