addPoly() entry-point, to quickly add MoveTo+N*LineTo (useful in dashing)
Review URL: https://codereview.appspot.com/6256063
git-svn-id: http://skia.googlecode.com/svn/trunk@4061 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkPath.h b/include/core/SkPath.h
index 03108df..e509346 100644
--- a/include/core/SkPath.h
+++ b/include/core/SkPath.h
@@ -559,6 +559,19 @@
void addRoundRect(const SkRect& rect, const SkScalar radii[],
Direction dir = kCW_Direction);
+ /**
+ * Add a new contour made of just lines. This is just a fast version of
+ * the following:
+ * this->moveTo(pts[0]);
+ * for (int i = 1; i < count; ++i) {
+ * this->lineTo(pts[i]);
+ * }
+ * if (close) {
+ * this->close();
+ * }
+ */
+ void addPoly(const SkPoint pts[], int count, bool close);
+
/** Add a copy of src to the path, offset by (dx,dy)
@param src The path to add as a new contour
@param dx The amount to translate the path in X as it is added
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index ee6a171..5f63651 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -12,6 +12,11 @@
#include "SkWriter32.h"
#include "SkMath.h"
+// This value is just made-up for now. When count is 4, calling memset was much
+// slower than just writing the loop. This seems odd, and hopefully in the
+// future this we appear to have been a fluke...
+#define MIN_COUNT_FOR_MEMSET_TO_BE_FAST 16
+
////////////////////////////////////////////////////////////////////////////
/**
@@ -627,6 +632,39 @@
this->close();
}
+void SkPath::addPoly(const SkPoint pts[], int count, bool close) {
+ SkDEBUGCODE(this->validate();)
+ if (count <= 0) {
+ return;
+ }
+
+ fLastMoveToIndex = fPts.count();
+ fPts.append(count, pts);
+
+ // +close makes room for the extra kClose_Verb
+ uint8_t* vb = fVerbs.append(count + close);
+ vb[0] = kMove_Verb;
+
+ if (count > 1) {
+ // cast to unsigned, so if MIN_COUNT_FOR_MEMSET_TO_BE_FAST is defined to
+ // be 0, the compiler will remove the test/branch entirely.
+ if ((unsigned)count >= MIN_COUNT_FOR_MEMSET_TO_BE_FAST) {
+ memset(&vb[1], kLine_Verb, count - 1);
+ } else {
+ for (int i = 1; i < count; ++i) {
+ vb[i] = kLine_Verb;
+ }
+ }
+ fSegmentMask |= kLine_SegmentMask;
+ }
+ if (close) {
+ vb[count] = kClose_Verb;
+ }
+
+ GEN_ID_INC;
+ DIRTY_AFTER_EDIT;
+}
+
#define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3)
void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp
index fae2d4b..7b8f869 100644
--- a/tests/PathTest.cpp
+++ b/tests/PathTest.cpp
@@ -16,6 +16,72 @@
#include "SkSize.h"
#include "SkWriter32.h"
+// assert that we always
+// start with a moveTo
+// only have 1 moveTo
+// only have Lines after that
+// end with a single close
+// only have (at most) 1 close
+//
+static void test_poly(skiatest::Reporter* reporter, const SkPath& path,
+ const SkPoint srcPts[], int count, bool expectClose) {
+ SkPath::RawIter iter(path);
+ SkPoint pts[4];
+ SkPath::Verb verb;
+
+ bool firstTime = true;
+ bool foundClose = false;
+ for (;;) {
+ switch (iter.next(pts)) {
+ case SkPath::kMove_Verb:
+ REPORTER_ASSERT(reporter, firstTime);
+ REPORTER_ASSERT(reporter, pts[0] == srcPts[0]);
+ srcPts++;
+ firstTime = false;
+ break;
+ case SkPath::kLine_Verb:
+ REPORTER_ASSERT(reporter, !firstTime);
+ REPORTER_ASSERT(reporter, pts[1] == srcPts[0]);
+ srcPts++;
+ break;
+ case SkPath::kQuad_Verb:
+ REPORTER_ASSERT(reporter, !"unexpected quad verb");
+ break;
+ case SkPath::kCubic_Verb:
+ REPORTER_ASSERT(reporter, !"unexpected cubic verb");
+ break;
+ case SkPath::kClose_Verb:
+ REPORTER_ASSERT(reporter, !firstTime);
+ REPORTER_ASSERT(reporter, !foundClose);
+ REPORTER_ASSERT(reporter, expectClose);
+ foundClose = true;
+ break;
+ case SkPath::kDone_Verb:
+ goto DONE;
+ }
+ }
+DONE:
+ REPORTER_ASSERT(reporter, foundClose == expectClose);
+}
+
+static void test_addPoly(skiatest::Reporter* reporter) {
+ SkPoint pts[32];
+ SkRandom rand;
+
+ for (size_t i = 0; i < SK_ARRAY_COUNT(pts); ++i) {
+ pts[i].fX = rand.nextSScalar1();
+ pts[i].fY = rand.nextSScalar1();
+ }
+
+ for (int doClose = 0; doClose <= 1; ++doClose) {
+ for (size_t count = 1; count <= SK_ARRAY_COUNT(pts); ++count) {
+ SkPath path;
+ path.addPoly(pts, count, SkToBool(doClose));
+ test_poly(reporter, path, pts, count, SkToBool(doClose));
+ }
+ }
+}
+
static void test_strokerec(skiatest::Reporter* reporter) {
SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
REPORTER_ASSERT(reporter, rec.isFillStyle());
@@ -1398,8 +1464,8 @@
test_raw_iter(reporter);
test_circle(reporter);
test_oval(reporter);
-
test_strokerec(reporter);
+ test_addPoly(reporter);
}
#include "TestClassDef.h"