From 744fabad474e3e111e7cbd8609cf7e209df17f32 Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Tue, 29 May 2012 19:54:52 +0000 Subject: [PATCH] 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 --- include/core/SkPath.h | 13 ++++++++++ src/core/SkPath.cpp | 38 ++++++++++++++++++++++++++++ tests/PathTest.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 118 insertions(+), 1 deletion(-) 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 @@ public: 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 @@ void SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, 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 @@ void TestPath(skiatest::Reporter* reporter) { test_raw_iter(reporter); test_circle(reporter); test_oval(reporter); - test_strokerec(reporter); + test_addPoly(reporter); } #include "TestClassDef.h" -- 2.7.4