API change: SkPath computeBounds -> getBounds
git-svn-id: http://skia.googlecode.com/svn/trunk@140 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
6c924ad46c
commit
d252db03d9
@ -371,8 +371,14 @@ public:
|
||||
bounds (i.e. there is nothing complex like a patheffect that would make
|
||||
the bounds computation expensive.
|
||||
*/
|
||||
bool canComputeFastBounds() const;
|
||||
|
||||
bool canComputeFastBounds() const {
|
||||
// use bit-or since no need for early exit
|
||||
return (reinterpret_cast<uintptr_t>(this->getMaskFilter()) |
|
||||
reinterpret_cast<uintptr_t>(this->getLooper()) |
|
||||
reinterpret_cast<uintptr_t>(this->getRasterizer()) |
|
||||
reinterpret_cast<uintptr_t>(this->getPathEffect())) == 0;
|
||||
}
|
||||
|
||||
/** Only call this if canComputeFastBounds() returned true. This takes a
|
||||
raw rectangle (the raw bounds of a shape), and adjusts it for stylistic
|
||||
effects in the paint (e.g. stroking). If needed, it uses the storage
|
||||
@ -394,7 +400,10 @@ public:
|
||||
}
|
||||
}
|
||||
*/
|
||||
const SkRect& computeFastBounds(const SkRect& orig, SkRect* storage) const;
|
||||
const SkRect& computeFastBounds(const SkRect& orig, SkRect* storage) const {
|
||||
return this->getStyle() == kFill_Style ? orig :
|
||||
this->computeStrokeFastBounds(orig, storage);
|
||||
}
|
||||
|
||||
/** Get the paint's shader object.
|
||||
<p />
|
||||
@ -759,7 +768,10 @@ private:
|
||||
void descriptorProc(const SkMatrix* deviceMatrix,
|
||||
void (*proc)(const SkDescriptor*, void*),
|
||||
void* context) const;
|
||||
|
||||
|
||||
const SkRect& computeStrokeFastBounds(const SkRect& orig,
|
||||
SkRect* storage) const;
|
||||
|
||||
enum {
|
||||
kCanonicalTextSizeForPaths = 64
|
||||
};
|
||||
|
@ -122,32 +122,27 @@ public:
|
||||
//! 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 @@ public:
|
||||
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();
|
||||
|
||||
|
@ -41,20 +41,38 @@ public:
|
||||
virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
|
||||
const SkAlpha aa[]);
|
||||
|
||||
/** Enum of possible coefficients to describe some xfermodes
|
||||
*/
|
||||
enum Coeff {
|
||||
kZero_Coeff,
|
||||
kOne_Coeff,
|
||||
kSC_Coeff,
|
||||
kISC_Coeff,
|
||||
kDC_Coeff,
|
||||
kIDC_Coeff,
|
||||
kSA_Coeff,
|
||||
kISA_Coeff,
|
||||
kDA_Coeff,
|
||||
kIDA_Coeff,
|
||||
kZero_Coeff, /** 0 */
|
||||
kOne_Coeff, /** 1 */
|
||||
kSC_Coeff, /** src color */
|
||||
kISC_Coeff, /** inverse src color (i.e. 1 - sc) */
|
||||
kDC_Coeff, /** dst color */
|
||||
kIDC_Coeff, /** inverse dst color (i.e. 1 - dc) */
|
||||
kSA_Coeff, /** src alpha */
|
||||
kISA_Coeff, /** inverse src alpha (i.e. 1 - sa) */
|
||||
kDA_Coeff, /** dst alpha */
|
||||
kIDA_Coeff, /** inverse dst alpha (i.e. 1 - da) */
|
||||
|
||||
kCoeffCount
|
||||
};
|
||||
|
||||
/** If the xfermode can be expressed as an equation using the coefficients
|
||||
in Coeff, then asCoeff() returns true, and sets (if not null) src and
|
||||
dst accordingly.
|
||||
|
||||
result = src_coeff * src_color + dst_coeff * dst_color;
|
||||
|
||||
As examples, here are some of the porterduff coefficients
|
||||
|
||||
MODE SRC_COEFF DST_COEFF
|
||||
clear zero zero
|
||||
src one zero
|
||||
dst zero one
|
||||
srcover one isa
|
||||
dstover ida one
|
||||
*/
|
||||
virtual bool asCoeff(Coeff* src, Coeff* dst);
|
||||
|
||||
protected:
|
||||
|
@ -13,9 +13,7 @@ static void test_circlebounds(SkCanvas* canvas) {
|
||||
SkRect r = { 1.39999998, 1, 21.3999996, 21 };
|
||||
SkPath p;
|
||||
p.addOval(r);
|
||||
SkRect r2;
|
||||
p.computeBounds(&r2, SkPath::kFast_BoundsType);
|
||||
SkASSERT(r == r2);
|
||||
SkASSERT(r == p.getBounds());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,7 @@ static void lettersToBitmap(SkBitmap* dst, const char chars[],
|
||||
original.getTextWidths(&chars[i], 1, &width);
|
||||
x += width;
|
||||
}
|
||||
SkRect bounds;
|
||||
path.computeBounds(&bounds, SkPath::kExact_BoundsType);
|
||||
SkRect bounds = path.getBounds();
|
||||
SkScalar sw = -original.getStrokeWidth();
|
||||
bounds.inset(sw, sw);
|
||||
path.offset(-bounds.fLeft, -bounds.fTop);
|
||||
@ -76,8 +75,7 @@ static void lettersToBitmap2(SkBitmap* dst, const char chars[],
|
||||
original.getTextWidths(&chars[i], 1, &width);
|
||||
x += width;
|
||||
}
|
||||
SkRect bounds;
|
||||
path.computeBounds(&bounds, SkPath::kExact_BoundsType);
|
||||
SkRect bounds = path.getBounds();
|
||||
SkScalar sw = -original.getStrokeWidth();
|
||||
bounds.inset(sw, sw);
|
||||
path.offset(-bounds.fLeft, -bounds.fTop);
|
||||
|
@ -784,6 +784,64 @@ static void delete_blitter(void* blitter)
|
||||
SkDELETE((SkBlitter*)blitter);
|
||||
}
|
||||
|
||||
static bool just_solid_color(const SkPaint& paint) {
|
||||
if (paint.getAlpha() == 0xFF && paint.getColorFilter() == NULL) {
|
||||
SkShader* shader = paint.getShader();
|
||||
if (NULL == shader ||
|
||||
(shader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** By analyzing the paint (with an xfermode), we may decide we can take
|
||||
special action. This enum lists our possible actions
|
||||
*/
|
||||
enum XferInterp {
|
||||
kNormal_XferInterp, // no special interpretation, draw normally
|
||||
kSrcOver_XferInterp, // draw as if in srcover mode
|
||||
kSkipDrawing_XferInterp // draw nothing
|
||||
};
|
||||
|
||||
static XferInterp interpret_xfermode(const SkPaint& paint, SkXfermode* xfer,
|
||||
SkBitmap::Config deviceConfig) {
|
||||
SkPorterDuff::Mode mode;
|
||||
|
||||
if (SkPorterDuff::IsMode(xfer, &mode)) {
|
||||
switch (mode) {
|
||||
case SkPorterDuff::kSrc_Mode:
|
||||
if (just_solid_color(paint)) {
|
||||
return kSrcOver_XferInterp;
|
||||
}
|
||||
break;
|
||||
case SkPorterDuff::kDst_Mode:
|
||||
return kSkipDrawing_XferInterp;
|
||||
case SkPorterDuff::kSrcOver_Mode:
|
||||
return kSrcOver_XferInterp;
|
||||
case SkPorterDuff::kDstOver_Mode:
|
||||
if (SkBitmap::kRGB_565_Config == deviceConfig) {
|
||||
return kSkipDrawing_XferInterp;
|
||||
}
|
||||
break;
|
||||
case SkPorterDuff::kSrcIn_Mode:
|
||||
if (SkBitmap::kRGB_565_Config == deviceConfig &&
|
||||
just_solid_color(paint)) {
|
||||
return kSrcOver_XferInterp;
|
||||
}
|
||||
break;
|
||||
case SkPorterDuff::kDstIn_Mode:
|
||||
if (just_solid_color(paint)) {
|
||||
return kSkipDrawing_XferInterp;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return kNormal_XferInterp;
|
||||
}
|
||||
|
||||
SkBlitter* SkBlitter::Choose(const SkBitmap& device,
|
||||
const SkMatrix& matrix,
|
||||
const SkPaint& paint,
|
||||
@ -813,6 +871,19 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device,
|
||||
}
|
||||
|
||||
SkXfermode* mode = paint.getXfermode();
|
||||
if (NULL != mode) {
|
||||
switch (interpret_xfermode(paint, mode, device.config())) {
|
||||
case kSrcOver_XferInterp:
|
||||
mode = NULL;
|
||||
break;
|
||||
case kSkipDrawing_XferInterp:
|
||||
SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
|
||||
return blitter;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == shader && (NULL != mode || paint.getColorFilter() != NULL))
|
||||
{
|
||||
// xfermodes require shaders for our current set of blitters
|
||||
|
@ -879,58 +879,33 @@ void SkCanvas::computeLocalClipBoundsCompareType() const {
|
||||
}
|
||||
}
|
||||
|
||||
/* current impl ignores edgetype, and relies on
|
||||
getLocalClipBoundsCompareType(), which always returns a value assuming
|
||||
antialiasing (worst case)
|
||||
*/
|
||||
bool SkCanvas::quickReject(const SkRect& rect, EdgeType) const {
|
||||
/* current impl ignores edgetype, and relies on
|
||||
getLocalClipBoundsCompareType(), which always returns a value assuming
|
||||
antialiasing (worst case)
|
||||
*/
|
||||
|
||||
if (fMCRec->fRegion->isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check for empty user rect (horizontal)
|
||||
SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft);
|
||||
SkScalarCompareType userR = SkScalarToCompareType(rect.fRight);
|
||||
if (userL >= userR) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check for empty user rect (vertical)
|
||||
const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
|
||||
|
||||
// for speed, do the most likely reject compares first
|
||||
SkScalarCompareType userT = SkScalarToCompareType(rect.fTop);
|
||||
SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom);
|
||||
if (userT >= userB) {
|
||||
if (userT >= clipR.fBottom || userB <= clipR.fTop) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if we are completely outside of the local clip bounds
|
||||
const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
|
||||
return userL >= clipR.fRight || userT >= clipR.fBottom ||
|
||||
userR <= clipR.fLeft || userB <= clipR.fTop;
|
||||
SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft);
|
||||
SkScalarCompareType userR = SkScalarToCompareType(rect.fRight);
|
||||
if (userL >= clipR.fRight || userR <= clipR.fLeft) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -947,6 +922,7 @@ bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const {
|
||||
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;
|
||||
}
|
||||
@ -1063,9 +1039,9 @@ void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -2236,10 +2236,8 @@ bool SkBounder::doRect(const SkRect& rect, const SkPaint& paint) {
|
||||
}
|
||||
|
||||
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 @@ static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
@ -1517,36 +1517,24 @@ bool SkPaint::getFillPath(const SkPath& src, SkPath* dst) const
|
||||
return width != 0; // return true if we're filled, or false if we're hairline (width == 0)
|
||||
}
|
||||
|
||||
bool SkPaint::canComputeFastBounds() const {
|
||||
// use bit-or since no need for early exit
|
||||
return (reinterpret_cast<uintptr_t>(this->getMaskFilter()) |
|
||||
reinterpret_cast<uintptr_t>(this->getLooper()) |
|
||||
reinterpret_cast<uintptr_t>(this->getRasterizer()) |
|
||||
reinterpret_cast<uintptr_t>(this->getPathEffect())) == 0;
|
||||
}
|
||||
|
||||
const SkRect& SkPaint::computeFastBounds(const SkRect& src,
|
||||
SkRect* storage) const {
|
||||
const SkRect& SkPaint::computeStrokeFastBounds(const SkRect& src,
|
||||
SkRect* storage) const {
|
||||
SkASSERT(storage);
|
||||
|
||||
if (this->getStyle() != SkPaint::kFill_Style) {
|
||||
// if we're stroked, outset the rect by the radius (and join type)
|
||||
SkScalar radius = SkScalarHalf(this->getStrokeWidth());
|
||||
|
||||
if (0 == radius) { // hairline
|
||||
radius = SK_Scalar1;
|
||||
} else if (this->getStrokeJoin() == SkPaint::kMiter_Join) {
|
||||
SkScalar scale = this->getStrokeMiter();
|
||||
if (scale > SK_Scalar1) {
|
||||
radius = SkScalarMul(radius, scale);
|
||||
}
|
||||
SkASSERT(this->getStyle() != SkPaint::kFill_Style);
|
||||
|
||||
// since we're stroked, outset the rect by the radius (and join type)
|
||||
SkScalar radius = SkScalarHalf(this->getStrokeWidth());
|
||||
if (0 == radius) { // hairline
|
||||
radius = SK_Scalar1;
|
||||
} else if (this->getStrokeJoin() == SkPaint::kMiter_Join) {
|
||||
SkScalar scale = this->getStrokeMiter();
|
||||
if (scale > SK_Scalar1) {
|
||||
radius = SkScalarMul(radius, scale);
|
||||
}
|
||||
storage->set(src.fLeft - radius, src.fTop - radius,
|
||||
src.fRight + radius, src.fBottom + radius);
|
||||
return *storage;
|
||||
}
|
||||
// no adjustments needed, just return the original rect
|
||||
return src;
|
||||
storage->set(src.fLeft - radius, src.fTop - radius,
|
||||
src.fRight + radius, src.fBottom + radius);
|
||||
return *storage;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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 @@ public:
|
||||
|
||||
~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 @@ private:
|
||||
// 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 @@ static void compute_fast_bounds(SkRect* bounds, const SkTDArray<SkPoint>& pts) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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 @@ SkPath& SkPath::operator=(const SkPath& src) {
|
||||
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 @@ void SkPath::swap(SkPath& other) {
|
||||
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 @@ void SkPath::reset() {
|
||||
|
||||
fPts.reset();
|
||||
fVerbs.reset();
|
||||
fFastBoundsIsDirty = true;
|
||||
fBoundsIsDirty = true;
|
||||
}
|
||||
|
||||
void SkPath::rewind() {
|
||||
@ -146,7 +146,7 @@ void SkPath::rewind() {
|
||||
|
||||
fPts.rewind();
|
||||
fVerbs.rewind();
|
||||
fFastBoundsIsDirty = true;
|
||||
fBoundsIsDirty = true;
|
||||
}
|
||||
|
||||
bool SkPath::isEmpty() const {
|
||||
@ -198,20 +198,12 @@ void SkPath::setLastPt(SkScalar x, SkScalar y) {
|
||||
}
|
||||
}
|
||||
|
||||
#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 @@ void SkPath::moveTo(SkScalar x, SkScalar y) {
|
||||
}
|
||||
pt->set(x, y);
|
||||
|
||||
fFastBoundsIsDirty = true;
|
||||
fBoundsIsDirty = true;
|
||||
}
|
||||
|
||||
void SkPath::rMoveTo(SkScalar x, SkScalar y) {
|
||||
@ -259,7 +251,7 @@ void SkPath::lineTo(SkScalar x, SkScalar y) {
|
||||
fPts.append()->set(x, y);
|
||||
*fVerbs.append() = kLine_Verb;
|
||||
|
||||
fFastBoundsIsDirty = true;
|
||||
fBoundsIsDirty = true;
|
||||
}
|
||||
|
||||
void SkPath::rLineTo(SkScalar x, SkScalar y) {
|
||||
@ -281,7 +273,7 @@ void SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) {
|
||||
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 @@ void SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2,
|
||||
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 @@ void SkPath::transform(const SkMatrix& matrix, SkPath* dst) const {
|
||||
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::transform(const SkMatrix& matrix, SkPath* dst) const {
|
||||
}
|
||||
}
|
||||
|
||||
void SkPath::updateBoundsCache() const {
|
||||
if (fFastBoundsIsDirty) {
|
||||
SkRect r;
|
||||
this->computeBounds(&r, kFast_BoundsType);
|
||||
SkASSERT(!fFastBoundsIsDirty);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -1220,7 +1204,7 @@ void SkPath::unflatten(SkFlattenableReadBuffer& buffer) {
|
||||
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 @@ void SkPath::validate() const {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,9 +138,7 @@ bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op) {
|
||||
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);
|
||||
}
|
||||
|
@ -271,11 +271,8 @@ void SkScalerContext::getMetrics(SkGlyph* glyph) {
|
||||
}
|
||||
} 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;
|
||||
|
@ -350,11 +350,8 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
|
||||
return;
|
||||
}
|
||||
|
||||
SkRect r;
|
||||
SkIRect ir;
|
||||
|
||||
path.computeBounds(&r, SkPath::kFast_BoundsType);
|
||||
r.roundOut(&ir);
|
||||
SkIRect ir;
|
||||
path.getBounds().roundOut(&ir);
|
||||
if (ir.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -248,11 +248,8 @@ static void hair_path(const SkPath& path, const SkRegion* clip, SkBlitter* blitt
|
||||
|
||||
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))
|
||||
|
@ -582,11 +582,8 @@ void SkScan::FillPath(const SkPath& path, const SkRegion& clip,
|
||||
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);
|
||||
|
@ -538,8 +538,7 @@ void SkStroke::setJoin(SkPaint::Join join) {
|
||||
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);
|
||||
|
@ -45,12 +45,10 @@ bool Sk2DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width)
|
||||
{
|
||||
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
|
||||
|
@ -443,9 +443,7 @@ static int worst_case_edge_count(const SkPath& path) {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -53,9 +53,7 @@ static void toString(const SkPath& path, SkString* str) {
|
||||
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);
|
||||
|
@ -11,16 +11,11 @@ static void TestPath(skiatest::Reporter* reporter) {
|
||||
REPORTER_ASSERT(reporter, p == p2);
|
||||
REPORTER_ASSERT(reporter, !(p != p2));
|
||||
|
||||
// initialize bounds to not-empty
|
||||
bounds.set(0, 0, SK_Scalar1, SK_Scalar1);
|
||||
p.computeBounds(&bounds, SkPath::kFast_BoundsType);
|
||||
REPORTER_ASSERT(reporter, bounds.isEmpty());
|
||||
REPORTER_ASSERT(reporter, p.getBounds().isEmpty());
|
||||
|
||||
bounds.set(0, 0, SK_Scalar1, SK_Scalar1);
|
||||
p.addRect(bounds);
|
||||
bounds2.setEmpty();
|
||||
p.computeBounds(&bounds2, SkPath::kFast_BoundsType);
|
||||
REPORTER_ASSERT(reporter, bounds == bounds2);
|
||||
REPORTER_ASSERT(reporter, bounds == p.getBounds());
|
||||
|
||||
REPORTER_ASSERT(reporter, p != p2);
|
||||
REPORTER_ASSERT(reporter, !(p == p2));
|
||||
@ -35,8 +30,7 @@ static void TestPath(skiatest::Reporter* reporter) {
|
||||
|
||||
bounds.offset(SK_Scalar1*3, SK_Scalar1*4);
|
||||
p.offset(SK_Scalar1*3, SK_Scalar1*4);
|
||||
p.computeBounds(&bounds2, SkPath::kFast_BoundsType);
|
||||
REPORTER_ASSERT(reporter, bounds == bounds2);
|
||||
REPORTER_ASSERT(reporter, bounds == p.getBounds());
|
||||
|
||||
#if 0 // isRect needs to be implemented
|
||||
REPORTER_ASSERT(reporter, p.isRect(NULL));
|
||||
|
@ -1,9 +1,11 @@
|
||||
#include <iostream>
|
||||
#include "SkGraphics.h"
|
||||
#include "Test.h"
|
||||
|
||||
using namespace skiatest;
|
||||
|
||||
// need to explicitly declare this, or we get some weird infinite loop llist
|
||||
template TestRegistry* TestRegistry::gHead;
|
||||
|
||||
class Iter {
|
||||
public:
|
||||
Iter(Reporter* r) : fReporter(r) {
|
||||
@ -35,13 +37,13 @@ static const char* result2string(Reporter::Result result) {
|
||||
return result == Reporter::kPassed ? "passed" : "FAILED";
|
||||
}
|
||||
|
||||
class PrintfReporter : public Reporter {
|
||||
class DebugfReporter : public Reporter {
|
||||
protected:
|
||||
virtual void onStart(Test* test) {
|
||||
printf("Running %s...\n", test->getName());
|
||||
SkDebugf("Running %s...\n", test->getName());
|
||||
}
|
||||
virtual void onReport(const char desc[], Reporter::Result result) {
|
||||
printf("\t%s: %s\n", result2string(result), desc);
|
||||
SkDebugf("\t%s: %s\n", result2string(result), desc);
|
||||
}
|
||||
virtual void onEnd(Test* test) {}
|
||||
};
|
||||
@ -59,7 +61,7 @@ public:
|
||||
int main (int argc, char * const argv[]) {
|
||||
SkAutoGraphics ag;
|
||||
|
||||
PrintfReporter reporter;
|
||||
DebugfReporter reporter;
|
||||
Iter iter(&reporter);
|
||||
Test* test;
|
||||
|
||||
@ -71,7 +73,7 @@ int main (int argc, char * const argv[]) {
|
||||
int total = reporter.countTests();
|
||||
int passed = reporter.countResults(Reporter::kPassed);
|
||||
int failed = reporter.countResults(Reporter::kFailed);
|
||||
printf("Tests=%d Passed=%d (%g%%) Failed=%d (%g%%)\n", total,
|
||||
SkDebugf("Tests=%d Passed=%d (%g%%) Failed=%d (%g%%)\n", total,
|
||||
passed, passed * 100.f / total,
|
||||
failed, failed * 100.f / total);
|
||||
|
||||
|
@ -68,8 +68,6 @@
|
||||
008C4D980F77DAEE0056981C /* SampleHairline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 008C4D970F77DAEE0056981C /* SampleHairline.cpp */; };
|
||||
009CC9190F65918A002185BE /* SampleFontScalerTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 009CC9180F65918A002185BE /* SampleFontScalerTest.cpp */; };
|
||||
00A41E4B0EFC312F00C9CBEB /* SampleArc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00A41E4A0EFC312F00C9CBEB /* SampleArc.cpp */; };
|
||||
00FACE3C0F7D0E6600F8A7FF /* SkLargeBlock_malloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00FACE3B0F7D0E6600F8A7FF /* SkLargeBlock_malloc.cpp */; };
|
||||
00FACE680F7D23DD00F8A7FF /* SkWriter32_largeBlock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00FACE5C0F7D209700F8A7FF /* SkWriter32_largeBlock.cpp */; };
|
||||
0156F80407C56A3000C6122B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0156F80307C56A3000C6122B /* Foundation.framework */; };
|
||||
01FC44D507BD3BB800D228F4 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 01FC44D407BD3BB800D228F4 /* Quartz.framework */; };
|
||||
8D0C4E8D0486CD37000505A6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0867D6AAFE840B52C02AAC07 /* InfoPlist.strings */; };
|
||||
@ -186,10 +184,6 @@
|
||||
009CC9180F65918A002185BE /* SampleFontScalerTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFontScalerTest.cpp; path = ../../samplecode/SampleFontScalerTest.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00A41E4A0EFC312F00C9CBEB /* SampleArc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleArc.cpp; path = ../../samplecode/SampleArc.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00D6B5CB0F72DC4300C466B9 /* SampleFuzz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFuzz.cpp; path = ../../samplecode/SampleFuzz.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00FACE3B0F7D0E6600F8A7FF /* SkLargeBlock_malloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkLargeBlock_malloc.cpp; path = ../../src/utils/SkLargeBlock_malloc.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00FACE3F0F7D167400F8A7FF /* SkLargeBlock_remap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkLargeBlock_remap.cpp; path = ../../src/utils/SkLargeBlock_remap.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00FACE5C0F7D209700F8A7FF /* SkWriter32_largeBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkWriter32_largeBlock.cpp; path = ../../src/utils/SkWriter32_largeBlock.cpp; sourceTree = SOURCE_ROOT; };
|
||||
00FACE600F7D22CF00F8A7FF /* SkWriter32_noLargeBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkWriter32_noLargeBlock.cpp; path = ../../src/utils/SkWriter32_noLargeBlock.cpp; sourceTree = SOURCE_ROOT; };
|
||||
0156F80307C56A3000C6122B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
||||
01FC44D407BD3BB800D228F4 /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = /System/Library/Frameworks/Quartz.framework; sourceTree = "<absolute>"; };
|
||||
0867D6ABFE840B52C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
@ -337,10 +331,6 @@
|
||||
002884490EFAA35C0083E387 /* core.xcodeproj */,
|
||||
002884B40EFAB69F0083E387 /* maccore.xcodeproj */,
|
||||
00003C8C0EFC230E000FF73A /* effects.xcodeproj */,
|
||||
00FACE3B0F7D0E6600F8A7FF /* SkLargeBlock_malloc.cpp */,
|
||||
00FACE3F0F7D167400F8A7FF /* SkLargeBlock_remap.cpp */,
|
||||
00FACE5C0F7D209700F8A7FF /* SkWriter32_largeBlock.cpp */,
|
||||
00FACE600F7D22CF00F8A7FF /* SkWriter32_noLargeBlock.cpp */,
|
||||
);
|
||||
name = CICarbonSample;
|
||||
sourceTree = "<group>";
|
||||
@ -529,8 +519,6 @@
|
||||
007A7CB30F01658C00A2D6EE /* SamplePicture.cpp in Sources */,
|
||||
0041CE440F00A12400695E8C /* SampleLines.cpp in Sources */,
|
||||
008C4D980F77DAEE0056981C /* SampleHairline.cpp in Sources */,
|
||||
00FACE3C0F7D0E6600F8A7FF /* SkLargeBlock_malloc.cpp in Sources */,
|
||||
00FACE680F7D23DD00F8A7FF /* SkWriter32_largeBlock.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user