Index: src/core/SkCanvas.cpp |
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp |
index 6dd8d0472136ef1ca0690e5420e8688167b952f4..1b32236ebc96c9333a90ada91e72c816d3d6edfb 100644 |
--- a/src/core/SkCanvas.cpp |
+++ b/src/core/SkCanvas.cpp |
@@ -38,6 +38,10 @@ |
#include "GrRenderTarget.h" |
#endif |
+#ifndef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
+#define SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS |
+#endif |
+ |
/* |
* Return true if the drawing this rect would hit every pixels in the canvas. |
* |
@@ -408,11 +412,36 @@ static SkColorFilter* image_to_color_filter(const SkPaint& paint) { |
return SkColorFilter::CreateComposeFilter(imgCF, paintCF); |
} |
+/** |
+ * There are many bounds in skia. A circle's bounds is just its center extended by its radius. |
+ * However, if we stroke a circle, then the "bounds" of that is larger, since it will now draw |
+ * outside of its raw-bounds by 1/2 the stroke width. SkPaint has lots of optional |
+ * effects/attributes that can modify the effective bounds of a given primitive -- maskfilters, |
+ * patheffects, stroking, etc. This function takes a raw bounds and a paint, and returns the |
+ * conservative "effective" bounds based on the settings in the paint... with one exception. This |
+ * function does *not* look at the imagefilter, which can also modify the effective bounds. It is |
+ * deliberately ignored. |
+ */ |
+static const SkRect& apply_paint_to_bounds_sans_imagefilter(const SkPaint& paint, |
+ const SkRect& rawBounds, |
+ SkRect* storage) { |
+ SkPaint tmpUnfiltered(paint); |
+ tmpUnfiltered.setImageFilter(nullptr); |
+ if (tmpUnfiltered.canComputeFastBounds()) { |
+ return tmpUnfiltered.computeFastBounds(rawBounds, storage); |
+ } else { |
+ return rawBounds; |
+ } |
+} |
+ |
class AutoDrawLooper { |
public: |
+ // "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the |
+ // paint. It's used to determine the size of the offscreen layer for filters. |
+ // If null, the clip will be used instead. |
AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint, |
bool skipLayerForImageFilter = false, |
- const SkRect* bounds = nullptr) : fOrigPaint(paint) { |
+ const SkRect* rawBounds = nullptr) : fOrigPaint(paint) { |
fCanvas = canvas; |
fFilter = canvas->getDrawFilter(); |
fPaint = &fOrigPaint; |
@@ -447,7 +476,14 @@ public: |
SkPaint tmp; |
tmp.setImageFilter(fPaint->getImageFilter()); |
tmp.setXfermode(fPaint->getXfermode()); |
- (void)canvas->internalSaveLayer(bounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag, |
+#ifndef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
+ SkRect storage; |
+ if (rawBounds) { |
+ // Make rawBounds include all paint outsets except for those due to image filters. |
+ rawBounds = &apply_paint_to_bounds_sans_imagefilter(*fPaint, *rawBounds, &storage); |
+ } |
+#endif |
+ (void)canvas->internalSaveLayer(rawBounds, &tmp, SkCanvas::kARGB_ClipLayer_SaveFlag, |
SkCanvas::kFullLayer_SaveLayerStrategy); |
fTempLayerForImageFilter = true; |
// we remove the imagefilter/xfermode inside doNext() |
@@ -1019,8 +1055,21 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveFlags flags, |
const SkMatrix& ctm = fMCRec->fMatrix; // this->getTotalMatrix() |
+// This is a temporary hack, until individual filters can do their own |
+// bloating, when this will be removed. |
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS |
+ SkRect storage; |
+#endif |
if (imageFilter) { |
imageFilter->filterBounds(clipBounds, ctm, &clipBounds); |
+#ifdef SK_SUPPORT_SRC_BOUNDS_BLOAT_FOR_IMAGEFILTERS |
+ if (bounds && imageFilter->canComputeFastBounds()) { |
+ imageFilter->computeFastBounds(*bounds, &storage); |
+ bounds = &storage; |
+ } else { |
+ bounds = nullptr; |
+ } |
+#endif |
} |
SkIRect ir; |
if (bounds) { |
@@ -1965,10 +2014,17 @@ void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], |
} else { |
r.set(pts, SkToInt(count)); |
} |
+#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
bounds = &paint.computeFastStrokeBounds(r, &storage); |
if (this->quickReject(*bounds)) { |
return; |
} |
+#else |
+ if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) { |
+ return; |
+ } |
+ bounds = &r; |
+#endif |
} |
SkASSERT(pts != nullptr); |
@@ -1992,10 +2048,17 @@ void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) { |
SkRect tmp(r); |
tmp.sort(); |
+#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
bounds = &paint.computeFastBounds(tmp, &storage); |
if (this->quickReject(*bounds)) { |
return; |
} |
+#else |
+ if (this->quickReject(paint.computeFastBounds(tmp, &storage))) { |
+ return; |
+ } |
+ bounds = &r; |
+#endif |
} |
LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, SkDrawFilter::kRect_Type, bounds, false) |
@@ -2012,10 +2075,17 @@ void SkCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) { |
SkRect storage; |
const SkRect* bounds = nullptr; |
if (paint.canComputeFastBounds()) { |
+#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
bounds = &paint.computeFastBounds(oval, &storage); |
if (this->quickReject(*bounds)) { |
return; |
} |
+#else |
+ if (this->quickReject(paint.computeFastBounds(oval, &storage))) { |
+ return; |
+ } |
+ bounds = &oval; |
+#endif |
} |
LOOPER_BEGIN(paint, SkDrawFilter::kOval_Type, bounds) |
@@ -2032,10 +2102,17 @@ void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { |
SkRect storage; |
const SkRect* bounds = nullptr; |
if (paint.canComputeFastBounds()) { |
+#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
bounds = &paint.computeFastBounds(rrect.getBounds(), &storage); |
if (this->quickReject(*bounds)) { |
return; |
} |
+#else |
+ if (this->quickReject(paint.computeFastBounds(rrect.getBounds(), &storage))) { |
+ return; |
+ } |
+ bounds = &rrect.getBounds(); |
+#endif |
} |
if (rrect.isRect()) { |
@@ -2062,10 +2139,17 @@ void SkCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, |
SkRect storage; |
const SkRect* bounds = nullptr; |
if (paint.canComputeFastBounds()) { |
+#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
bounds = &paint.computeFastBounds(outer.getBounds(), &storage); |
if (this->quickReject(*bounds)) { |
return; |
} |
+#else |
+ if (this->quickReject(paint.computeFastBounds(outer.getBounds(), &storage))) { |
+ return; |
+ } |
+ bounds = &outer.getBounds(); |
+#endif |
} |
LOOPER_BEGIN(paint, SkDrawFilter::kRRect_Type, bounds) |
@@ -2087,10 +2171,17 @@ void SkCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { |
const SkRect* bounds = nullptr; |
if (!path.isInverseFillType() && paint.canComputeFastBounds()) { |
const SkRect& pathBounds = path.getBounds(); |
+#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
bounds = &paint.computeFastBounds(pathBounds, &storage); |
if (this->quickReject(*bounds)) { |
return; |
} |
+#else |
+ if (this->quickReject(paint.computeFastBounds(pathBounds, &storage))) { |
+ return; |
+ } |
+ bounds = &pathBounds; |
+#endif |
} |
const SkRect& r = path.getBounds(); |
@@ -2115,12 +2206,22 @@ void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const S |
SkRect bounds = SkRect::MakeXYWH(x, y, |
SkIntToScalar(image->width()), SkIntToScalar(image->height())); |
if (nullptr == paint || paint->canComputeFastBounds()) { |
+#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
if (paint) { |
paint->computeFastBounds(bounds, &bounds); |
} |
if (this->quickReject(bounds)) { |
return; |
} |
+#else |
+ SkRect tmp = bounds; |
+ if (paint) { |
+ paint->computeFastBounds(tmp, &tmp); |
+ } |
+ if (this->quickReject(tmp)) { |
+ return; |
+ } |
+#endif |
} |
SkLazyPaint lazy; |
@@ -2143,12 +2244,22 @@ void SkCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const Sk |
SkRect storage; |
const SkRect* bounds = &dst; |
if (nullptr == paint || paint->canComputeFastBounds()) { |
+#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
if (paint) { |
bounds = &paint->computeFastBounds(dst, &storage); |
} |
if (this->quickReject(*bounds)) { |
return; |
} |
+#else |
+ storage = dst; |
+ if (paint) { |
+ paint->computeFastBounds(dst, &storage); |
+ } |
+ if (this->quickReject(storage)) { |
+ return; |
+ } |
+#endif |
} |
SkLazyPaint lazy; |
if (nullptr == paint) { |
@@ -2185,10 +2296,18 @@ void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, cons |
if (paint->canComputeFastBounds()) { |
bitmap.getBounds(&storage); |
matrix.mapRect(&storage); |
+#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
bounds = &paint->computeFastBounds(storage, &storage); |
if (this->quickReject(*bounds)) { |
return; |
} |
+#else |
+ SkRect tmp = storage; |
+ if (this->quickReject(paint->computeFastBounds(tmp, &tmp))) { |
+ return; |
+ } |
+ bounds = &storage; |
+#endif |
} |
LOOPER_BEGIN(*paint, SkDrawFilter::kBitmap_Type, bounds) |
@@ -2211,12 +2330,18 @@ void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, |
SkRect storage; |
const SkRect* bounds = &dst; |
if (nullptr == paint || paint->canComputeFastBounds()) { |
+#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
if (paint) { |
bounds = &paint->computeFastBounds(dst, &storage); |
} |
if (this->quickReject(*bounds)) { |
return; |
} |
+#else |
+ if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) { |
+ return; |
+ } |
+#endif |
} |
SkLazyPaint lazy; |
@@ -2248,12 +2373,18 @@ void SkCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center, cons |
SkRect storage; |
const SkRect* bounds = &dst; |
if (nullptr == paint || paint->canComputeFastBounds()) { |
+#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
if (paint) { |
bounds = &paint->computeFastBounds(dst, &storage); |
} |
if (this->quickReject(*bounds)) { |
return; |
} |
+#else |
+ if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) { |
+ return; |
+ } |
+#endif |
} |
SkLazyPaint lazy; |
@@ -2278,12 +2409,18 @@ void SkCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, c |
SkRect storage; |
const SkRect* bounds = &dst; |
if (nullptr == paint || paint->canComputeFastBounds()) { |
+#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
if (paint) { |
bounds = &paint->computeFastBounds(dst, &storage); |
} |
if (this->quickReject(*bounds)) { |
return; |
} |
+#else |
+ if (this->quickReject(paint ? paint->computeFastBounds(dst, &storage) : dst)) { |
+ return; |
+ } |
+#endif |
} |
SkLazyPaint lazy; |
@@ -2456,11 +2593,19 @@ void SkCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, |
const SkRect* bounds = nullptr; |
if (paint.canComputeFastBounds()) { |
storage = blob->bounds().makeOffset(x, y); |
+#ifdef SK_SAVE_LAYER_BOUNDS_ARE_FILTERED |
bounds = &paint.computeFastBounds(storage, &storage); |
if (this->quickReject(*bounds)) { |
return; |
} |
+#else |
+ SkRect tmp; |
+ if (this->quickReject(paint.computeFastBounds(storage, &tmp))) { |
+ return; |
+ } |
+ bounds = &storage; |
+#endif |
} |
// We cannot filter in the looper as we normally do, because the paint is |