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
diff --git a/gpu/include/GrClip.h b/gpu/include/GrClip.h
index 414a6d6..64c9bbb 100644
--- a/gpu/include/GrClip.h
+++ b/gpu/include/GrClip.h
@@ -28,7 +28,11 @@
 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 @@
      *  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 d70609e..80bbeb3 100644
--- a/gpu/include/GrPath.h
+++ b/gpu/include/GrPath.h
@@ -46,6 +46,12 @@
                          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 e0e5326..552fa5e 100644
--- a/gpu/include/GrRect.h
+++ b/gpu/include/GrRect.h
@@ -223,6 +223,14 @@
                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 924c01b..5ba991b 100644
--- a/gpu/src/GrClip.cpp
+++ b/gpu/src/GrClip.cpp
@@ -38,9 +38,10 @@
     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::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 @@
             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 @@
                     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 fc53ac2..019b2fd 100644
--- a/gpu/src/GrPath.cpp
+++ b/gpu/src/GrPath.cpp
@@ -84,12 +84,27 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+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 @@
                 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 @@
                 }
                 ++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 @@
                     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 @@
     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 @@
     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 @@
     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 c0d71c3..48b86c2 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -81,6 +81,13 @@
     /** 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 @@
     }
 
 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 bdb30d9..79ca58c 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 @@
         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 @@
         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 @@
     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 @@
         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 @@
         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 @@
         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 @@
         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 @@
         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 @@
         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 @@
         fX += v.fX;
         fY += v.fY;
     }
-    
+
     /** Subtract v's coordinates from the point's
     */
     void operator-=(const SkPoint& v) {
@@ -249,7 +264,7 @@
     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 664426c..a8d218a 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -72,8 +72,7 @@
     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 @@
             device->lockPixels();
         }
         fDevice = device;
-        fX = SkToS16(x);
-        fY = SkToS16(y);
         fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
 	}
 
@@ -100,8 +97,8 @@
 
     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 @@
         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 @@
             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 @@
         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 @@
 
     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 @@
     */
     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 @@
         }
     }
 
+#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 2383ed9..5e6376e 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 990c24b..86082c5 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -267,29 +267,24 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-#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 @@
         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 @@
                                 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 @@
 
     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);