Add asADash entry point into SkPathEffect to allow extracting Dash info from PathEffects
authorcommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 22 Apr 2014 15:21:18 +0000 (15:21 +0000)
committercommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 22 Apr 2014 15:21:18 +0000 (15:21 +0000)
BUG=skia:
R=bsalomon@google.com, reed@google.com

Author: egdaniel@google.com

Review URL: https://codereview.chromium.org/212103010

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

gyp/tests.gypi
include/core/SkPathEffect.h
include/core/SkPicture.h
include/effects/SkDashPathEffect.h
src/core/SkPathEffect.cpp
src/effects/SkDashPathEffect.cpp
tests/AsADashTest.cpp [new file with mode: 0644]

index e6c6bb0..f27b144 100644 (file)
@@ -34,6 +34,7 @@
     '../tests/ARGBImageEncoderTest.cpp',
     '../tests/AndroidPaintTest.cpp',
     '../tests/AnnotationTest.cpp',
+    '../tests/AsADashTest.cpp',
     '../tests/AtomicTest.cpp',
     '../tests/BBoxHierarchyTest.cpp',
     '../tests/BitSetTest.cpp',
index 86ccf86..638287d 100644 (file)
@@ -104,6 +104,33 @@ public:
                           const SkStrokeRec&, const SkMatrix&,
                           const SkRect* cullR) const;
 
+    /**
+     *  If the PathEffect can be represented as a dash pattern, asADash will return kDash_DashType
+     *  and None otherwise. If a non NULL info is passed in, the various DashInfo will be filled
+     *  in if the PathEffect can be a dash pattern. If passed in info has an fCount equal or
+     *  greater to that of the effect, it will memcpy the values of the dash intervals into the
+     *  info. Thus the general approach will be call asADash once with default info to get DashType
+     *  and fCount. If effect can be represented as a dash pattern, allocate space for the intervals
+     *  in info, then call asADash again with the same info and the intervals will get copied in.
+     */
+
+    enum DashType {
+        kNone_DashType, //!< ignores the info parameter
+        kDash_DashType, //!< fills in all of the info parameter
+    };
+
+    struct DashInfo {
+        DashInfo() : fIntervals(NULL), fCount(0), fPhase(0) {}
+
+        SkScalar*   fIntervals;         //!< Length of on/off intervals for dashed lines
+                                        //   Even values represent ons, and odds offs
+        int32_t     fCount;             //!< Number of intervals in the dash. Should be even number
+        SkScalar    fPhase;             //!< Offset into the dashed interval pattern
+                                        //   mod the sum of all intervals
+    };
+
+    virtual DashType asADash(DashInfo* info) const;
+
     SK_DEFINE_FLATTENABLE_TYPE(SkPathEffect)
 
 protected:
index bf9ec4f..996d857 100644 (file)
@@ -324,13 +324,14 @@ protected:
     // V22: SK_PICT_FACTORY_TAG's size is now the chunk size in bytes
     // V23: SkPaint::FilterLevel became a real enum
     // V24: SkTwoPointConicalGradient now has fFlipped flag for gradient flipping
+    // V25: SkDashPathEffect now only writes phase and interval array when flattening
 
     // Note: If the picture version needs to be increased then please follow the
     // steps to generate new SKPs in (only accessible to Googlers): http://goo.gl/qATVcw
 
     // Only SKPs within the min/current picture version range (inclusive) can be read.
     static const uint32_t MIN_PICTURE_VERSION = 19;
-    static const uint32_t CURRENT_PICTURE_VERSION = 24;
+    static const uint32_t CURRENT_PICTURE_VERSION = 25;
 
     mutable uint32_t      fUniqueID;
 
index 41f8f5a..f69e905 100644 (file)
@@ -49,6 +49,8 @@ public:
                           const SkStrokeRec&, const SkMatrix&,
                           const SkRect*) const SK_OVERRIDE;
 
+    virtual DashType asADash(DashInfo* info) const SK_OVERRIDE;
+
     virtual Factory getFactory() const SK_OVERRIDE;
 
     static SkFlattenable* CreateProc(SkReadBuffer&);
@@ -63,8 +65,11 @@ public:
     SkDashPathEffect(const SkScalar intervals[], int count, SkScalar phase);
 
 private:
