AI 144018: change path to return its internal cached bounds, making it much lighter-weight to get the bounds.
BUG=1748928
Automated import of CL 144018
diff --git a/include/core/SkPath.h b/include/core/SkPath.h
index 4cedcde..be49ebd 100644
--- a/include/core/SkPath.h
+++ b/include/core/SkPath.h
@@ -122,32 +122,27 @@
//! Swap contents of this and other. Guaranteed not to throw
void swap(SkPath& other);
- enum BoundsType {
- /** compute the bounds of the path's control points, may be larger than
- with kExact_BoundsType, but may be faster to compute
- */
- kFast_BoundsType,
- /** compute the exact bounds of the path, may be smaller than with
- kFast_BoundsType, but may be slower to compute
- */
- kExact_BoundsType
- };
-
- /** Compute the bounds of the path, and write the answer into bounds. If the
- path contains 0 or 1 points, the bounds is set to (0,0,0,0)
-
- @param bounds Returns the computed bounds of the path
- @param btype Specifies if the computed bounds should be exact
- (slower) or approximate (faster)
+ /** Returns the bounds of the path's points. If the path contains 0 or 1
+ points, the bounds is set to (0,0,0,0), and isEmpty() will return true.
+ Note: this bounds may be larger than the actual shape, since curves
+ do not extend as far as their control points.
*/
- void computeBounds(SkRect* bounds, BoundsType btype) const;
+ const SkRect& getBounds() const {
+ if (fBoundsIsDirty) {
+ this->computeBounds();
+ }
+ return fBounds;
+ }
/** Calling this will, if the internal cache of the bounds is out of date,
- update it so that subsequent calls to computeBounds will be instanteous.
+ update it so that subsequent calls to getBounds will be instanteous.
This also means that any copies or simple transformations of the path
will inherit the cached bounds.
- */
- void updateBoundsCache() const;
+ */
+ void updateBoundsCache() const {
+ // for now, just calling getBounds() is sufficient
+ this->getBounds();
+ }
// Construction methods
@@ -564,10 +559,13 @@
private:
SkTDArray<SkPoint> fPts;
SkTDArray<uint8_t> fVerbs;
- mutable SkRect fFastBounds;
- mutable uint8_t fFastBoundsIsDirty;
+ mutable SkRect fBounds;
+ mutable uint8_t fBoundsIsDirty;
uint8_t fFillType;
+ // called, if dirty, by getBounds()
+ void computeBounds() const;
+
friend class Iter;
void cons_moveto();
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 572d6ca..199c1b0 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -905,27 +905,7 @@
}
bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const {
- if (fMCRec->fRegion->isEmpty() || path.isEmpty()) {
- return true;
- }
-
- if (fMCRec->fMatrix->rectStaysRect()) {
- SkRect r;
- path.computeBounds(&r, SkPath::kFast_BoundsType);
- return this->quickReject(r, et);
- }
-
- SkPath dstPath;
- SkRect r;
- SkIRect ir;
-
- path.transform(*fMCRec->fMatrix, &dstPath);
- dstPath.computeBounds(&r, SkPath::kFast_BoundsType);
- r.round(&ir);
- if (kAA_EdgeType == et) {
- ir.inset(-1, -1);
- }
- return fMCRec->fRegion->quickReject(ir);
+ return path.isEmpty() || this->quickReject(path.getBounds(), et);
}
bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const {
@@ -942,6 +922,7 @@
SkScalarCompareType userB = SkScalarToCompareType(bottom);
// check for invalid user Y coordinates (i.e. empty)
+ // reed: why do we need to do this check, since it slows us down?
if (userT >= userB) {
return true;
}
@@ -1058,9 +1039,9 @@
void SkCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
if (paint.canComputeFastBounds()) {
- SkRect r;
- path.computeBounds(&r, SkPath::kFast_BoundsType);
- if (this->quickReject(paint.computeFastBounds(r, &r),
+ SkRect storage;
+ const SkRect& bounds = path.getBounds();
+ if (this->quickReject(paint.computeFastBounds(bounds, &storage),
paint2EdgeType(&paint))) {
return;
}
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 60c474a..93b5d4e 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -2236,10 +2236,8 @@
}
bool SkBounder::doPath(const SkPath& path, const SkPaint& paint, bool doFill) {
- SkRect bounds;
- SkIRect r;
-
- path.computeBounds(&bounds, SkPath::kFast_BoundsType);
+ SkIRect r;
+ const SkRect& bounds = path.getBounds();
if (doFill) {
bounds.round(&r);
@@ -2276,8 +2274,7 @@
// init our bounds from the path
{
- SkRect pathBounds;
- devPath.computeBounds(&pathBounds, SkPath::kExact_BoundsType);
+ SkRect pathBounds = devPath.getBounds();
pathBounds.inset(-SK_ScalarHalf, -SK_ScalarHalf);
pathBounds.roundOut(bounds);
}
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index da90227..0cb50fb 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -27,7 +27,7 @@
It captures some state about the path up front (i.e. if it already has a
cached bounds), and the if it can, it updates the cache bounds explicitly,
- avoiding the need to revisit all of the points in computeBounds().
+ avoiding the need to revisit all of the points in getBounds().
*/
class SkAutoPathBoundsUpdate {
public:
@@ -43,11 +43,11 @@
~SkAutoPathBoundsUpdate() {
if (fEmpty) {
- fPath->fFastBounds = fRect;
- fPath->fFastBoundsIsDirty = false;
+ fPath->fBounds = fRect;
+ fPath->fBoundsIsDirty = false;
} else if (!fDirty) {
- fPath->fFastBounds.join(fRect);
- fPath->fFastBoundsIsDirty = false;
+ fPath->fBounds.join(fRect);
+ fPath->fBoundsIsDirty = false;
}
}
@@ -60,14 +60,14 @@
// returns true if we should proceed
void init(const SkPath* path) {
fPath = path;
- fDirty = path->fFastBoundsIsDirty;
+ fDirty = path->fBoundsIsDirty;
fEmpty = path->isEmpty();
// Cannot use fRect for our bounds unless we know it is sorted
fRect.sort();
}
};
-static void compute_fast_bounds(SkRect* bounds, const SkTDArray<SkPoint>& pts) {
+static void compute_pt_bounds(SkRect* bounds, const SkTDArray<SkPoint>& pts) {
if (pts.count() <= 1) { // we ignore just 1 point (moveto)
bounds->set(0, 0, 0, 0);
} else {
@@ -91,7 +91,7 @@
////////////////////////////////////////////////////////////////////////////
-SkPath::SkPath() : fFastBoundsIsDirty(true), fFillType(kWinding_FillType) {}
+SkPath::SkPath() : fBoundsIsDirty(true), fFillType(kWinding_FillType) {}
SkPath::SkPath(const SkPath& src) {
SkDEBUGCODE(src.validate();)
@@ -106,11 +106,11 @@
SkDEBUGCODE(src.validate();)
if (this != &src) {
- fFastBounds = src.fFastBounds;
- fPts = src.fPts;
- fVerbs = src.fVerbs;
- fFillType = src.fFillType;
- fFastBoundsIsDirty = src.fFastBoundsIsDirty;
+ fBounds = src.fBounds;
+ fPts = src.fPts;
+ fVerbs = src.fVerbs;
+ fFillType = src.fFillType;
+ fBoundsIsDirty = src.fBoundsIsDirty;
}
SkDEBUGCODE(this->validate();)
return *this;
@@ -125,11 +125,11 @@
SkASSERT(&other != NULL);
if (this != &other) {
- SkTSwap<SkRect>(fFastBounds, other.fFastBounds);
+ SkTSwap<SkRect>(fBounds, other.fBounds);
fPts.swap(other.fPts);
fVerbs.swap(other.fVerbs);
SkTSwap<uint8_t>(fFillType, other.fFillType);
- SkTSwap<uint8_t>(fFastBoundsIsDirty, other.fFastBoundsIsDirty);
+ SkTSwap<uint8_t>(fBoundsIsDirty, other.fBoundsIsDirty);
}
}
@@ -138,7 +138,7 @@
fPts.reset();
fVerbs.reset();
- fFastBoundsIsDirty = true;
+ fBoundsIsDirty = true;
}
void SkPath::rewind() {
@@ -146,7 +146,7 @@
fPts.rewind();
fVerbs.rewind();
- fFastBoundsIsDirty = true;
+ fBoundsIsDirty = true;
}
bool SkPath::isEmpty() const {
@@ -198,20 +198,12 @@
}
}
-#define ALWAYS_FAST_BOUNDS_FOR_NOW true
-
-void SkPath::computeBounds(SkRect* bounds, BoundsType bt) const {
+void SkPath::computeBounds() const {
SkDEBUGCODE(this->validate();)
+ SkASSERT(fBoundsIsDirty);
- SkASSERT(bounds);
-
- // we BoundsType for now
-
- if (fFastBoundsIsDirty) {
- fFastBoundsIsDirty = false;
- compute_fast_bounds(&fFastBounds, fPts);
- }
- *bounds = fFastBounds;
+ fBoundsIsDirty = false;
+ compute_pt_bounds(&fBounds, fPts);
}
//////////////////////////////////////////////////////////////////////////////
@@ -240,7 +232,7 @@
}
pt->set(x, y);
- fFastBoundsIsDirty = true;
+ fBoundsIsDirty = true;
}
void SkPath::rMoveTo(SkScalar x, SkScalar y) {
@@ -259,7 +251,7 @@
fPts.append()->set(x, y);
*fVerbs.append() = kLine_Verb;
- fFastBoundsIsDirty = true;
+ fBoundsIsDirty = true;
}
void SkPath::rLineTo(SkScalar x, SkScalar y) {
@@ -281,7 +273,7 @@
pts[1].set(x2, y2);
*fVerbs.append() = kQuad_Verb;
- fFastBoundsIsDirty = true;
+ fBoundsIsDirty = true;
}
void SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
@@ -304,7 +296,7 @@
pts[2].set(x3, y3);
*fVerbs.append() = kCubic_Verb;
- fFastBoundsIsDirty = true;
+ fBoundsIsDirty = true;
}
void SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
@@ -899,13 +891,13 @@
matrix.mapPoints(dst->fPts.begin(), dst->fPts.count());
} else {
// remember that dst might == this, so be sure to check
- // fFastBoundsIsDirty before we set it
- if (!fFastBoundsIsDirty && matrix.rectStaysRect() && fPts.count() > 1) {
+ // fBoundsIsDirty before we set it
+ if (!fBoundsIsDirty && matrix.rectStaysRect() && fPts.count() > 1) {
// if we're empty, fastbounds should not be mapped
- matrix.mapRect(&dst->fFastBounds, fFastBounds);
- dst->fFastBoundsIsDirty = false;
+ matrix.mapRect(&dst->fBounds, fBounds);
+ dst->fBoundsIsDirty = false;
} else {
- dst->fFastBoundsIsDirty = true;
+ dst->fBoundsIsDirty = true;
}
if (this != dst) {
@@ -918,14 +910,6 @@
}
}
-void SkPath::updateBoundsCache() const {
- if (fFastBoundsIsDirty) {
- SkRect r;
- this->computeBounds(&r, kFast_BoundsType);
- SkASSERT(!fFastBoundsIsDirty);
- }
-}
-
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@@ -1220,7 +1204,7 @@
buffer.read(fPts.begin(), sizeof(SkPoint) * fPts.count());
buffer.read(fVerbs.begin(), fVerbs.count());
- fFastBoundsIsDirty = true;
+ fBoundsIsDirty = true;
SkDEBUGCODE(this->validate();)
}
@@ -1291,14 +1275,14 @@
fPts.validate();
fVerbs.validate();
- if (!fFastBoundsIsDirty) {
+ if (!fBoundsIsDirty) {
SkRect bounds;
- compute_fast_bounds(&bounds, fPts);
+ compute_pt_bounds(&bounds, fPts);
// can't call contains(), since it returns false if the rect is empty
- SkASSERT(fFastBounds.fLeft <= bounds.fLeft);
- SkASSERT(fFastBounds.fTop <= bounds.fTop);
- SkASSERT(fFastBounds.fRight >= bounds.fRight);
- SkASSERT(fFastBounds.fBottom >= bounds.fBottom);
+ SkASSERT(fBounds.fLeft <= bounds.fLeft);
+ SkASSERT(fBounds.fTop <= bounds.fTop);
+ SkASSERT(fBounds.fRight >= bounds.fRight);
+ SkASSERT(fBounds.fBottom >= bounds.fBottom);
}
}
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index ed47d64..77756a9 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -138,9 +138,7 @@
validate();
if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
- SkRect bounds;
- path.computeBounds(&bounds, SkPath::kFast_BoundsType);
- return this->INHERITED::clipRect(bounds, op);
+ return this->INHERITED::clipRect(path.getBounds(), op);
} else {
return this->INHERITED::clipPath(path, op);
}
diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp
index b271970..cc3eb1a 100644
--- a/src/core/SkScalerContext.cpp
+++ b/src/core/SkScalerContext.cpp
@@ -271,11 +271,8 @@
}
} else {
// just use devPath
- SkRect r;
SkIRect ir;
-
- devPath.computeBounds(&r, SkPath::kExact_BoundsType);
- r.roundOut(&ir);
+ devPath.getBounds().roundOut(&ir);
glyph->fLeft = ir.fLeft;
glyph->fTop = ir.fTop;
diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp
index 422d060..f2f117a 100644
--- a/src/core/SkScan_AntiPath.cpp
+++ b/src/core/SkScan_AntiPath.cpp
@@ -350,11 +350,8 @@
return;
}
- SkRect r;
- SkIRect ir;
-
- path.computeBounds(&r, SkPath::kFast_BoundsType);
- r.roundOut(&ir);
+ SkIRect ir;
+ path.getBounds().roundOut(&ir);
if (ir.isEmpty()) {
return;
}
diff --git a/src/core/SkScan_Hairline.cpp b/src/core/SkScan_Hairline.cpp
index 6a66754..b959968 100644
--- a/src/core/SkScan_Hairline.cpp
+++ b/src/core/SkScan_Hairline.cpp
@@ -248,11 +248,8 @@
if (clip)
{
- SkRect bounds;
- SkIRect ibounds;
-
- path.computeBounds(&bounds, SkPath::kFast_BoundsType);
- bounds.roundOut(&ibounds);
+ SkIRect ibounds;
+ path.getBounds().roundOut(&ibounds);
ibounds.inset(-1, -1);
if (clip->quickReject(ibounds))
diff --git a/src/core/SkScan_Path.cpp b/src/core/SkScan_Path.cpp
index fcf1530..ead1b85 100644
--- a/src/core/SkScan_Path.cpp
+++ b/src/core/SkScan_Path.cpp
@@ -582,11 +582,8 @@
return;
}
- SkRect r;
SkIRect ir;
-
- path.computeBounds(&r, SkPath::kFast_BoundsType);
- r.round(&ir);
+ path.getBounds().round(&ir);
if (ir.isEmpty()) {
if (path.isInverseFillType()) {
blitter->blitRegion(clip);
diff --git a/src/core/SkStroke.cpp b/src/core/SkStroke.cpp
index 86dff48..30d524e 100644
--- a/src/core/SkStroke.cpp
+++ b/src/core/SkStroke.cpp
@@ -538,8 +538,7 @@
routine
*/
static int needs_to_shrink(const SkPath& path) {
- SkRect r;
- path.computeBounds(&r, SkPath::kFast_BoundsType);
+ const SkRect& r = path.getBounds();
SkFixed mask = SkAbs32(r.fLeft);
mask |= SkAbs32(r.fTop);
mask |= SkAbs32(r.fRight);
diff --git a/src/effects/Sk2DPathEffect.cpp b/src/effects/Sk2DPathEffect.cpp
index 405b194..603deb7 100644
--- a/src/effects/Sk2DPathEffect.cpp
+++ b/src/effects/Sk2DPathEffect.cpp
@@ -45,12 +45,10 @@
{
Sk2DPathEffectBlitter blitter(this, dst);
SkPath tmp;
- SkRect bounds;
SkIRect ir;
src.transform(fInverse, &tmp);
- tmp.computeBounds(&bounds, SkPath::kExact_BoundsType);
- bounds.round(&ir);
+ tmp.getBounds().round(&ir);
if (!ir.isEmpty()) {
// need to pass a clip to fillpath, required for inverse filltypes,
// even though those do not make sense for this patheffect
diff --git a/src/gl/SkGL.cpp b/src/gl/SkGL.cpp
index 0634709..89bcdf4 100644
--- a/src/gl/SkGL.cpp
+++ b/src/gl/SkGL.cpp
@@ -443,9 +443,7 @@
}
void SkGL::DrawPath(const SkPath& path, bool useTex, SkGLClipIter* clipIter) {
- SkRect bounds;
-
- path.computeBounds(&bounds, SkPath::kFast_BoundsType);
+ const SkRect& bounds = path.getBounds();
if (bounds.isEmpty()) {
return;
}
diff --git a/src/utils/SkDumpCanvas.cpp b/src/utils/SkDumpCanvas.cpp
index a0c85fe..1ef444c 100644
--- a/src/utils/SkDumpCanvas.cpp
+++ b/src/utils/SkDumpCanvas.cpp
@@ -53,9 +53,7 @@
if (path.isEmpty()) {
str->set("path:empty");
} else {
- SkRect bounds;
- path.computeBounds(&bounds, SkPath::kFast_BoundsType);
- toString(bounds, str);
+ toString(path.getBounds(), str);
#if 1
SkString s;
dumpVerbs(path, &s);