From 6f8f292aa768869a9e85c314b124875f57504f2c Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Fri, 4 Mar 2011 22:27:10 +0000 Subject: [PATCH] add origin to device used for interpreting the clipstack when a device is a layer git-svn-id: http://skia.googlecode.com/svn/trunk@894 2bbb7eff-a529-9590-31e7-b0007b416f81 --- gpu/include/GrClip.h | 13 ++++++++-- gpu/include/GrPath.h | 6 +++++ gpu/include/GrRect.h | 8 ++++++ gpu/src/GrClip.cpp | 14 ++++++++--- gpu/src/GrPath.cpp | 33 ++++++++++++++++++------- include/core/SkDevice.h | 12 +++++++++ include/core/SkPoint.h | 55 ++++++++++++++++++++++++++--------------- src/core/SkCanvas.cpp | 30 ++++++++-------------- src/core/SkDevice.cpp | 5 +++- src/gpu/SkGpuDevice.cpp | 19 ++++++-------- 10 files changed, 128 insertions(+), 67 deletions(-) diff --git a/gpu/include/GrClip.h b/gpu/include/GrClip.h index 414a6d6806..64c9bbbb34 100644 --- a/gpu/include/GrClip.h +++ b/gpu/include/GrClip.h @@ -28,7 +28,11 @@ class GrClip { public: GrClip(); GrClip(const GrClip& src); - GrClip(GrClipIterator* iter, const GrRect* bounds = NULL); + /** + * If specified, the bounds parameter already takes (tx,ty) into account. + */ + GrClip(GrClipIterator* iter, GrScalar tx, GrScalar ty, + const GrRect* bounds = NULL); GrClip(const GrIRect& rect); GrClip(const GrRect& rect); @@ -77,7 +81,12 @@ public: * Resets this clip to be empty */ void setEmpty(); - void setFromIterator(GrClipIterator* iter, const GrRect* bounds = NULL); + + /** + * If specified, the bounds parameter already takes (tx,ty) into account. + */ + void setFromIterator(GrClipIterator* iter, GrScalar tx, GrScalar ty, + const GrRect* bounds = NULL); void setFromRect(const GrRect& rect); void setFromIRect(const GrIRect& rect); diff --git a/gpu/include/GrPath.h b/gpu/include/GrPath.h index d70609ee6b..80bbeb358b 100644 --- a/gpu/include/GrPath.h +++ b/gpu/include/GrPath.h @@ -46,6 +46,12 @@ public: GrScalar x2, GrScalar y2); virtual void close(); + /** + * Offset the path by (tx, ty), adding tx to the horizontal position + * and adds ty to the vertical position of every point. + */ + void offset(GrScalar tx, GrScalar ty); + class Iter : public GrPathIter { public: /** diff --git a/gpu/include/GrRect.h b/gpu/include/GrRect.h index e0e53264fd..552fa5e58c 100644 --- a/gpu/include/GrRect.h +++ b/gpu/include/GrRect.h @@ -223,6 +223,14 @@ struct GrRect { fBottom >= r.fBottom; } + /** + * Offset the rectangle by (tx, ty), adding tx to the horizontal position + * and adds ty to the vertical position. + */ + void offset(GrScalar tx, GrScalar ty) { + fLeft += tx; fTop += ty; + fRight += tx; fBottom += ty; + } /** * Initialize a rectangle to a point. diff --git a/gpu/src/GrClip.cpp b/gpu/src/GrClip.cpp index 924c01b9f8..5ba991bb1c 100644 --- a/gpu/src/GrClip.cpp +++ b/gpu/src/GrClip.cpp @@ -38,9 +38,10 @@ GrClip::GrClip(const GrRect& rect) this->setFromRect(rect); } -GrClip::GrClip(GrClipIterator* iter, const GrRect* bounds) +GrClip::GrClip(GrClipIterator* iter, GrScalar tx, GrScalar ty, + const GrRect* bounds) : fList(fListMemory, kPreAllocElements) { - this->setFromIterator(iter, bounds); + this->setFromIterator(iter, tx, ty, bounds); } GrClip::~GrClip() {} @@ -86,7 +87,8 @@ void GrClip::setFromIRect(const GrIRect& r) { } } -void GrClip::setFromIterator(GrClipIterator* iter, const GrRect* bounds) { +void GrClip::setFromIterator(GrClipIterator* iter, GrScalar tx, GrScalar ty, + const GrRect* bounds) { fList.reset(); int rectCount = 0; @@ -104,6 +106,9 @@ void GrClip::setFromIterator(GrClipIterator* iter, const GrRect* bounds) { switch (e.fType) { case kRect_ClipType: iter->getRect(&e.fRect); + if (tx || ty) { + e.fRect.offset(tx, ty); + } ++rectCount; if (isectRectValid) { if (1 == rectCount || kIntersect_SetOp == e.fOp) { @@ -122,6 +127,9 @@ void GrClip::setFromIterator(GrClipIterator* iter, const GrRect* bounds) { break; case kPath_ClipType: e.fPath.resetFromIter(iter->getPathIter()); + if (tx || ty) { + e.fPath.offset(tx, ty); + } e.fPathFill = iter->getPathFill(); isectRectValid = false; break; diff --git a/gpu/src/GrPath.cpp b/gpu/src/GrPath.cpp index fc53ac2335..019b2fd5c4 100644 --- a/gpu/src/GrPath.cpp +++ b/gpu/src/GrPath.cpp @@ -84,12 +84,27 @@ void GrPath::close() { /////////////////////////////////////////////////////////////////////////////// +void GrPath::offset(GrScalar tx, GrScalar ty) { + if (!tx && !ty) { + return; // nothing to do + } + + GrPoint* iter = fPts.begin(); + GrPoint* stop = fPts.end(); + while (iter < stop) { + iter->offset(tx, ty); + ++iter; + } +} + +/////////////////////////////////////////////////////////////////////////////// + static bool check_two_vecs(const GrVec& prevVec, const GrVec& currVec, GrScalar turnDir, int* xDir, int* yDir, - int* flipX, + int* flipX, int* flipY) { if (currVec.fX * *xDir < 0) { ++*flipX; @@ -214,9 +229,9 @@ void GrPath::resetFromIter(GrPathIter* iter) { vec.setBetween(previousPt, pts[consumed]); if (vec.fX || vec.fY) { if (subPathPts >= 2) { - if (0 == turnDir) { + if (0 == turnDir) { firstVec = previousVec; - init_from_two_vecs(firstVec, vec, + init_from_two_vecs(firstVec, vec, &turnDir, &xDir, &yDir); // here we aren't checking whether the x/y dirs // change between the first and second edge. It @@ -236,14 +251,14 @@ void GrPath::resetFromIter(GrPathIter* iter) { } ++consumed; } - if (subPathPts > 2 && (kClose_PathCmd == cmd || + if (subPathPts > 2 && (kClose_PathCmd == cmd || (!subPathClosed && kEnd_PathCmd == cmd ))) { // if an additional vector is needed to close the loop check // that it validates against the previous vector. GrVec vec; vec.setBetween(previousPt, firstPt); if (vec.fX || vec.fY) { - if (!check_two_vecs(previousVec, vec, turnDir, + if (!check_two_vecs(previousVec, vec, turnDir, &xDir, &yDir, &flipX, &flipY)) { fConvexHint = kConcave_ConvexHint; break; @@ -251,7 +266,7 @@ void GrPath::resetFromIter(GrPathIter* iter) { previousVec = vec; } // check that closing vector validates against the first vector. - if (!check_two_vecs(previousVec, firstVec, turnDir, + if (!check_two_vecs(previousVec, firstVec, turnDir, &xDir, &yDir, &flipX, &flipY)) { fConvexHint = kConcave_ConvexHint; break; @@ -309,7 +324,7 @@ void GrPath::ConvexUnitTest() { testIter.reset(triRight); testPath.resetFromIter(&testIter); GrAssert(kConvex_ConvexHint == testPath.getConvexHint()); - + GrPath square; square.moveTo(0, 0); square.lineTo(1, 0); @@ -335,7 +350,7 @@ void GrPath::ConvexUnitTest() { square.lineTo(0, 1); square.lineTo(0, 1); square.close(); - + testIter.reset(redundantSquare); testPath.resetFromIter(&testIter); GrAssert(kConvex_ConvexHint == testPath.getConvexHint()); @@ -354,7 +369,7 @@ void GrPath::ConvexUnitTest() { bowTie.lineTo(0, 1); bowTie.lineTo(0, 1); bowTie.close(); - + testIter.reset(bowTie); testPath.resetFromIter(&testIter); GrAssert(kConcave_ConvexHint == testPath.getConvexHint()); diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h index c0d71c3f8e..48b86c2be6 100644 --- a/include/core/SkDevice.h +++ b/include/core/SkDevice.h @@ -81,6 +81,13 @@ public: /** Return the height of the device (in pixels). */ virtual int height() const { return fBitmap.height(); } + + /** + * Return the device's origin: its offset in device coordinates from + * the default origin in its canvas' matrix/clip + */ + const SkIPoint& getOrigin() const { return fOrigin; } + /** Return the bitmap config of the device's pixels */ SkBitmap::Config config() const { return fBitmap.getConfig(); } @@ -217,9 +224,14 @@ protected: } private: + friend class SkCanvas; + // just called by SkCanvas when built as a layer + void setOrigin(int x, int y) { fOrigin.set(x, y); } + SkCanvas* fCanvas; SkBitmap fBitmap; SkRefDict fRefDict; + SkIPoint fOrigin; }; #endif diff --git a/include/core/SkPoint.h b/include/core/SkPoint.h index bdb30d99ee..79ca58c4ea 100644 --- a/include/core/SkPoint.h +++ b/include/core/SkPoint.h @@ -26,13 +26,28 @@ */ struct SkIPoint { int32_t fX, fY; - + static SkIPoint Make(int32_t x, int32_t y) { SkIPoint pt; pt.set(x, y); return pt; } + int32_t x() const { return fX; } + int32_t y() const { return fY; } + void setX(int32_t x) { fX = x; } + void setY(int32_t y) { fY = y; } + + /** + * Returns true iff fX and fY are both zero. + */ + bool isZero() const { return (fX | fY) == 0; } + + /** + * Set both fX and fY to zero. Same as set(0, 0) + */ + void setZero() { fX = fY = 0; } + /** Set the x and y values of the point. */ void set(int32_t x, int32_t y) { fX = x; fY = y; } @@ -55,11 +70,11 @@ struct SkIPoint { the point */ void rotateCCW() { this->rotateCCW(this); } - + /** Negate the X and Y coordinates of the point. */ void negate() { fX = -fX; fY = -fY; } - + /** Return a new point whose X and Y coordinates are the negative of the original point's */ @@ -75,7 +90,7 @@ struct SkIPoint { fX += v.fX; fY += v.fY; } - + /** Subtract v's coordinates from this point's */ void operator-=(const SkIPoint& v) { fX -= v.fX; @@ -90,7 +105,7 @@ struct SkIPoint { friend bool operator==(const SkIPoint& a, const SkIPoint& b) { return a.fX == b.fX && a.fY == b.fY; } - + friend bool operator!=(const SkIPoint& a, const SkIPoint& b) { return a.fX != b.fX || a.fY != b.fY; } @@ -111,7 +126,7 @@ struct SkIPoint { v.set(a.fX + b.fX, a.fY + b.fY); return v; } - + /** Returns the dot product of a and b, treating them as 2D vectors */ static int32_t DotProduct(const SkIPoint& a, const SkIPoint& b) { @@ -133,10 +148,10 @@ struct SkPoint { pt.set(x, y); return pt; } - + /** Set the point's X and Y coordinates */ void set(SkScalar x, SkScalar y) { fX = x; fY = y; } - + /** Set the point's X and Y coordinates by automatically promoting (x,y) to SkScalar values. */ @@ -144,7 +159,7 @@ struct SkPoint { fX = SkIntToScalar(x); fY = SkIntToScalar(y); } - + /** Set the point's X and Y coordinates by automatically promoting p's coordinates to SkScalar values. */ @@ -163,19 +178,19 @@ struct SkPoint { return true. */ bool normalize(); - + /** Set the point (vector) to be unit-length in the same direction as the x,y params. If the vector (x,y) has a degenerate length (i.e. nearly 0) then return false and do nothing, otherwise return true. */ bool setNormalize(SkScalar x, SkScalar y); - + /** Scale the point (vector) to have the specified length, and return that length. If the original length is degenerately small (nearly zero), do nothing and return false, otherwise return true. */ bool setLength(SkScalar length); - + /** Set the point (vector) to have the specified length in the same direction as (x,y). If the vector (x,y) has a degenerate length (i.e. nearly 0) then return false and do nothing, otherwise return true. @@ -186,7 +201,7 @@ struct SkPoint { It is legal for dst == this. */ void scale(SkScalar scale, SkPoint* dst) const; - + /** Scale the point's coordinates by scale, writing the answer back into the point. */ @@ -196,29 +211,29 @@ struct SkPoint { It is legal for dst == this. */ void rotateCW(SkPoint* dst) const; - + /** Rotate the point clockwise by 90 degrees, writing the answer back into the point. */ void rotateCW() { this->rotateCW(this); } - + /** Rotate the point counter-clockwise by 90 degrees, writing the answer into dst. It is legal for dst == this. */ void rotateCCW(SkPoint* dst) const; - + /** Rotate the point counter-clockwise by 90 degrees, writing the answer back into the point. */ void rotateCCW() { this->rotateCCW(this); } - + /** Negate the point's coordinates */ void negate() { fX = -fX; fY = -fY; } - + /** Returns a new point whose coordinates are the negative of the point's */ SkPoint operator-() const { @@ -234,7 +249,7 @@ struct SkPoint { fX += v.fX; fY += v.fY; } - + /** Subtract v's coordinates from the point's */ void operator-=(const SkPoint& v) { @@ -249,7 +264,7 @@ struct SkPoint { friend bool operator==(const SkPoint& a, const SkPoint& b) { return a.fX == b.fX && a.fY == b.fY; } - + friend bool operator!=(const SkPoint& a, const SkPoint& b) { return a.fX != b.fX || a.fY != b.fY; } diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 664426cf1f..a8d218ae56 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -72,8 +72,7 @@ struct DeviceCM { SkDevice* fDevice; SkRegion fClip; const SkMatrix* fMatrix; - SkPaint* fPaint; // may be null (in the future) - int16_t fX, fY; // relative to base matrix/clip + SkPaint* fPaint; // may be null (in the future) // optional, related to canvas' external matrix const SkMatrix* fMVMatrix; const SkMatrix* fExtMatrix; @@ -85,8 +84,6 @@ struct DeviceCM { device->lockPixels(); } fDevice = device; - fX = SkToS16(x); - fY = SkToS16(y); fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL; } @@ -100,8 +97,8 @@ struct DeviceCM { void updateMC(const SkMatrix& totalMatrix, const SkRegion& totalClip, const SkClipStack& clipStack, SkRegion* updateClip) { - int x = fX; - int y = fY; + int x = fDevice->getOrigin().x(); + int y = fDevice->getOrigin().y(); int width = fDevice->width(); int height = fDevice->height(); @@ -147,12 +144,6 @@ struct DeviceCM { fExtMatrix = &extM; // assumes extM has long life-time (owned by canvas) } - void translateClip() { - if (fX | fY) { - fClip.translate(fX, fY); - } - } - private: SkMatrix fMatrixStorage, fMVMatrixStorage; }; @@ -251,8 +242,6 @@ public: fClip = &rec->fClip; fDevice = rec->fDevice; fBitmap = &fDevice->accessBitmap(true); - fLayerX = rec->fX; - fLayerY = rec->fY; fPaint = rec->fPaint; fMVMatrix = rec->fMVMatrix; fExtMatrix = rec->fExtMatrix; @@ -270,18 +259,17 @@ public: return false; } - int getX() const { return fLayerX; } - int getY() const { return fLayerY; } SkDevice* getDevice() const { return fDevice; } + int getX() const { return fDevice->getOrigin().x(); } + int getY() const { return fDevice->getOrigin().y(); } const SkMatrix& getMatrix() const { return *fMatrix; } const SkRegion& getClip() const { return *fClip; } const SkPaint* getPaint() const { return fPaint; } + private: SkCanvas* fCanvas; const DeviceCM* fCurrLayer; const SkPaint* fPaint; // May be null. - int fLayerX; - int fLayerY; SkBool8 fSkipEmptyClips; typedef SkDraw INHERITED; @@ -748,6 +736,7 @@ int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SkDevice* device = this->createDevice(config, ir.width(), ir.height(), isOpaque, true); + device->setOrigin(ir.fLeft, ir.fTop); DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint)); device->unref(); @@ -800,7 +789,8 @@ void SkCanvas::internalRestore() { */ if (NULL != layer) { if (layer->fNext) { - this->drawDevice(layer->fDevice, layer->fX, layer->fY, + const SkIPoint& origin = layer->fDevice->getOrigin(); + this->drawDevice(layer->fDevice, origin.x(), origin.y(), layer->fPaint); // reset this, since drawDevice will have set it to true fDeviceCMDirty = true; @@ -1035,9 +1025,9 @@ void SkCanvas::validateClip() const { } } +#if 0 // enable this locally for testing // now compare against the current rgn const SkRegion& rgn = this->getTotalClip(); -#if 0 // disable for now (reed) SkASSERT(rgn == clipRgn); #endif } diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 2383ed98b8..5e6376e2e1 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -4,10 +4,13 @@ SkDeviceFactory::~SkDeviceFactory() {} -SkDevice::SkDevice(SkCanvas* canvas) : fCanvas(canvas) {} +SkDevice::SkDevice(SkCanvas* canvas) : fCanvas(canvas) { + fOrigin.setZero(); +} SkDevice::SkDevice(SkCanvas* canvas, const SkBitmap& bitmap, bool isForLayer) : fCanvas(canvas), fBitmap(bitmap) { + fOrigin.setZero(); // auto-allocate if we're for offscreen drawing if (isForLayer) { if (NULL == fBitmap.getPixels() && NULL == fBitmap.pixelRef()) { diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 990c24ba69..86082c5e50 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -267,29 +267,24 @@ void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) { /////////////////////////////////////////////////////////////////////////////// -#define USE_CLIP_STACK 0 - static void convert_matrixclip(GrContext* context, const SkMatrix& matrix, const SkClipStack& clipStack, - const SkRegion& clipRegion) { + const SkRegion& clipRegion, + const SkIPoint& origin) { GrMatrix grmat; SkGr::SkMatrix2GrMatrix(matrix, &grmat); context->setMatrix(grmat); -#if USE_CLIP_STACK SkGrClipIterator iter; iter.reset(clipStack); -#else - SkGrRegionIterator iter; - iter.reset(clipRegion); -#endif const SkIRect& skBounds = clipRegion.getBounds(); GrRect bounds; bounds.setLTRB(GrIntToScalar(skBounds.fLeft), GrIntToScalar(skBounds.fTop), GrIntToScalar(skBounds.fRight), GrIntToScalar(skBounds.fBottom)); - GrClip grc(&iter, &bounds); + GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()), + &bounds); context->setClip(grc); } @@ -302,7 +297,7 @@ void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) { fContext->setRenderTarget(fRenderTarget); SkASSERT(draw.fClipStack); convert_matrixclip(fContext, *draw.fMatrix, - *draw.fClipStack, *draw.fClip); + *draw.fClipStack, *draw.fClip, this->getOrigin()); fNeedPrepareRenderTarget = false; } } @@ -311,7 +306,7 @@ void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip, const SkClipStack& clipStack) { this->INHERITED::setMatrixClip(matrix, clip, clipStack); - convert_matrixclip(fContext, matrix, clipStack, clip); + convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin()); } void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix, @@ -321,7 +316,7 @@ void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix, this->INHERITED::gainFocus(canvas, matrix, clip, clipStack); - convert_matrixclip(fContext, matrix, clipStack, clip); + convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin()); if (fNeedClear) { fContext->eraseColor(0x0);