Respecify SkCanvas::drawArc, consolidate conversion to SkPath, add GM for oddball drawArcs
Allows the arc to wind more than 360 degrees when useCenter is true, specs that nothing draws
if the oval is empty or the sweep angle is 0.
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2281653002
Review-Url: https://codereview.chromium.org/2281653002
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 0b14368..8f9a576 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -3098,11 +3098,10 @@
SkScalar sweepAngle, bool useCenter,
const SkPaint& paint) {
TRACE_EVENT0("disabled-by-default-skia", "SkCanvas::drawArc()");
- if (SkScalarAbs(sweepAngle) >= SkIntToScalar(360)) {
- this->drawOval(oval, paint);
- } else {
- this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
+ if (oval.isEmpty() || !sweepAngle) {
+ return;
}
+ this->onDrawArc(oval, startAngle, sweepAngle, useCenter, paint);
}
void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index a90076d..1f3bd61 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -16,6 +16,7 @@
#include "SkLatticeIter.h"
#include "SkMetaData.h"
#include "SkPatchUtils.h"
+#include "SkPathPriv.h"
#include "SkPathMeasure.h"
#include "SkRasterClip.h"
#include "SkRSXform.h"
@@ -74,16 +75,10 @@
void SkBaseDevice::drawArc(const SkDraw& draw, const SkRect& oval, SkScalar startAngle,
SkScalar sweepAngle, bool useCenter, const SkPaint& paint) {
- SkASSERT(SkScalarAbs(sweepAngle) >= 0.f && SkScalarAbs(sweepAngle) < 360.f);
SkPath path;
- if (useCenter) {
- path.moveTo(oval.centerX(), oval.centerY());
- }
- path.arcTo(oval, startAngle, sweepAngle, !useCenter);
- if (useCenter) {
- path.close();
- }
- path.setIsVolatile(true);
+ bool isFillNoPathEffect = SkPaint::kFill_Style == paint.getStyle() && !paint.getPathEffect();
+ SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter,
+ isFillNoPathEffect);
this->drawPath(draw, path, paint);
}
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index 64d3c0d..1fb3e11 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -3341,3 +3341,42 @@
}
return true;
}
+
+void SkPathPriv::CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar startAngle,
+ SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect) {
+ SkASSERT(!oval.isEmpty());
+ SkASSERT(sweepAngle);
+
+ path->reset();
+ path->setIsVolatile(true);
+ path->setFillType(SkPath::kWinding_FillType);
+ if (isFillNoPathEffect && SkScalarAbs(sweepAngle) >= 360.f) {
+ path->addOval(oval);
+ return;
+ }
+ if (useCenter) {
+ path->moveTo(oval.centerX(), oval.centerY());
+ }
+ // Arc to mods at 360 and drawArc is not supposed to.
+ bool forceMoveTo = !useCenter;
+ while (sweepAngle <= -360.f) {
+ path->arcTo(oval, startAngle, -180.f, forceMoveTo);
+ startAngle -= 180.f;
+ path->arcTo(oval, startAngle, -180.f, false);
+ startAngle -= 180.f;
+ forceMoveTo = false;
+ sweepAngle += 360.f;
+ }
+ while (sweepAngle >= 360.f) {
+ path->arcTo(oval, startAngle, 180.f, forceMoveTo);
+ startAngle += 180.f;
+ path->arcTo(oval, startAngle, 180.f, false);
+ startAngle += 180.f;
+ forceMoveTo = false;
+ sweepAngle -= 360.f;
+ }
+ path->arcTo(oval, startAngle, sweepAngle, forceMoveTo);
+ if (useCenter) {
+ path->close();
+ }
+}
diff --git a/src/core/SkPathPriv.h b/src/core/SkPathPriv.h
index 8689dee..60b0f2a 100644
--- a/src/core/SkPathPriv.h
+++ b/src/core/SkPathPriv.h
@@ -91,6 +91,13 @@
*/
static bool IsSimpleClosedRect(const SkPath& path, SkRect* rect, SkPath::Direction* direction,
unsigned* start);
+
+ /**
+ * Creates a path from arc params using the semantics of SkCanvas::drawArc. This function
+ * assumes empty ovals and zero sweeps have already been filtered out.
+ */
+ static void CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar startAngle,
+ SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect);
};
#endif
diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp
index 3b346b6..5bda884 100644
--- a/src/gpu/GrDrawContext.cpp
+++ b/src/gpu/GrDrawContext.cpp
@@ -1023,14 +1023,8 @@
}
}
SkPath path;
- path.setIsVolatile(true);
- if (useCenter) {
- path.moveTo(oval.centerX(), oval.centerY());
- }
- path.arcTo(oval, startAngle, sweepAngle, !useCenter);
- if (useCenter) {
- path.close();
- }
+ SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter,
+ style.isSimpleFill());
this->internalDrawPath(clip, paint, viewMatrix, path, style);
return;
}
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index fe35869..add634d 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -2027,7 +2027,12 @@
bool useCenter,
const GrStyle& style,
const GrShaderCaps* shaderCaps) {
+ SkASSERT(!oval.isEmpty());
+ SkASSERT(sweepAngle);
SkScalar width = oval.width();
+ if (SkScalarAbs(sweepAngle) >= 360.f) {
+ return nullptr;
+ }
if (!SkScalarNearlyEqual(width, oval.height()) || !circle_stays_circle(viewMatrix)) {
return nullptr;
}