Add SkPath::getVerbs/countVerbs
authorbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 7 Jun 2012 21:43:15 +0000 (21:43 +0000)
committerbsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 7 Jun 2012 21:43:15 +0000 (21:43 +0000)
Review URL: http://codereview.appspot.com/6306053/

git-svn-id: http://skia.googlecode.com/svn/trunk@4209 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkPath.h
include/core/SkTDArray.h
src/core/SkGlyphCache.cpp
src/core/SkPath.cpp
tests/PathTest.cpp

index 4e987c0..e6989f2 100644 (file)
@@ -259,6 +259,21 @@ public:
     */
     int getPoints(SkPoint points[], int max) const;
 
+    /** Return the number of verbs in the path
+     */
+    int countVerbs() const {
+        return this->getVerbs(NULL, 0);
+    }
+
+    /** Returns the number of verbs in the path. Up to max verbs are copied. The
+        verbs are copied as one byte per verb.
+        
+        @param verbs If not null, receives up to max verbs
+        @param max The maximum number of verbs to copy into verbs
+        @return the actual number of verbs in the path
+    */
+    int getVerbs(uint8_t verbs[], int max) const;
+
     //! Swap contents of this and other. Guaranteed not to throw
     void swap(SkPath& other);
 
index f0f9449..426bb6d 100644 (file)
@@ -228,6 +228,25 @@ public:
         return -1;
     }
 
+    /**
+     * Copies up to max elements into dst. The number of items copied is
+     * capped by count - index. The actual number copied is returned.
+     */
+    int copyRange(T* dst, size_t index, int max) const {
+        SkASSERT(max >= 0);
+        SkASSERT(!max || dst);
+        if (index >= fCount) {
+            return 0;
+        }
+        int count = SkMin32(max, fCount - index);
+        memcpy(dst, fArray + index, sizeof(T) * count);
+        return count;
+    }
+
+    void copy(T* dst) const {
+        this->copyRange(0, fCount, dst);
+    }
+
     // routines to treat the array like a stack
     T*          push() { return this->append(); }
     void        push(const T& elem) { *this->append() = elem; }
index f3363cd..387b78b 100644 (file)
@@ -313,7 +313,7 @@ const SkPath* SkGlyphCache::findPath(const SkGlyph& glyph) {
             const_cast<SkGlyph&>(glyph).fPath = SkNEW(SkPath);
             fScalerContext->getPath(glyph, glyph.fPath);
             fMemoryUsed += sizeof(SkPath) +
-                    glyph.fPath->getPoints(NULL, 0x7FFFFFFF) * sizeof(SkPoint);
+                    glyph.fPath->countPoints() * sizeof(SkPoint);
         }
     }
     return glyph.fPath;
index 34b0ac9..4dab604 100644 (file)
@@ -390,14 +390,13 @@ bool SkPath::isRect(SkRect* rect) const {
     return result;
 }
 
