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

Unified Diff: src/core/SkCanvas.cpp

Issue 1304883004: Change saveLayer() semantics to take unfiltered bounds. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Update to ToT; fix comments per review Created 5 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698