Add bounding rect for paths

Review URL: http://codereview.appspot.com/4442094/



git-svn-id: http://skia.googlecode.com/svn/trunk@1205 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrPath.h b/gpu/include/GrPath.h
index 80bbeb3..f958329 100644
--- a/gpu/include/GrPath.h
+++ b/gpu/include/GrPath.h
@@ -22,6 +22,7 @@
 #include "GrPathIter.h"
 #include "GrTDArray.h"
 #include "GrPoint.h"
+#include "GrRect.h"
 
 class GrPath : public GrPathSink {
 public:
@@ -33,6 +34,8 @@
     GrConvexHint getConvexHint() const { return fConvexHint; }
     void setConvexHint(GrConvexHint hint) { fConvexHint = hint; }
 
+    const GrRect& getConservativeBounds() const { return fConservativeBounds; }
+
     void resetFromIter(GrPathIter*);
 
     bool operator ==(const GrPath& path) const;
@@ -66,6 +69,7 @@
         virtual GrConvexHint convexHint() const;
         virtual GrPathCmd next();
         virtual void rewind();
+        virtual bool getConservativeBounds(GrRect* rect) const;
 
         /**
          * Sets iterator to begining of path
@@ -84,7 +88,8 @@
 
     GrTDArray<GrPathCmd>    fCmds;
     GrTDArray<GrPoint>      fPts;
-    GrConvexHint  fConvexHint;
+    GrConvexHint            fConvexHint;
+    GrRect                  fConservativeBounds;
 
     // this ensures we have a moveTo at the start of each contour
     inline void ensureMoveTo();
diff --git a/gpu/include/GrPathIter.h b/gpu/include/GrPathIter.h
index 55427c0..5261f0f 100644
--- a/gpu/include/GrPathIter.h
+++ b/gpu/include/GrPathIter.h
@@ -21,6 +21,7 @@
 #include "GrTypes.h"
 
 struct GrPoint;
+struct GrRect;
 
 /**
  2D Path iterator. Porting layer creates a subclass of this. It allows Ganesh to
@@ -60,6 +61,12 @@
       */
      virtual GrPathCmd next() = 0;
 
+     /**
+      * Returns conservative bounds on the path points. If returns false then
+      * no bounds are available.
+      */
+     virtual bool getConservativeBounds(GrRect* rect) const = 0;
+
     /**
      Restarts iteration from the beginning.
      */
diff --git a/gpu/include/GrRect.h b/gpu/include/GrRect.h
index b85574a..8a63cdc 100644
--- a/gpu/include/GrRect.h
+++ b/gpu/include/GrRect.h
@@ -225,6 +225,15 @@
     }
 
     /**
+     * Returns true if the rect contains the point or the
+     * point lies on the edge of the rect.
+     */
+    bool containsInclusive(const GrPoint& point) const {
+        return point.fX >= fLeft && point.fX <= fRight &&
+               point.fY >= fTop && point.fY <= fBottom;
+    }
+
+    /**
      * Does this rect fully contain another rect.
      */
     bool contains(const GrRect& r) const {
@@ -333,6 +342,14 @@
         fBottom = GrMax(pt.fY, fBottom);
     }
 