-int SkPath::getPoints(SkPoint copy[], int max) const {
+int SkPath::getPoints(SkPoint dst[], int max) const {
     SkDEBUGCODE(this->validate();)
 
     SkASSERT(max >= 0);
+    SkASSERT(!max || dst);
     int count = fPts.count();
-    if (copy && max > 0 && count > 0) {
-        memcpy(copy, fPts.begin(), sizeof(SkPoint) * SkMin32(max, count));
-    }
+    fPts.copyRange(dst, 0, max);
     return count;
 }
 
@@ -408,6 +407,15 @@ SkPoint SkPath::getPoint(int index) const {
     return SkPoint::Make(0, 0);
 }
 
+int SkPath::getVerbs(uint8_t dst[], int max) const {
+    SkDEBUGCODE(this->validate();)
+
+    SkASSERT(max >= 0);
+    SkASSERT(!max || dst);
+    fVerbs.copyRange(dst, 0, max);
+    return fVerbs.count();
+}
+
 bool SkPath::getLastPt(SkPoint* lastPt) const {
     SkDEBUGCODE(this->validate();)
 
index 9d9903f..21f78bf 100644 (file)
@@ -756,16 +756,28 @@ static void test_zero_length_paths(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
     bounds.set(0, 0, 0, 0);
     REPORTER_ASSERT(reporter, bounds == p.getBounds());
+    {
+    uint8_t verbs[1];
+    REPORTER_ASSERT(reporter, SK_ARRAY_COUNT(verbs) == p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+    }
 
     // MoveTo-MoveTo case
     p.moveTo(SK_Scalar1*2, SK_Scalar1);
     REPORTER_ASSERT(reporter, !p.isEmpty());
     REPORTER_ASSERT(reporter, 2 == p.countPoints());
+    REPORTER_ASSERT(reporter, 2 == p.countVerbs());
     p.getLastPt(&pt);
     REPORTER_ASSERT(reporter, pt.fX == SK_Scalar1*2);
     REPORTER_ASSERT(reporter, pt.fY == SK_Scalar1);
     bounds.set(SK_Scalar1, SK_Scalar1, 2*SK_Scalar1, SK_Scalar1);
     REPORTER_ASSERT(reporter, bounds == p.getBounds()); 
+    {
+    uint8_t verbs[2];
+    REPORTER_ASSERT(reporter, SK_ARRAY_COUNT(verbs) == p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[1]);
+    }
 
     // moveTo-close case
     p.reset();
@@ -774,7 +786,14 @@ static void test_zero_length_paths(skiatest::Reporter* reporter) {
     bounds.set(0, 0, 0, 0);
     REPORTER_ASSERT(reporter, !p.isEmpty());
     REPORTER_ASSERT(reporter, 1 == p.countPoints());
+    REPORTER_ASSERT(reporter, 2 == p.countVerbs());
     REPORTER_ASSERT(reporter, bounds == p.getBounds());
+    {
+    uint8_t verbs[2];
+    REPORTER_ASSERT(reporter, SK_ARRAY_COUNT(verbs) == p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kClose_Verb == verbs[1]);
+    }
 
     // moveTo-close-moveTo-close case
     p.moveTo(SK_Scalar1*2, SK_Scalar1);
@@ -783,6 +802,14 @@ static void test_zero_length_paths(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, !p.isEmpty());
     REPORTER_ASSERT(reporter, 2 == p.countPoints());
     REPORTER_ASSERT(reporter, bounds == p.getBounds());
+    {
+    uint8_t verbs[4];
+    REPORTER_ASSERT(reporter, SK_ARRAY_COUNT(verbs) == p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kClose_Verb == verbs[1]);
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kClose_Verb == verbs[1]);
+    }
 
     // moveTo-line case
     p.reset();
@@ -792,6 +819,12 @@ static void test_zero_length_paths(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, !p.isEmpty());
     REPORTER_ASSERT(reporter, 2 == p.countPoints());
     REPORTER_ASSERT(reporter, bounds == p.getBounds());
+    {
+    uint8_t verbs[2];
+    REPORTER_ASSERT(reporter, SK_ARRAY_COUNT(verbs) == p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[1]);
+    }
 
     // moveTo-lineTo-moveTo-lineTo case
     p.moveTo(SK_Scalar1*2, SK_Scalar1);
@@ -800,6 +833,14 @@ static void test_zero_length_paths(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, !p.isEmpty());
     REPORTER_ASSERT(reporter, 4 == p.countPoints());
     REPORTER_ASSERT(reporter, bounds == p.getBounds());
+    {
+    uint8_t verbs[4];
+    REPORTER_ASSERT(reporter, SK_ARRAY_COUNT(verbs) == p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[1]);
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[2]);
+    REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[3]);
+    }
 
     // moveTo-line-close case
     p.reset();
@@ -810,6 +851,13 @@ static void test_zero_length_paths(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, !p.isEmpty());
     REPORTER_ASSERT(reporter, 2 == p.countPoints());
     REPORTER_ASSERT(reporter, bounds == p.getBounds());
+    {
+    uint8_t verbs[3];
+    REPORTER_ASSERT(reporter, SK_ARRAY_COUNT(verbs) == p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[1]);
+    REPORTER_ASSERT(reporter, SkPath::kClose_Verb == verbs[2]);
+    }
 
     // moveTo-line-close-moveTo-line-close case
     p.moveTo(SK_Scalar1*2, SK_Scalar1);
@@ -819,6 +867,16 @@ static void test_zero_length_paths(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, !p.isEmpty());
     REPORTER_ASSERT(reporter, 4 == p.countPoints());
     REPORTER_ASSERT(reporter, bounds == p.getBounds());
+    {
+    uint8_t verbs[6];
+    REPORTER_ASSERT(reporter, SK_ARRAY_COUNT(verbs) == p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[1]);
+    REPORTER_ASSERT(reporter, SkPath::kClose_Verb == verbs[2]);
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[3]);
+    REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[4]);
+    REPORTER_ASSERT(reporter, SkPath::kClose_Verb == verbs[5]);
+    }
 
     // moveTo-quadTo case
     p.reset();
@@ -828,12 +886,26 @@ static void test_zero_length_paths(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, !p.isEmpty());
     REPORTER_ASSERT(reporter, 3 == p.countPoints());
     REPORTER_ASSERT(reporter, bounds == p.getBounds());
+    {
+    uint8_t verbs[2];
+    REPORTER_ASSERT(reporter, SK_ARRAY_COUNT(verbs) == p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kQuad_Verb == verbs[1]);
+    }
 
     // moveTo-quadTo-close case
     p.close();
     REPORTER_ASSERT(reporter, !p.isEmpty());
     REPORTER_ASSERT(reporter, 3 == p.countPoints());