+    void setInternalMembers(SkScalar phase);
+
     SkScalar*   fIntervals;
     int32_t     fCount;
+    SkScalar    fPhase;
     // computed from phase
     SkScalar    fInitialDashLength;
     int32_t     fInitialDashIndex;
index e181320..01d5d6f 100644 (file)
@@ -22,6 +22,10 @@ bool SkPathEffect::asPoints(PointData* results, const SkPath& src,
     return false;
 }
 
+SkPathEffect::DashType SkPathEffect::asADash(DashInfo* info) const {
+    return kNone_DashType;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 SkPairPathEffect::SkPairPathEffect(SkPathEffect* pe0, SkPathEffect* pe1)
index 15276b6..6f132e0 100644 (file)
@@ -34,19 +34,10 @@ static SkScalar FindFirstInterval(const SkScalar intervals[], SkScalar phase,
     return intervals[0];
 }
 
-SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count,
-                                   SkScalar phase) {
-    SkASSERT(intervals);
-    SkASSERT(count > 1 && SkAlign2(count) == count);
-
-    fIntervals = (SkScalar*)sk_malloc_throw(sizeof(SkScalar) * count);
-    fCount = count;
-
+void SkDashPathEffect::setInternalMembers(SkScalar phase) {
     SkScalar len = 0;
-    for (int i = 0; i < count; i++) {
-        SkASSERT(intervals[i] >= 0);
-        fIntervals[i] = intervals[i];
-        len += intervals[i];
+    for (int i = 0; i < fCount; i++) {
+        len += fIntervals[i];
     }
     fIntervalLength = len;
 
@@ -74,8 +65,10 @@ SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count,
         }
         SkASSERT(phase >= 0 && phase < len);
 
-        fInitialDashLength = FindFirstInterval(intervals, phase,
-                                               &fInitialDashIndex, count);
+        fPhase = phase;
+
+        fInitialDashLength = FindFirstInterval(fIntervals, fPhase,
+                                               &fInitialDashIndex, fCount);
 
         SkASSERT(fInitialDashLength >= 0);
         SkASSERT(fInitialDashIndex >= 0 && fInitialDashIndex < fCount);
@@ -84,6 +77,21 @@ SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count,
     }
 }
 
+SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count,
+                                   SkScalar phase) {
+    SkASSERT(intervals);
+    SkASSERT(count > 1 && SkAlign2(count) == count);
+
+    fIntervals = (SkScalar*)sk_malloc_throw(sizeof(SkScalar) * count);
+    fCount = count;
+    for (int i = 0; i < count; i++) {
+        SkASSERT(intervals[i] >= 0);
+        fIntervals[i] = intervals[i];
+    }
+
+    this->setInternalMembers(phase);
+}
+
 SkDashPathEffect::~SkDashPathEffect() {
     sk_free(fIntervals);
 }
@@ -510,17 +518,24 @@ bool SkDashPathEffect::asPoints(PointData* results,
     return true;
 }
 
+SkPathEffect::DashType SkDashPathEffect::asADash(DashInfo* info) const {
+    if (info) {
+        if (info->fCount >= fCount && NULL != info->fIntervals) {
+            memcpy(info->fIntervals, fIntervals, fCount * sizeof(SkScalar));
+        }
+        info->fCount = fCount;
+        info->fPhase = fPhase;
+    }
+    return kDash_DashType;
+}
+
 SkFlattenable::Factory SkDashPathEffect::getFactory() const {
     return CreateProc;
 }
 
 void SkDashPathEffect::flatten(SkWriteBuffer& buffer) const {
     this->INHERITED::flatten(buffer);
-    buffer.writeInt(fInitialDashIndex);
-    buffer.writeScalar(fInitialDashLength);
-    buffer.writeScalar(fIntervalLength);
-    // Dummy write to stay compatible with old skps. Write will be removed in follow up patch.
-    buffer.writeBool(false);
+    buffer.writeScalar(fPhase);
     buffer.writeScalarArray(fIntervals, fCount);
 }
 
