return this->clipRegion(deviceRgn, SkRegion::kReplace_Op);
}
- /** Enum describing how to treat edges when performing quick-reject tests
- of a geometry against the current clip. Treating them as antialiased
- (kAA_EdgeType) will take into account the extra pixels that may be drawn
- if the edge does not lie exactly on a device pixel boundary (after being
- transformed by the current matrix).
- */
- enum EdgeType {
- /** Treat the edges as B&W (not antialiased) for the purposes of testing
- against the current clip
- */
- kBW_EdgeType,
- /** Treat the edges as antialiased for the purposes of testing
- against the current clip
- */
- kAA_EdgeType
- };
-
/** Return true if the specified rectangle, after being transformed by the
current matrix, would lie completely outside of the current clip. Call
this to check if an area you intend to draw into is clipped out (and
therefore you can skip making the draw calls).
@param rect the rect to compare with the current clip
- @param et specifies how to treat the edges (see EdgeType)
@return true if the rect (transformed by the canvas' matrix) does not
intersect with the canvas' clip
*/
- bool quickReject(const SkRect& rect, EdgeType et) const;
+ bool quickReject(const SkRect& rect) const;
/** Return true if the specified path, after being transformed by the
current matrix, would lie completely outside of the current clip. Call
return false even if the path itself might not intersect the clip
(i.e. the bounds of the path intersects, but the path does not).
@param path The path to compare with the current clip
- @param et specifies how to treat the edges (see EdgeType)
@return true if the path (transformed by the canvas' matrix) does not
intersect with the canvas' clip
*/
- bool quickReject(const SkPath& path, EdgeType et) const;
+ bool quickReject(const SkPath& path) const;
/** Return true if the horizontal band specified by top and bottom is
completely clipped out. This is a conservative calculation, meaning
@return true if the horizontal band is completely clipped out (i.e. does
not intersect the current clip)
*/
- bool quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const {
+ bool quickRejectY(SkScalar top, SkScalar bottom) const {
SkASSERT(SkScalarToCompareType(top) <= SkScalarToCompareType(bottom));
- const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et);
+ const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
// In the case where the clip is empty and we are provided with a
// negative top and positive bottom parameter then this test will return
// false even though it will be clipped. We have chosen to exclude that
in a way similar to quickReject, in that it tells you that drawing
outside of these bounds will be clipped out.
*/
- bool getClipBounds(SkRect* bounds, EdgeType et = kAA_EdgeType) const;
+ bool getClipBounds(SkRect* bounds) const;
/** Return the bounds of the current clip, in device coordinates; returns
true if non-empty. Maybe faster than getting the clip explicitly and
mutable SkRectCompareType fLocalBoundsCompareType;
mutable bool fLocalBoundsCompareTypeDirty;
- mutable SkRectCompareType fLocalBoundsCompareTypeBW;
- mutable bool fLocalBoundsCompareTypeDirtyBW;
-
- /* Get the local clip bounds with an anti-aliased edge.
- */
const SkRectCompareType& getLocalClipBoundsCompareType() const {
- return getLocalClipBoundsCompareType(kAA_EdgeType);
- }
-
- const SkRectCompareType& getLocalClipBoundsCompareType(EdgeType et) const {
- if (et == kAA_EdgeType) {
- if (fLocalBoundsCompareTypeDirty) {
- this->computeLocalClipBoundsCompareType(et);
- fLocalBoundsCompareTypeDirty = false;
- }
- return fLocalBoundsCompareType;
- } else {
- if (fLocalBoundsCompareTypeDirtyBW) {
- this->computeLocalClipBoundsCompareType(et);
- fLocalBoundsCompareTypeDirtyBW = false;
- }
- return fLocalBoundsCompareTypeBW;
+ if (fLocalBoundsCompareTypeDirty) {
+ this->computeLocalClipBoundsCompareType();
+ fLocalBoundsCompareTypeDirty = false;
}
+ return fLocalBoundsCompareType;
}
- void computeLocalClipBoundsCompareType(EdgeType et) const;
+ void computeLocalClipBoundsCompareType() const;
SkMatrix fExternalMatrix, fExternalInverse;
bool fUseExternalMatrix;
typedef SkTLazy<SkPaint> SkLazyPaint;
///////////////////////////////////////////////////////////////////////////////
-// Helpers for computing fast bounds for quickReject tests
-
-static SkCanvas::EdgeType paint2EdgeType(const SkPaint* paint) {
- return paint != NULL && paint->isAntiAlias() ?
- SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType;
-}
-
-///////////////////////////////////////////////////////////////////////////////
/* This is the record we keep for each SkDevice that the user installs.
The clip/matrix/proc are fields that reflect the top of the save/restore
fBounder = NULL;
fLocalBoundsCompareType.setEmpty();
fLocalBoundsCompareTypeDirty = true;
- fLocalBoundsCompareTypeBW.setEmpty();
- fLocalBoundsCompareTypeDirtyBW = true;
fLastDeviceToGainFocus = NULL;
fDeviceCMDirty = false;
fSaveLayerCount = 0;
fDeviceCMDirty = true;
fLocalBoundsCompareTypeDirty = true;
- fLocalBoundsCompareTypeDirtyBW = true;
fClipStack.restore();
// reserve our layer (if any)
bool SkCanvas::translate(SkScalar dx, SkScalar dy) {
fDeviceCMDirty = true;
fLocalBoundsCompareTypeDirty = true;
- fLocalBoundsCompareTypeDirtyBW = true;
return fMCRec->fMatrix->preTranslate(dx, dy);
}
bool SkCanvas::scale(SkScalar sx, SkScalar sy) {
fDeviceCMDirty = true;
fLocalBoundsCompareTypeDirty = true;
- fLocalBoundsCompareTypeDirtyBW = true;
return fMCRec->fMatrix->preScale(sx, sy);
}
bool SkCanvas::rotate(SkScalar degrees) {
fDeviceCMDirty = true;
fLocalBoundsCompareTypeDirty = true;
- fLocalBoundsCompareTypeDirtyBW = true;
return fMCRec->fMatrix->preRotate(degrees);
}
bool SkCanvas::skew(SkScalar sx, SkScalar sy) {
fDeviceCMDirty = true;
fLocalBoundsCompareTypeDirty = true;
- fLocalBoundsCompareTypeDirtyBW = true;
return fMCRec->fMatrix->preSkew(sx, sy);
}
bool SkCanvas::concat(const SkMatrix& matrix) {
fDeviceCMDirty = true;
fLocalBoundsCompareTypeDirty = true;
- fLocalBoundsCompareTypeDirtyBW = true;
return fMCRec->fMatrix->preConcat(matrix);
}
void SkCanvas::setMatrix(const SkMatrix& matrix) {
fDeviceCMDirty = true;
fLocalBoundsCompareTypeDirty = true;
- fLocalBoundsCompareTypeDirtyBW = true;
*fMCRec->fMatrix = matrix;
}
return false;
}
- if (this->quickReject(rect, kAA_EdgeType)) {
+ if (this->quickReject(rect)) {
fDeviceCMDirty = true;
fLocalBoundsCompareTypeDirty = true;
- fLocalBoundsCompareTypeDirtyBW = true;
fClipStack.clipEmpty();
return fMCRec->fRasterClip->setEmpty();
fDeviceCMDirty = true;
fLocalBoundsCompareTypeDirty = true;
- fLocalBoundsCompareTypeDirtyBW = true;
if (fMCRec->fMatrix->rectStaysRect()) {
// for these simpler matrices, we can stay a rect ever after applying
return false;
}
- if (this->quickReject(path.getBounds(), kAA_EdgeType)) {
+ if (this->quickReject(path.getBounds())) {
fDeviceCMDirty = true;
fLocalBoundsCompareTypeDirty = true;
- fLocalBoundsCompareTypeDirtyBW = true;
fClipStack.clipEmpty();
return fMCRec->fRasterClip->setEmpty();
fDeviceCMDirty = true;
fLocalBoundsCompareTypeDirty = true;
- fLocalBoundsCompareTypeDirtyBW = true;
SkPath devPath;
path.transform(*fMCRec->fMatrix, &devPath);
fDeviceCMDirty = true;
fLocalBoundsCompareTypeDirty = true;
- fLocalBoundsCompareTypeDirtyBW = true;
// todo: signal fClipStack that we have a region, and therefore (I guess)
// we have to ignore it, and use the region directly?
///////////////////////////////////////////////////////////////////////////////
-void SkCanvas::computeLocalClipBoundsCompareType(EdgeType et) const {
+void SkCanvas::computeLocalClipBoundsCompareType() const {
SkRect r;
- SkRectCompareType& rCompare = et == kAA_EdgeType ? fLocalBoundsCompareType :
- fLocalBoundsCompareTypeBW;
- if (!this->getClipBounds(&r, et)) {
- rCompare.setEmpty();
+ if (!this->getClipBounds(&r)) {
+ fLocalBoundsCompareType.setEmpty();
} else {
- rCompare.set(SkScalarToCompareType(r.fLeft),
- SkScalarToCompareType(r.fTop),
- SkScalarToCompareType(r.fRight),
- SkScalarToCompareType(r.fBottom));
+ fLocalBoundsCompareType.set(SkScalarToCompareType(r.fLeft),
+ SkScalarToCompareType(r.fTop),
+ SkScalarToCompareType(r.fRight),
+ SkScalarToCompareType(r.fBottom));
}
}
-/* current impl ignores edgetype, and relies on
- getLocalClipBoundsCompareType(), which always returns a value assuming
- antialiasing (worst case)
- */
-bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
+bool SkCanvas::quickReject(const SkRect& rect) const {
if (!rect.isFinite())
return true;
dst.roundOut(&idst);
return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds());
} else {
- const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et);
+ const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
// for speed, do the most likely reject compares first
SkScalarCompareType userT = SkScalarToCompareType(rect.fTop);
}
}
-bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const {
- return path.isEmpty() || this->quickReject(path.getBounds(), et);
+bool SkCanvas::quickReject(const SkPath& path) const {
+ return path.isEmpty() || this->quickReject(path.getBounds());
}
static inline int pinIntForScalar(int x) {
return x;
}
-bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const {
+bool SkCanvas::getClipBounds(SkRect* bounds) const {
SkIRect ibounds;
if (!getClipDeviceBounds(&ibounds)) {
return false;
if (NULL != bounds) {
SkRect r;
- // adjust it outwards if we are antialiasing
- int inset = (kAA_EdgeType == et);
+ // adjust it outwards in case we are antialiasing
+ const int inset = 1;
// SkRect::iset() will correctly assert if we pass a value out of range
// (when SkScalar==fixed), so we pin to legal values. This does not
r.set(pts, count);
}
SkRect storage;
- if (this->quickReject(paint.computeFastStrokeBounds(r, &storage),
- paint2EdgeType(&paint))) {
+ if (this->quickReject(paint.computeFastStrokeBounds(r, &storage))) {
return;
}
}
void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
if (paint.canComputeFastBounds()) {
SkRect storage;
- if (this->quickReject(paint.computeFastBounds(r, &storage),
- paint2EdgeType(&paint))) {
+ if (this->quickReject(paint.computeFastBounds(r, &storage))) {
return;
}
}
if (!path.isInverseFillType() && paint.canComputeFastBounds()) {
SkRect storage;
const SkRect& bounds = path.getBounds();
- if (this->quickReject(paint.computeFastBounds(bounds, &storage),
- paint2EdgeType(&paint))) {
+ if (this->quickReject(paint.computeFastBounds(bounds, &storage))) {
return;
}
}
if (paint) {
(void)paint->computeFastBounds(bounds, &bounds);
}
- if (this->quickReject(bounds, paint2EdgeType(paint))) {
+ if (this->quickReject(bounds)) {
return;
}
}
if (paint) {
bounds = &paint->computeFastBounds(dst, &storage);
}
- if (this->quickReject(*bounds, paint2EdgeType(paint))) {
+ if (this->quickReject(*bounds)) {
return;
}
}
if (paint) {
bounds = &paint->computeFastBounds(dst, &storage);
}
- if (this->quickReject(*bounds, paint2EdgeType(paint))) {
+ if (this->quickReject(*bounds)) {
return;
}
}
if (paint.canComputeFastBounds()) {
SkRect storage;
- if (this->quickReject(paint.computeFastBounds(r, &storage),
- paint2EdgeType(&paint))) {
+ if (this->quickReject(paint.computeFastBounds(r, &storage))) {
return;
}
}
if (rx > 0 && ry > 0) {
if (paint.canComputeFastBounds()) {
SkRect storage;
- if (this->quickReject(paint.computeFastBounds(r, &storage),
- paint2EdgeType(&paint))) {
+ if (this->quickReject(paint.computeFastBounds(r, &storage))) {
return;
}
}
void SkCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
if (paint.canComputeFastBounds()) {
SkRect storage;
- if (this->quickReject(paint.computeFastBounds(oval, &storage),
- paint2EdgeType(&paint))) {
+ if (this->quickReject(paint.computeFastBounds(oval, &storage))) {
return;
}
}
const SkPoint* pos = (const SkPoint*)reader.skip(points * sizeof(SkPoint));
const SkScalar top = reader.readScalar();
const SkScalar bottom = reader.readScalar();
- if (!canvas.quickRejectY(top, bottom, SkCanvas::kAA_EdgeType)) {
+ if (!canvas.quickRejectY(top, bottom)) {
canvas.drawPosText(text.text(), text.length(), pos, paint);
}
} break;
const SkScalar top = *xpos++;
const SkScalar bottom = *xpos++;
const SkScalar constY = *xpos++;
- if (!canvas.quickRejectY(top, bottom, SkCanvas::kAA_EdgeType)) {
+ if (!canvas.quickRejectY(top, bottom)) {
canvas.drawPosTextH(text.text(), text.length(), xpos,
constY, paint);
}
// ptr[1] == y
// ptr[2] == top
// ptr[3] == bottom
- if (!canvas.quickRejectY(ptr[2], ptr[3],
- SkCanvas::kAA_EdgeType)) {
+ if (!canvas.quickRejectY(ptr[2], ptr[3])) {
canvas.drawText(text.text(), text.length(), ptr[0], ptr[1],
paint);
}
SkRect r;
r.set(fLoc.fX, fLoc.fY, fLoc.fX + fWidth, fLoc.fY + fHeight);
if (this->isClipToBounds() &&
- canvas->quickReject(r, SkCanvas::kBW_EdgeType)) {
+ canvas->quickReject(r)) {
return;
}
testStep->assertMessage());
}
TEST_STEP(DrawLayer, DrawLayerTestStep);
-\r
-static void NestedSaveRestoreWithSolidPaintTestStep(SkCanvas* canvas,\r
- skiatest::Reporter* reporter,\r
- CanvasTestStep* testStep) {\r
- // This test step challenges the TestDeferredCanvasStateConsistency\r
- // test cases because the opaque paint can trigger an optimization\r
- // that discards previously recorded commands. The challenge is to maintain\r
- // correct clip and matrix stack state.\r
- canvas->resetMatrix();\r
- canvas->rotate(SkIntToScalar(30));\r
- canvas->save();\r
- canvas->translate(SkIntToScalar(2), SkIntToScalar(1));\r
- canvas->save();\r
- canvas->scale(SkIntToScalar(3), SkIntToScalar(3));\r
- SkPaint paint;\r
- paint.setColor(0xFFFFFFFF);\r
- canvas->drawPaint(paint);\r
- canvas->restore();\r
- canvas->restore();\r
-}\r
-TEST_STEP(NestedSaveRestoreWithSolidPaint, \\r
- NestedSaveRestoreWithSolidPaintTestStep);\r
-\r
-static void NestedSaveRestoreWithFlushTestStep(SkCanvas* canvas,\r
- skiatest::Reporter* reporter,\r
- CanvasTestStep* testStep) {\r
- // This test step challenges the TestDeferredCanvasStateConsistency\r
- // test case because the canvas flush on a deferred canvas will\r
- // reset the recording session. The challenge is to maintain correct\r
- // clip and matrix stack state on the playback canvas.\r
- canvas->resetMatrix();\r
- canvas->rotate(SkIntToScalar(30));\r
- canvas->save();\r
- canvas->translate(SkIntToScalar(2), SkIntToScalar(1));\r
- canvas->save();\r
- canvas->scale(SkIntToScalar(3), SkIntToScalar(3));\r
- canvas->drawRect(kTestRect,kTestPaint);\r
- canvas->flush();\r
- canvas->restore();\r
- canvas->restore();\r
-}\r
-TEST_STEP(NestedSaveRestoreWithFlush, \\r
- NestedSaveRestoreWithFlushTestStep);\r
+
+static void NestedSaveRestoreWithSolidPaintTestStep(SkCanvas* canvas,
+ skiatest::Reporter* reporter,
+ CanvasTestStep* testStep) {
+ // This test step challenges the TestDeferredCanvasStateConsistency
+ // test cases because the opaque paint can trigger an optimization
+ // that discards previously recorded commands. The challenge is to maintain
+ // correct clip and matrix stack state.
+ canvas->resetMatrix();
+ canvas->rotate(SkIntToScalar(30));
+ canvas->save();
+ canvas->translate(SkIntToScalar(2), SkIntToScalar(1));
+ canvas->save();
+ canvas->scale(SkIntToScalar(3), SkIntToScalar(3));
+ SkPaint paint;
+ paint.setColor(0xFFFFFFFF);
+ canvas->drawPaint(paint);
+ canvas->restore();
+ canvas->restore();
+}
+TEST_STEP(NestedSaveRestoreWithSolidPaint, \
+ NestedSaveRestoreWithSolidPaintTestStep);
+
+static void NestedSaveRestoreWithFlushTestStep(SkCanvas* canvas,
+ skiatest::Reporter* reporter,
+ CanvasTestStep* testStep) {
+ // This test step challenges the TestDeferredCanvasStateConsistency
+ // test case because the canvas flush on a deferred canvas will
+ // reset the recording session. The challenge is to maintain correct
+ // clip and matrix stack state on the playback canvas.
+ canvas->resetMatrix();
+ canvas->rotate(SkIntToScalar(30));
+ canvas->save();
+ canvas->translate(SkIntToScalar(2), SkIntToScalar(1));
+ canvas->save();
+ canvas->scale(SkIntToScalar(3), SkIntToScalar(3));
+ canvas->drawRect(kTestRect,kTestPaint);
+ canvas->flush();
+ canvas->restore();
+ canvas->restore();
+}
+TEST_STEP(NestedSaveRestoreWithFlush, \
+ NestedSaveRestoreWithFlushTestStep);
static void AssertCanvasStatesEqual(skiatest::Reporter* reporter,
const SkCanvas* canvas1,
canvas2->getSaveCount(), testStep->assertMessage());
REPORTER_ASSERT_MESSAGE(reporter, canvas1->isDrawingToLayer() ==
canvas2->isDrawingToLayer(), testStep->assertMessage());
+
SkRect bounds1, bounds2;
REPORTER_ASSERT_MESSAGE(reporter,
- canvas1->getClipBounds(&bounds1, SkCanvas::kAA_EdgeType) ==
- canvas2->getClipBounds(&bounds2, SkCanvas::kAA_EdgeType),
+ canvas1->getClipBounds(&bounds1) == canvas2->getClipBounds(&bounds2),
testStep->assertMessage());
REPORTER_ASSERT_MESSAGE(reporter, bounds1 == bounds2,
- testStep->assertMessage());
- REPORTER_ASSERT_MESSAGE(reporter,
- canvas1->getClipBounds(&bounds1, SkCanvas::kBW_EdgeType) ==
- canvas2->getClipBounds(&bounds2, SkCanvas::kBW_EdgeType),
- testStep->assertMessage());
- REPORTER_ASSERT_MESSAGE(reporter, bounds1 == bounds2,
- testStep->assertMessage());
+ testStep->assertMessage());
+
REPORTER_ASSERT_MESSAGE(reporter, canvas1->getDrawFilter() ==
canvas2->getDrawFilter(), testStep->assertMessage());
SkIRect deviceBounds1, deviceBounds2;