+    REPORTER_ASSERT(reporter, 3 == p.countVerbs());
     REPORTER_ASSERT(reporter, bounds == p.getBounds());
+    {
+    uint8_t verbs[3];
+    REPORTER_ASSERT(reporter, SK_ARRAY_COUNT(verbs) == p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kQuad_Verb == verbs[1]);
+    REPORTER_ASSERT(reporter, SkPath::kClose_Verb == verbs[2]);
+    }
 
     // moveTo-quadTo-moveTo-quadTo case
     p.reset();
@@ -845,6 +917,14 @@ static void test_zero_length_paths(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, !p.isEmpty());
     REPORTER_ASSERT(reporter, 6 == p.countPoints());
     REPORTER_ASSERT(reporter, bounds == p.getBounds());
+    {
+    uint8_t verbs[4];
+    REPORTER_ASSERT(reporter, SK_ARRAY_COUNT(verbs) == p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kQuad_Verb == verbs[1]);
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kQuad_Verb == verbs[1]);
+    }
 
     // moveTo-cubicTo case
     p.reset();
@@ -856,14 +936,27 @@ static void test_zero_length_paths(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, !p.isEmpty());
     REPORTER_ASSERT(reporter, 4 == p.countPoints());
     REPORTER_ASSERT(reporter, bounds == p.getBounds());
+    {
+    uint8_t verbs[2];
+    REPORTER_ASSERT(reporter, SK_ARRAY_COUNT(verbs) == p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb  == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kCubic_Verb == verbs[1]);
+    }
 
-    // moveTo-quadTo-close case
+    // moveTo-cubicTo-close case
     p.close();
     REPORTER_ASSERT(reporter, !p.isEmpty());
     REPORTER_ASSERT(reporter, 4 == p.countPoints());
     REPORTER_ASSERT(reporter, bounds == p.getBounds());
+    {
+    uint8_t verbs[3];
+    REPORTER_ASSERT(reporter, SK_ARRAY_COUNT(verbs) == p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb   == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kCubic_Verb  == verbs[1]);
+    REPORTER_ASSERT(reporter, SkPath::kClose_Verb  == verbs[2]);
+    }
 
-    // moveTo-quadTo-moveTo-quadTo case
+    // moveTo-cubicTo-moveTo-cubicTo case
     p.reset();
     p.moveTo(SK_Scalar1, SK_Scalar1);
     p.cubicTo(SK_Scalar1, SK_Scalar1,
@@ -877,6 +970,14 @@ static void test_zero_length_paths(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, !p.isEmpty());
     REPORTER_ASSERT(reporter, 8 == p.countPoints());
     REPORTER_ASSERT(reporter, bounds == p.getBounds());
+    {
+    uint8_t verbs[4];
+    REPORTER_ASSERT(reporter, SK_ARRAY_COUNT(verbs) == p.getVerbs(verbs, SK_ARRAY_COUNT(verbs)));
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb  == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kCubic_Verb  == verbs[1]);
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[2]);
+    REPORTER_ASSERT(reporter, SkPath::kCubic_Verb == verbs[3]);
+    }
 }
 
 struct SegmentInfo {
@@ -1391,6 +1492,7 @@ static void TestPath(skiatest::Reporter* reporter) {
 
     REPORTER_ASSERT(reporter, p.isEmpty());
     REPORTER_ASSERT(reporter, 0 == p.countPoints());
+    REPORTER_ASSERT(reporter, 0 == p.countVerbs());
     REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
     REPORTER_ASSERT(reporter, p.isConvex());
     REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
@@ -1426,11 +1528,21 @@ static void TestPath(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, p != p2);
     REPORTER_ASSERT(reporter, !(p == p2));
 
-    // does getPoints return the right result
-    REPORTER_ASSERT(reporter, p.getPoints(NULL, 5) == 4);
+    // do getPoints and getVerbs return the right result
+    REPORTER_ASSERT(reporter, p.getPoints(NULL, 0) == 4);
+    REPORTER_ASSERT(reporter, p.getVerbs(NULL, 0) == 5);
     SkPoint pts[4];
     int count = p.getPoints(pts, 4);
     REPORTER_ASSERT(reporter, count == 4);
+    uint8_t verbs[6];
+    verbs[5] = 0xff;
+    p.getVerbs(verbs, 5);
+    REPORTER_ASSERT(reporter, SkPath::kMove_Verb == verbs[0]);
+    REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[1]);
+    REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[2]);
+    REPORTER_ASSERT(reporter, SkPath::kLine_Verb == verbs[3]);
+    REPORTER_ASSERT(reporter, SkPath::kClose_Verb == verbs[4]);
+    REPORTER_ASSERT(reporter, 0xff == verbs[5]);
     bounds2.set(pts, 4);
     REPORTER_ASSERT(reporter, bounds == bounds2);