@@ -529,10 +544,15 @@ SkFlattenable* SkDashPathEffect::CreateProc(SkReadBuffer& buffer) {
 }
 
 SkDashPathEffect::SkDashPathEffect(SkReadBuffer& buffer) : INHERITED(buffer) {
-    fInitialDashIndex = buffer.readInt();
-    fInitialDashLength = buffer.readScalar();
-    fIntervalLength = buffer.readScalar();
-    buffer.readBool(); // dummy read to stay compatible with old skps
+    bool useOldPic = buffer.pictureVersion() < 25 && 0 != buffer.pictureVersion();
+    if (useOldPic) {
+        fInitialDashIndex = buffer.readInt();
+        fInitialDashLength = buffer.readScalar();
+        fIntervalLength = buffer.readScalar();
+        buffer.readBool(); // Dummy for old ScalarToFit field
+    } else {
+        fPhase = buffer.readScalar();
+    }
 
     fCount = buffer.getArrayCount();
     size_t allocSize = sizeof(SkScalar) * fCount;
@@ -542,4 +562,14 @@ SkDashPathEffect::SkDashPathEffect(SkReadBuffer& buffer) : INHERITED(buffer) {
     } else {
         fIntervals = NULL;
     }
+
+    if (useOldPic) {
+        fPhase = 0;
+        for (int i = 0; i < fInitialDashIndex; ++i) {
+            fPhase += fIntervals[i];
+        }
+        fPhase += fInitialDashLength;
+    } else {
+        this->setInternalMembers(fPhase);
+    }
 }
diff --git a/tests/AsADashTest.cpp b/tests/AsADashTest.cpp
new file mode 100644 (file)
index 0000000..47f1971
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "Test.h"
+
+#include "SkPathEffect.h"
+#include "SkDashPathEffect.h"
+#include "SkCornerPathEffect.h"
+
+DEF_TEST(AsADashTest_noneDash, reporter) {
+    SkAutoTUnref<SkCornerPathEffect> pe(SkCornerPathEffect::Create(1.0));
+    SkPathEffect::DashInfo info;
+
+    SkPathEffect::DashType dashType = pe->asADash(&info);
+    REPORTER_ASSERT(reporter, SkPathEffect::kNone_DashType == dashType);
+}
+
+DEF_TEST(AsADashTest_nullInfo, reporter) {
+    SkScalar inIntervals[] = { 4.0, 2.0, 1.0, 3.0 };
+    const SkScalar phase = 2.0;
+    SkAutoTUnref<SkDashPathEffect> pe(SkDashPathEffect::Create(inIntervals, 4, phase));
+
+    SkPathEffect::DashType dashType = pe->asADash(NULL);
+    REPORTER_ASSERT(reporter, SkPathEffect::kDash_DashType == dashType);
+}
+
+DEF_TEST(AsADashTest_usingDash, reporter) {
+    SkScalar inIntervals[] = { 4.0, 2.0, 1.0, 3.0 };
+    SkScalar totalIntSum = 10.0;
+    const SkScalar phase = 2.0;
+
+    SkAutoTUnref<SkDashPathEffect> pe(SkDashPathEffect::Create(inIntervals, 4, phase));
+
+    SkPathEffect::DashInfo info;
+
+    SkPathEffect::DashType dashType = pe->asADash(&info);
+    REPORTER_ASSERT(reporter, SkPathEffect::kDash_DashType == dashType);
+    REPORTER_ASSERT(reporter, 4 == info.fCount);
+    REPORTER_ASSERT(reporter, SkScalarMod(phase, totalIntSum) == info.fPhase);
+
+    // Since it is a kDash_DashType, allocate space for the intervals and recall asADash
+    SkAutoTArray<SkScalar> intervals(info.fCount);
+    info.fIntervals = intervals.get();
+    pe->asADash(&info);
+    REPORTER_ASSERT(reporter, inIntervals[0] == info.fIntervals[0]);
+    REPORTER_ASSERT(reporter, inIntervals[1] == info.fIntervals[1]);
+    REPORTER_ASSERT(reporter, inIntervals[2] == info.fIntervals[2]);
+    REPORTER_ASSERT(reporter, inIntervals[3] == info.fIntervals[3]);
+
+    // Make sure nothing else has changed on us
+    REPORTER_ASSERT(reporter, 4 == info.fCount);
+    REPORTER_ASSERT(reporter, SkScalarMod(phase, totalIntSum) == info.fPhase);
+}