this->setLastPt(p.fX, p.fY);
}
+ enum SegmentMask {
+ kLine_SegmentMask = 1 << 0,
+ kQuad_SegmentMask = 1 << 1,
+ kCubic_SegmentMask = 1 << 2
+ };
+
+ /**
+ * Returns a mask, where each bit corresponding to a SegmentMask is
+ * set if the path contains 1 or more segments of that type.
+ * Returns 0 for an empty path (no segments).
+ */
+ uint32_t getSegmentMasks() const { return fSegmentMask; }
+
enum Verb {
kMove_Verb, //!< iter.next returns 1 point
kLine_Verb, //!< iter.next returns 2 points
SkTDArray<SkPoint> fPts;
SkTDArray<uint8_t> fVerbs;
mutable SkRect fBounds;
- mutable uint8_t fBoundsIsDirty;
uint8_t fFillType;
+ uint8_t fSegmentMask;
+ mutable uint8_t fBoundsIsDirty;
mutable uint8_t fConvexity;
#ifdef ANDROID
uint32_t fGenerationID;
SkPath::SkPath() : fBoundsIsDirty(true), fFillType(kWinding_FillType) {
fConvexity = kUnknown_Convexity;
+ fSegmentMask = 0;
#ifdef ANDROID
fGenerationID = 0;
#endif
fFillType = src.fFillType;
fBoundsIsDirty = src.fBoundsIsDirty;
fConvexity = src.fConvexity;
+ fSegmentMask = src.fSegmentMask;
GEN_ID_INC;
}
SkDEBUGCODE(this->validate();)
bool operator==(const SkPath& a, const SkPath& b) {
// note: don't need to look at isConvex or bounds, since just comparing the
// raw data is sufficient.
+
+ // We explicitly check fSegmentMask as a quick-reject. We could skip it,
+ // since it is only a cache of info in the fVerbs, but its a fast way to
+ // notice a difference
+
return &a == &b ||
- (a.fFillType == b.fFillType && a.fVerbs == b.fVerbs && a.fPts == b.fPts);
+ (a.fFillType == b.fFillType && a.fSegmentMask == b.fSegmentMask &&
+ a.fVerbs == b.fVerbs && a.fPts == b.fPts);
}
void SkPath::swap(SkPath& other) {
SkTSwap<uint8_t>(fFillType, other.fFillType);
SkTSwap<uint8_t>(fBoundsIsDirty, other.fBoundsIsDirty);
SkTSwap<uint8_t>(fConvexity, other.fConvexity);
+ SkTSwap<uint8_t>(fSegmentMask, other.fSegmentMask);
GEN_ID_INC;
}
}
GEN_ID_INC;
fBoundsIsDirty = true;
fConvexity = kUnknown_Convexity;
+ fSegmentMask = 0;
}
void SkPath::rewind() {
GEN_ID_INC;
fBoundsIsDirty = true;
fConvexity = kUnknown_Convexity;
+ fSegmentMask = 0;
}
bool SkPath::isEmpty() const {
}
fPts.append()->set(x, y);
*fVerbs.append() = kLine_Verb;
+ fSegmentMask |= kLine_SegmentMask;
GEN_ID_INC;
DIRTY_AFTER_EDIT;
pts[0].set(x1, y1);
pts[1].set(x2, y2);
*fVerbs.append() = kQuad_Verb;
+ fSegmentMask |= kQuad_SegmentMask;
GEN_ID_INC;
DIRTY_AFTER_EDIT;
pts[1].set(x2, y2);
pts[2].set(x3, y3);
*fVerbs.append() = kCubic_Verb;
+ fSegmentMask |= kCubic_SegmentMask;
GEN_ID_INC;
DIRTY_AFTER_EDIT;
fBounds.contains(bounds);
}
}
+
+ uint32_t mask = 0;
+ for (int i = 0; i < fVerbs.count(); i++) {
+ switch (fVerbs[i]) {
+ case kLine_Verb:
+ mask |= kLine_SegmentMask;
+ break;
+ case kQuad_Verb:
+ mask |= kQuad_SegmentMask;
+ break;
+ case kCubic_Verb:
+ mask |= kCubic_SegmentMask;
+ }
+ }
+ SkASSERT(mask == fSegmentMask);
}
#endif
REPORTER_ASSERT(reporter, fail ^ path1.isRect(0));
}
+#define kCurveSegmentMask (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)
+
void TestPath(skiatest::Reporter* reporter);
void TestPath(skiatest::Reporter* reporter) {
{
SkRect bounds, bounds2;
REPORTER_ASSERT(reporter, p.isEmpty());
+ REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
REPORTER_ASSERT(reporter, p.isConvex());
REPORTER_ASSERT(reporter, p.getFillType() == SkPath::kWinding_FillType);
REPORTER_ASSERT(reporter, !p.isInverseFillType());
p.addRoundRect(bounds, SK_Scalar1, SK_Scalar1);
check_convex_bounds(reporter, p, bounds);
+ // we have quads or cubics
+ REPORTER_ASSERT(reporter, p.getSegmentMasks() & kCurveSegmentMask);
p.reset();
+ REPORTER_ASSERT(reporter, 0 == p.getSegmentMasks());
+
p.addOval(bounds);
check_convex_bounds(reporter, p, bounds);
p.reset();
p.addRect(bounds);
check_convex_bounds(reporter, p, bounds);
+ // we have only lines
+ REPORTER_ASSERT(reporter, SkPath::kLine_SegmentMask == p.getSegmentMasks());
REPORTER_ASSERT(reporter, p != p2);
REPORTER_ASSERT(reporter, !(p == p2));
test_convexity(reporter);
test_convexity2(reporter);
test_close(reporter);
+
+ p.reset();
+ p.moveTo(0, 0);
+ p.quadTo(100, 100, 200, 200);
+ REPORTER_ASSERT(reporter, SkPath::kQuad_SegmentMask == p.getSegmentMasks());
+ p.cubicTo(100, 100, 200, 200, 300, 300);
+ REPORTER_ASSERT(reporter, kCurveSegmentMask == p.getSegmentMasks());
+ p.reset();
+ p.moveTo(0, 0);
+ p.cubicTo(100, 100, 200, 200, 300, 300);
+ REPORTER_ASSERT(reporter, SkPath::kCubic_SegmentMask == p.getSegmentMasks());
}
#include "TestClassDef.h"