Add a conservativelyContainsRect function to SkPath.
Review URL: https://codereview.appspot.com/6852044

git-svn-id: http://skia.googlecode.com/svn/trunk@6411 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index d1b90dd..b7c2162 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -311,6 +311,86 @@
     }
 }
 
+static inline bool check_edge_against_rect(const SkPoint& p0,
+                                           const SkPoint& p1,
+                                           const SkRect& rect,
+                                           SkPath::Direction dir) {
+    const SkPoint* edgeBegin;
+    SkVector v;
+    if (SkPath::kCW_Direction == dir) {
+        v = p1 - p0;
+        edgeBegin = &p0;
+    } else {
+        v = p0 - p1;
+        edgeBegin = &p1;
+    }
+    if (v.fX || v.fY) {
+        // check the cross product of v with the vec from edgeBegin to each rect corner
+        SkScalar yL = SkScalarMul(v.fY, rect.fLeft - edgeBegin->fX);
+        SkScalar xT = SkScalarMul(v.fX, rect.fTop - edgeBegin->fY);
+        SkScalar yR = SkScalarMul(v.fY, rect.fRight - edgeBegin->fX);
+        SkScalar xB = SkScalarMul(v.fX, rect.fBottom - edgeBegin->fY);
+        if ((xT < yL) || (xT < yR) || (xB < yL) || (xB < yR)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool SkPath::conservativelyContainsRect(const SkRect& rect) const {
+    // This only handles non-degenerate convex paths currently.
+    if (kConvex_Convexity != this->getConvexity()) {
+        return false;
+    }
+    
+    Direction direction;
+    if (!this->cheapComputeDirection(&direction)) {
+        return false;
+    }
+
+    SkPoint firstPt;
+    SkPoint prevPt;
+    RawIter iter(*this);
+    SkPath::Verb verb;
+    SkPoint pts[4];
+    SkDEBUGCODE(int moveCnt = 0;)
+
+    while ((verb = iter.next(pts)) != kDone_Verb) {
+        int nextPt = -1;
+        switch (verb) {
+            case kMove_Verb:
+                SkASSERT(!moveCnt);
+                SkDEBUGCODE(++moveCnt);
+                firstPt = prevPt = pts[0];
+                break;
+            case kLine_Verb:
+                nextPt = 1;
+                SkASSERT(moveCnt);
+                break;
+            case kQuad_Verb:
+                SkASSERT(moveCnt);
+                nextPt = 2;
+                break;
+            case kCubic_Verb:
+                SkASSERT(moveCnt);
+                nextPt = 3;
+                break;
+            case kClose_Verb:
+                break;
+            default:
+                SkDEBUGFAIL("unknown verb");
+        }
+        if (-1 != nextPt) {
+            if (!check_edge_against_rect(prevPt, pts[nextPt], rect, direction)) {
+                return false;
+            }
+            prevPt = pts[nextPt];
+        }
+    }
+
+    return check_edge_against_rect(prevPt, firstPt, rect, direction);
+}
+
 #ifdef SK_BUILD_FOR_ANDROID
 uint32_t SkPath::getGenerationID() const {
     return fGenerationID;