Revert "Reland "Revert "Add arcs as a specialized geometry to GrShape."""
This reverts commit 580aee2fa4a57bf8208498fbc23acea04e16e092.
Bug: skia:7794
Change-Id: I9c2b923859c826dff58c22c529dc4e2ab4d0f186
Reviewed-on: https://skia-review.googlesource.com/124042
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index 3e4f990..497037a 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -1304,6 +1304,25 @@
SkPoint singlePt;
+ // Adds a move-to to 'pt' if forceMoveTo is true. Otherwise a lineTo unless we're sufficiently
+ // close to 'pt' currently. This prevents spurious lineTos when adding a series of contiguous
+ // arcs from the same oval.
+ auto addPt = [&forceMoveTo, this](const SkPoint& pt) {
+ SkPoint lastPt;
+#ifdef SK_DISABLE_ARC_TO_LINE_TO_CHECK
+ static constexpr bool kSkipLineToCheck = true;
+#else
+ static constexpr bool kSkipLineToCheck = false;
+#endif
+ if (forceMoveTo) {
+ this->moveTo(pt);
+ } else if (kSkipLineToCheck || !this->getLastPt(&lastPt) ||
+ !SkScalarNearlyEqual(lastPt.fX, pt.fX) ||
+ !SkScalarNearlyEqual(lastPt.fY, pt.fY)) {
+ this->lineTo(pt);
+ }
+ };
+
// At this point, we know that the arc is not a lone point, but startV == stopV
// indicates that the sweepAngle is too small such that angles_to_unit_vectors
// cannot handle it.
@@ -1318,7 +1337,7 @@
// make sin(endAngle) to be 0 which will then draw a dot.
singlePt.set(oval.centerX() + radiusX * sk_float_cos(endAngle),
oval.centerY() + radiusY * sk_float_sin(endAngle));
- forceMoveTo ? this->moveTo(singlePt) : this->lineTo(singlePt);
+ addPt(singlePt);
return;
}
@@ -1327,12 +1346,12 @@
if (count) {
this->incReserve(count * 2 + 1);
const SkPoint& pt = conics[0].fPts[0];
- forceMoveTo ? this->moveTo(pt) : this->lineTo(pt);
+ addPt(pt);
for (int i = 0; i < count; ++i) {
this->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW);
}
} else {
- forceMoveTo ? this->moveTo(singlePt) : this->lineTo(singlePt);
+ addPt(singlePt);
}
}
@@ -3343,6 +3362,20 @@
return true;
}
+bool SkPathPriv::DrawArcIsConvex(SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect) {
+ if (isFillNoPathEffect && SkScalarAbs(sweepAngle) >= 360.f) {
+ // This gets converted to an oval.
+ return true;
+ }
+ if (useCenter) {
+ // This is a pie wedge. It's convex if the angle is <= 180.
+ return SkScalarAbs(sweepAngle) <= 180.f;
+ }
+ // When the angle exceeds 360 this wraps back on top of itself. Otherwise it is a circle clipped
+ // to a secant, i.e. convex.
+ return SkScalarAbs(sweepAngle) <= 360.f;
+}
+
void SkPathPriv::CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar startAngle,
SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect) {
SkASSERT(!oval.isEmpty());
@@ -3353,11 +3386,15 @@
path->setFillType(SkPath::kWinding_FillType);
if (isFillNoPathEffect && SkScalarAbs(sweepAngle) >= 360.f) {
path->addOval(oval);
+ SkASSERT(path->isConvex() && DrawArcIsConvex(sweepAngle, false, isFillNoPathEffect));
return;
}
if (useCenter) {
path->moveTo(oval.centerX(), oval.centerY());
}
+ auto firstDir =
+ sweepAngle > 0 ? SkPathPriv::kCW_FirstDirection : SkPathPriv::kCCW_FirstDirection;
+ bool convex = DrawArcIsConvex(sweepAngle, useCenter, isFillNoPathEffect);
// Arc to mods at 360 and drawArc is not supposed to.
bool forceMoveTo = !useCenter;
while (sweepAngle <= -360.f) {
@@ -3380,6 +3417,8 @@
if (useCenter) {
path->close();
}
+ path->setConvexity(convex ? SkPath::kConvex_Convexity : SkPath::kConcave_Convexity);
+ path->fFirstDirection.store(firstDir);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkPathPriv.h b/src/core/SkPathPriv.h
index ede79f6..3ee1f83 100644
--- a/src/core/SkPathPriv.h
+++ b/src/core/SkPathPriv.h
@@ -106,6 +106,12 @@
SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect);
/**
+ * Determines whether an arc produced by CreateDrawArcPath will be convex. Assumes a non-empty
+ * oval.
+ */
+ static bool DrawArcIsConvex(SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect);
+
+ /**
* Returns a C++11-iterable object that traverses a path's verbs in order. e.g:
*
* for (SkPath::Verb verb : SkPathPriv::Verbs(path)) {