+    void growToInclude(GrScalar x, GrScalar y) {
+        fLeft  = GrMin(x, fLeft);
+        fRight = GrMax(y, fRight);
+
+        fTop    = GrMin(x, fTop);
+        fBottom = GrMax(y, fBottom);
+    }
+
     /**
      * Grows a rect to include another rect.
      * @param rect the rect to include
@@ -390,6 +407,14 @@
         }
     }
 
+    void translate(GrScalar tx, GrScalar ty) {
+        fLeft += tx;
+        fRight += tx;
+
+        fTop += ty;
+        fBottom += ty;
+    }
+
     bool operator ==(const GrRect& r) const {
         return fLeft == r.fLeft     &&
                fTop == r.fTop       &&
diff --git a/gpu/src/GrPath.cpp b/gpu/src/GrPath.cpp
index a740dfc..17ecd5d 100644
--- a/gpu/src/GrPath.cpp
+++ b/gpu/src/GrPath.cpp
@@ -2,6 +2,7 @@
 
 GrPath::GrPath() {
     fConvexHint = kNone_ConvexHint;
+    fConservativeBounds.setLargestInverted();
 }
 
 GrPath::GrPath(const GrPath& src) : INHERITED() {
@@ -40,6 +41,7 @@
     if (fCmds.isEmpty() || this->wasLastVerb(kClose_PathCmd)) {
         *fCmds.append() = kMove_PathCmd;
         fPts.append()->set(0, 0);
+        fConservativeBounds.growToInclude(0,0);
     }
 }
 
@@ -51,12 +53,14 @@
         *fCmds.append() = kMove_PathCmd;
         fPts.append()->set(x, y);
     }
+    fConservativeBounds.growToInclude(x,y);
 }
 
 void GrPath::lineTo(GrScalar x, GrScalar y) {
     this->ensureMoveTo();
     *fCmds.append() = kLine_PathCmd;
     fPts.append()->set(x, y);
+    fConservativeBounds.growToInclude(x,y);
 }
 
 void GrPath::quadTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1) {
@@ -64,6 +68,8 @@
     *fCmds.append() = kQuadratic_PathCmd;
     fPts.append()->set(x0, y0);
     fPts.append()->set(x1, y1);
+    fConservativeBounds.growToInclude(x0,y0);
+    fConservativeBounds.growToInclude(x1,y1);
 }
 
 void GrPath::cubicTo(GrScalar x0, GrScalar y0, GrScalar x1, GrScalar y1,
@@ -73,6 +79,9 @@
     fPts.append()->set(x0, y0);
     fPts.append()->set(x1, y1);
     fPts.append()->set(x2, y2);
+    fConservativeBounds.growToInclude(x0,y0);
+    fConservativeBounds.growToInclude(x1,y1);
+    fConservativeBounds.growToInclude(x2,y2);
 }
 
 void GrPath::close() {
@@ -95,6 +104,7 @@
         iter->offset(tx, ty);
         ++iter;
     }
+    fConservativeBounds.translate(tx, ty);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -148,6 +158,7 @@
 void GrPath::resetFromIter(GrPathIter* iter) {
     fPts.reset();
     fCmds.reset();
+    fConservativeBounds.setLargestInverted();
 
     fConvexHint = iter->convexHint();
 
@@ -209,6 +220,9 @@
                 break;
         }
         int n = NumPathCmdPoints(cmd);
+        for (int i = 0; i < n; ++i) {
+            fConservativeBounds.growToInclude(pts[i]);
+        }
         if (0 == subPathPts && n > 0) {
             previousPt = pts[0];
             firstPt = previousPt;
@@ -427,6 +441,7 @@
             }
             fLastPt = srcPts[0];
             GrAssert(fPtIndex <= fPath->fPts.count() + 1);
+            GrAssert(fPath->getConservativeBounds().containsInclusive(srcPts[0]));
             fPtIndex += 1;
             break;
         case kLine_PathCmd:
@@ -436,6 +451,7 @@
             }
             fLastPt = srcPts[0];
             GrAssert(fPtIndex <= fPath->fPts.count() + 1);
+            GrAssert(fPath->getConservativeBounds().containsInclusive(srcPts[0]));
             fPtIndex += 1;
             break;
         case kQuadratic_PathCmd:
@@ -446,6 +462,8 @@
             }
             fLastPt = srcPts[1];
             GrAssert(fPtIndex <= fPath->fPts.count() + 2);
+            GrAssert(fPath->getConservativeBounds().containsInclusive(srcPts[0]));
+            GrAssert(fPath->getConservativeBounds().containsInclusive(srcPts[1]));
             fPtIndex += 2;
             break;
         case kCubic_PathCmd:
@@ -457,6 +475,9 @@
             }
             fLastPt = srcPts[2];
             GrAssert(fPtIndex <= fPath->fPts.count() + 3);
+            GrAssert(fPath->getConservativeBounds().containsInclusive(srcPts[0]));
+            GrAssert(fPath->getConservativeBounds().containsInclusive(srcPts[1]));
+            GrAssert(fPath->getConservativeBounds().containsInclusive(srcPts[2]));
             fPtIndex += 3;
             break;
         case kClose_PathCmd:
@@ -485,4 +506,11 @@
     fCmdIndex = fPtIndex = 0;
 }
 
+bool GrPath::Iter::getConservativeBounds(GrRect* rect) const {
+    if (!fPath->getConservativeBounds().isEmpty()) {
+        *rect = fPath->getConservativeBounds();
+        return true;
+    }
+    return false;
+}
 
diff --git a/include/gpu/SkGr.h b/include/gpu/SkGr.h
index 10f1bd0..bcb6766 100644
--- a/include/gpu/SkGr.h
+++ b/include/gpu/SkGr.h
@@ -169,6 +169,7 @@
     virtual GrPathCmd next();
     virtual void rewind();
     virtual GrConvexHint convexHint() const;
+    virtual bool getConservativeBounds(GrRect* rect) const;
 
     void reset(const SkPath& path) {
         fPath = &path;
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index f6e1425..23918f9 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -143,6 +143,11 @@
                                kNone_ConvexHint;
 }
 
+bool SkGrPathIter::getConservativeBounds(GrRect* rect) const {
+    *rect = Sk2Gr(fPath->getBounds());
+    return true;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 void SkGrClipIterator::reset(const SkClipStack& clipStack) {