Reland "Revert "Add arcs as a specialized geometry to GrShape.""

This reverts commit 8a98bc9674.

Reason for revert: <INSERT REASONING HERE>

Original change's description:
> Revert "Revert "Add arcs as a specialized geometry to GrShape.""
> 
> This reverts commit af88ec3712.
> 
> Bug: skia:7794
> Change-Id: I2d0e1d7b4e025481241d823b09f5de5d0f1a13eb
> Reviewed-on: https://skia-review.googlesource.com/123627
> Reviewed-by: Robert Phillips <robertphillips@google.com>
> Commit-Queue: Brian Salomon <bsalomon@google.com>

TBR=bsalomon@google.com,robertphillips@google.com

Change-Id: Ib09a533600028b76a69b455c952f3dd12b39bdba
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:7794
Reviewed-on: https://skia-review.googlesource.com/123780
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2018-04-25 21:20:20 +00:00 committed by Skia Commit-Bot
parent 46b08123b3
commit 580aee2fa4
7 changed files with 25 additions and 308 deletions

View File

@ -1304,25 +1304,6 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
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.
@ -1337,7 +1318,7 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
// 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));
addPt(singlePt);
forceMoveTo ? this->moveTo(singlePt) : this->lineTo(singlePt);
return;
}
@ -1346,12 +1327,12 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
if (count) {
this->incReserve(count * 2 + 1);
const SkPoint& pt = conics[0].fPts[0];
addPt(pt);
forceMoveTo ? this->moveTo(pt) : this->lineTo(pt);
for (int i = 0; i < count; ++i) {
this->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW);
}
} else {
addPt(singlePt);
forceMoveTo ? this->moveTo(singlePt) : this->lineTo(singlePt);
}
}
@ -3362,20 +3343,6 @@ bool SkPathPriv::IsSimpleClosedRect(const SkPath& path, SkRect* rect, SkPath::Di
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());
@ -3386,15 +3353,11 @@ void SkPathPriv::CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar st
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) {
@ -3417,8 +3380,6 @@ void SkPathPriv::CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar st
if (useCenter) {
path->close();
}
path->setConvexity(convex ? SkPath::kConvex_Convexity : SkPath::kConcave_Convexity);
path->fFirstDirection.store(firstDir);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -105,12 +105,6 @@ public:
static void CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar startAngle,
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:
*

View File

@ -136,7 +136,6 @@ void SkStrokeRec::applyToPaint(SkPaint* paint) const {
}
static inline SkScalar get_inflation_bounds(SkPaint::Join join,
SkPaint::Cap cap,
SkScalar strokeWidth,
SkScalar miterLimit) {
if (strokeWidth < 0) { // fill
@ -146,25 +145,20 @@ static inline SkScalar get_inflation_bounds(SkPaint::Join join,
}
// since we're stroked, outset the rect by the radius (and join type)
SkScalar radius = SkScalarHalf(strokeWidth);
SkScalar inflation = radius;
if (SkPaint::kMiter_Join == join) {
if (miterLimit > SK_Scalar1) {
inflation *= miterLimit;
radius *= miterLimit;
}
}
// A square cap at a 45 degree angle can add sqrt(2)*radius.
if (SkPaint::kSquare_Cap == cap) {
inflation = SkTMax(inflation, radius * SK_ScalarSqrt2);
}
return inflation;
return radius;
}
SkScalar SkStrokeRec::getInflationRadius() const {
return get_inflation_bounds((SkPaint::Join)fJoin, (SkPaint::Cap)fCap, fWidth, fMiterLimit);
return get_inflation_bounds((SkPaint::Join)fJoin, fWidth, fMiterLimit);
}
SkScalar SkStrokeRec::GetInflationRadius(const SkPaint& paint, SkPaint::Style style) {
SkScalar width = SkPaint::kFill_Style == style ? -SK_Scalar1 : paint.getStrokeWidth();
return get_inflation_bounds(paint.getStrokeJoin(), paint.getStrokeCap(), width,
paint.getStrokeMiter());
return get_inflation_bounds(paint.getStrokeJoin(), width, paint.getStrokeMiter());
}

View File

@ -1353,9 +1353,10 @@ void GrRenderTargetContext::drawArc(const GrClip& clip,
return;
}
}
this->drawShapeUsingPathRenderer(
clip, std::move(paint), aa, viewMatrix,
GrShape::MakeArc(oval, startAngle, sweepAngle, useCenter, style));
SkPath path;
SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter,
style.isSimpleFill());
this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path, style));
}
void GrRenderTargetContext::drawImageLattice(const GrClip& clip,

View File

@ -18,9 +18,6 @@ GrShape& GrShape::operator=(const GrShape& that) {
case Type::kRRect:
fRRectData = that.fRRectData;
break;
case Type::kArc:
fArcData = that.fArcData;
break;
case Type::kLine:
fLineData = that.fLineData;
break;
@ -85,14 +82,6 @@ GrShape GrShape::MakeFilled(const GrShape& original, FillInversion inversion) {
result.fRRectData.fStart = kDefaultRRectStart;
result.fRRectData.fInverted = is_inverted(original.fRRectData.fInverted, inversion);
break;
case Type::kArc:
result.fType = original.fType;
result.fArcData.fOval = original.fArcData.fOval;
result.fArcData.fStartAngleDegrees = original.fArcData.fStartAngleDegrees;
result.fArcData.fSweepAngleDegrees = original.fArcData.fSweepAngleDegrees;
result.fArcData.fUseCenter = original.fArcData.fUseCenter;
result.fArcData.fInverted = is_inverted(original.fArcData.fInverted, inversion);
break;
case Type::kLine:
// Lines don't fill.
if (is_inverted(original.fLineData.fInverted, inversion)) {
@ -155,9 +144,6 @@ SkRect GrShape::bounds() const {
}
case Type::kRRect:
return fRRectData.fRRect.getBounds();
case Type::kArc:
// Could make this less conservative by looking at angles.
return fArcData.fOval;
case Type::kPath:
return this->path().getBounds();
}
@ -229,13 +215,9 @@ int GrShape::unstyledKeySize() const {
return 1;
case Type::kRRect:
SkASSERT(!fInheritedKey.count());
GR_STATIC_ASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t));
SkASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t));
// + 1 for the direction, start index, and inverseness.
return SkRRect::kSizeInMemory / sizeof(uint32_t) + 1;
case Type::kArc:
SkASSERT(!fInheritedKey.count());
GR_STATIC_ASSERT(0 == sizeof(fArcData) % sizeof(uint32_t));
return sizeof(fArcData) / sizeof(uint32_t);
case Type::kLine:
GR_STATIC_ASSERT(2 * sizeof(uint32_t) == sizeof(SkPoint));
// 4 for the end points and 1 for the inverseness
@ -278,10 +260,6 @@ void GrShape::writeUnstyledKey(uint32_t* key) const {
*key++ |= fRRectData.fStart;
SkASSERT(fRRectData.fStart < 8);
break;
case Type::kArc:
memcpy(key, &fArcData, sizeof(fArcData));
key += sizeof(fArcData) / sizeof(uint32_t);
break;
case Type::kLine:
memcpy(key, fLineData.fPts, 2 * sizeof(SkPoint));
key += 4;
@ -371,29 +349,6 @@ void GrShape::addGenIDChangeListener(SkPathRef::GenIDChangeListener* listener) c
}
}
GrShape GrShape::MakeArc(const SkRect& oval, SkScalar startAngleDegrees, SkScalar sweepAngleDegrees,
bool useCenter, const GrStyle& style) {
#ifdef SK_DISABLE_ARC_TO_LINE_TO_CHECK
// When this flag is set the segment mask of the path won't match GrShape's segment mask for
// paths. Represent this shape as a path.
SkPath path;
SkPathPriv::CreateDrawArcPath(&path, oval, startAngleDegrees, sweepAngleDegrees, useCenter,
style.isSimpleFill());
return GrShape(path, style);
#else
GrShape result;
result.changeType(Type::kArc);
result.fArcData.fOval = oval;
result.fArcData.fStartAngleDegrees = startAngleDegrees;
result.fArcData.fSweepAngleDegrees = sweepAngleDegrees;
result.fArcData.fUseCenter = useCenter;
result.fArcData.fInverted = false;
result.fStyle = style;
result.attemptToSimplifyArc();
return result;
#endif
}
GrShape::GrShape(const GrShape& that) : fStyle(that.fStyle) {
const SkPath* thatPath = Type::kPath == that.fType ? &that.fPathData.fPath : nullptr;
this->initType(that.fType, thatPath);
@ -405,9 +360,6 @@ GrShape::GrShape(const GrShape& that) : fStyle(that.fStyle) {
case Type::kRRect:
fRRectData = that.fRRectData;
break;
case Type::kArc:
fArcData = that.fArcData;
break;
case Type::kLine:
fLineData = that.fLineData;
break;
@ -636,7 +588,6 @@ void GrShape::attemptToSimplifyRRect() {
} else if (fStyle.isDashed()) {
// Dashing ignores the inverseness (currently). skbug.com/5421
fRRectData.fInverted = false;
// Possible TODO here: Check whether the dash results in a single arc or line.
}
// Turn a stroke-and-filled miter rect into a filled rect. TODO: more rrect stroke shortcuts.
if (!fStyle.hasPathEffect() &&
@ -689,46 +640,6 @@ void GrShape::attemptToSimplifyLine() {
}
}
void GrShape::attemptToSimplifyArc() {
SkASSERT(fType == Type::kArc);
SkASSERT(!fArcData.fInverted);
if (fArcData.fOval.isEmpty() || !fArcData.fSweepAngleDegrees) {
this->changeType(Type::kEmpty);
return;
}
// Assuming no path effect, a filled, stroked, hairline, or stroke-and-filled arc that traverses
// the full circle and doesn't use the center point is an oval. Unless it has square or round
// caps. They may protrude out of the oval. Round caps can't protrude out of a circle but we're
// ignoring that for now.
if (fStyle.isSimpleFill() || (!fStyle.pathEffect() && !fArcData.fUseCenter &&
fStyle.strokeRec().getCap() == SkPaint::kButt_Cap)) {
if (fArcData.fSweepAngleDegrees >= 360.f || fArcData.fSweepAngleDegrees <= -360.f) {
auto oval = fArcData.fOval;
this->changeType(Type::kRRect);
this->fRRectData.fRRect.setOval(oval);
this->fRRectData.fDir = kDefaultRRectDir;
this->fRRectData.fStart = kDefaultRRectStart;
this->fRRectData.fInverted = false;
return;
}
}
if (!fStyle.pathEffect()) {
// Canonicalize the arc such that the start is always in [0, 360) and the sweep is always
// positive.
if (fArcData.fSweepAngleDegrees < 0) {
fArcData.fStartAngleDegrees = fArcData.fStartAngleDegrees + fArcData.fSweepAngleDegrees;
fArcData.fSweepAngleDegrees = -fArcData.fSweepAngleDegrees;
}
}
if (this->fArcData.fStartAngleDegrees < 0 || this->fArcData.fStartAngleDegrees >= 360.f) {
this->fArcData.fStartAngleDegrees = SkScalarMod(this->fArcData.fStartAngleDegrees, 360.f);
}
// Possible TODOs here: Look at whether dash pattern results in a single dash and convert to
// non-dashed stroke. Stroke and fill can be fill if circular and no path effect. Just stroke
// could as well if the stroke fills the center.
}
bool GrShape::attemptToSimplifyStrokedLineToRRect() {
SkASSERT(Type::kLine == fType);
SkASSERT(fStyle.strokeRec().getStyle() == SkStrokeRec::kStroke_Style);

View File

@ -116,9 +116,6 @@ public:
this->attemptToSimplifyRRect();
}
static GrShape MakeArc(const SkRect& oval, SkScalar startAngleDegrees,
SkScalar sweepAngleDegrees, bool useCenter, const GrStyle& style);
GrShape(const GrShape&);
GrShape& operator=(const GrShape& that);
@ -212,16 +209,6 @@ public:
out->setFillType(kDefaultPathFillType);
}
break;
case Type::kArc:
SkPathPriv::CreateDrawArcPath(out, fArcData.fOval, fArcData.fStartAngleDegrees,
fArcData.fSweepAngleDegrees, fArcData.fUseCenter,
fStyle.isSimpleFill());
if (fArcData.fInverted) {
out->setFillType(kDefaultPathInverseFillType);
} else {
out->setFillType(kDefaultPathFillType);
}
break;
case Type::kLine:
out->reset();
out->moveTo(fLineData.fPts[0]);
@ -269,10 +256,6 @@ public:
return true;
case Type::kRRect:
return true;
case Type::kArc:
return SkPathPriv::DrawArcIsConvex(fArcData.fSweepAngleDegrees,
SkToBool(fArcData.fUseCenter),
fStyle.isSimpleFill());
case Type::kLine:
return true;
case Type::kPath:
@ -299,9 +282,6 @@ public:
case Type::kRRect:
ret = fRRectData.fInverted;
break;
case Type::kArc:
ret = fArcData.fInverted;
break;
case Type::kLine:
ret = fLineData.fInverted;
break;
@ -340,8 +320,6 @@ public:
return true;
case Type::kRRect:
return true;
case Type::kArc:
return fArcData.fUseCenter;
case Type::kLine:
return false;
case Type::kPath:
@ -365,11 +343,6 @@ public:
return SkPath::kLine_SegmentMask;
}
return SkPath::kLine_SegmentMask | SkPath::kConic_SegmentMask;
case Type::kArc:
if (fArcData.fUseCenter) {
return SkPath::kConic_SegmentMask | SkPath::kLine_SegmentMask;
}
return SkPath::kConic_SegmentMask;
case Type::kLine:
return SkPath::kLine_SegmentMask;
case Type::kPath:
@ -414,7 +387,6 @@ private:
kEmpty,
kInvertedEmpty,
kRRect,
kArc,
kLine,
kPath,
};
@ -466,7 +438,6 @@ private:
void attemptToSimplifyPath();
void attemptToSimplifyRRect();
void attemptToSimplifyLine();
void attemptToSimplifyArc();
bool attemptToSimplifyStrokedLineToRRect();
@ -523,33 +494,26 @@ private:
return kPathRRectStartIdx;
}
Type fType;
union {
struct {
SkRRect fRRect;
SkPath::Direction fDir;
unsigned fStart;
bool fInverted;
SkRRect fRRect;
SkPath::Direction fDir;
unsigned fStart;
bool fInverted;
} fRRectData;
struct {
SkRect fOval;
SkScalar fStartAngleDegrees;
SkScalar fSweepAngleDegrees;
int16_t fUseCenter;
int16_t fInverted;
} fArcData;
struct {
SkPath fPath;
SkPath fPath;
// Gen ID of the original path (fPath may be modified)
int32_t fGenID;
int32_t fGenID;
} fPathData;
struct {
SkPoint fPts[2];
bool fInverted;
SkPoint fPts[2];
bool fInverted;
} fLineData;
};
GrStyle fStyle;
SkTLazy<SkPath> fInheritedPathForListeners;
GrStyle fStyle;
SkTLazy<SkPath> fInheritedPathForListeners;
SkAutoSTArray<8, uint32_t> fInheritedKey;
Type fType;
};
#endif

View File

@ -60,7 +60,7 @@ static bool test_bounds_by_rasterizing(const SkPath& path, const SkRect& bounds)
// everything got clipped out.
static constexpr int kRes = 2000;
// This tolerance is in units of 1/kRes fractions of the bounds width/height.
static constexpr int kTol = 2;
static constexpr int kTol = 0;
GR_STATIC_ASSERT(kRes % 4 == 0);
SkImageInfo info = SkImageInfo::MakeA8(kRes, kRes);
sk_sp<SkSurface> surface = SkSurface::MakeRaster(info);
@ -389,34 +389,6 @@ private:
SkRRect fRRect;
};
class ArcGeo : public Geo {
public:
ArcGeo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter)
: fOval(oval)
, fStartAngle(startAngle)
, fSweepAngle(sweepAngle)
, fUseCenter(useCenter) {}
SkPath path() const override {
SkPath path;
SkPathPriv::CreateDrawArcPath(&path, fOval, fStartAngle, fSweepAngle, fUseCenter, false);
return path;
}
GrShape makeShape(const SkPaint& paint) const override {
return GrShape::MakeArc(fOval, fStartAngle, fSweepAngle, fUseCenter, GrStyle(paint));
}
// GrShape specializes when created from arc params but it doesn't recognize arcs from SkPath.
bool isNonPath(const SkPaint& paint) const override { return false; }
private:
SkRect fOval;
SkScalar fStartAngle;
SkScalar fSweepAngle;
bool fUseCenter;
};
class PathGeo : public Geo {
public:
enum class Invert { kNo, kYes };
@ -2149,10 +2121,6 @@ DEF_TEST(GrShape, reporter) {
PathGeo::Invert::kNo));
}
// Arcs
geos.emplace_back(new ArcGeo(SkRect::MakeWH(200, 100), 12.f, 110.f, false));
geos.emplace_back(new ArcGeo(SkRect::MakeWH(200, 100), 12.f, 110.f, true));
{
SkPath openRectPath;
openRectPath.moveTo(0, 0);
@ -2253,80 +2221,4 @@ DEF_TEST(GrShape, reporter) {
test_volatile_path(reporter, PathGeo(SkPath(), PathGeo::Invert::kNo));
}
DEF_TEST(GrShape_arcs, reporter) {
SkStrokeRec roundStroke(SkStrokeRec::kFill_InitStyle);
roundStroke.setStrokeStyle(2.f);
roundStroke.setStrokeParams(SkPaint::kRound_Cap, SkPaint::kRound_Join, 1.f);
SkStrokeRec squareStroke(roundStroke);
squareStroke.setStrokeParams(SkPaint::kSquare_Cap, SkPaint::kRound_Join, 1.f);
SkStrokeRec roundStrokeAndFill(roundStroke);
roundStrokeAndFill.setStrokeStyle(2.f, true);
static constexpr SkScalar kIntervals[] = {1, 2};
auto dash = SkDashPathEffect::Make(kIntervals, SK_ARRAY_COUNT(kIntervals), 1.5f);
SkTArray<GrStyle> styles;
styles.push_back(GrStyle::SimpleFill());
styles.push_back(GrStyle::SimpleHairline());
styles.push_back(GrStyle(roundStroke, nullptr));
styles.push_back(GrStyle(squareStroke, nullptr));
styles.push_back(GrStyle(roundStrokeAndFill, nullptr));
styles.push_back(GrStyle(roundStroke, dash));
for (const auto& style : styles) {
// An empty rect never draws anything according to SkCanvas::drawArc() docs.
TestCase emptyArc(GrShape::MakeArc(SkRect::MakeEmpty(), 0, 90.f, false, style), reporter);
TestCase emptyPath(reporter, SkPath(), style);
emptyArc.compare(reporter, emptyPath, TestCase::kAllSame_ComparisonExpecation);
static constexpr SkRect kOval1{0, 0, 50, 50};
static constexpr SkRect kOval2{50, 0, 100, 50};
// Test that swapping starting and ending angle doesn't change the shape unless the arc
// has a path effect. Also test that different ovals produce different shapes.
TestCase arc1CW(GrShape::MakeArc(kOval1, 0, 90.f, false, style), reporter);
TestCase arc1CCW(GrShape::MakeArc(kOval1, 90.f, -90.f, false, style), reporter);
TestCase arc1CWWithCenter(GrShape::MakeArc(kOval1, 0, 90.f, true, style), reporter);
TestCase arc1CCWWithCenter(GrShape::MakeArc(kOval1, 90.f, -90.f, true, style), reporter);
TestCase arc2CW(GrShape::MakeArc(kOval2, 0, 90.f, false, style), reporter);
TestCase arc2CWWithCenter(GrShape::MakeArc(kOval2, 0, 90.f, true, style), reporter);
auto reversedExepectations = style.hasPathEffect()
? TestCase::kAllDifferent_ComparisonExpecation
: TestCase::kAllSame_ComparisonExpecation;
arc1CW.compare(reporter, arc1CCW, reversedExepectations);
arc1CWWithCenter.compare(reporter, arc1CCWWithCenter, reversedExepectations);
arc1CW.compare(reporter, arc2CW, TestCase::kAllDifferent_ComparisonExpecation);
arc1CW.compare(reporter, arc1CWWithCenter, TestCase::kAllDifferent_ComparisonExpecation);
arc1CWWithCenter.compare(reporter, arc2CWWithCenter,
TestCase::kAllDifferent_ComparisonExpecation);
// Test that two arcs that start at the same angle but specified differently are equivalent.
TestCase arc3A(GrShape::MakeArc(kOval1, 224.f, 73.f, false, style), reporter);
TestCase arc3B(GrShape::MakeArc(kOval1, 224.f - 360.f, 73.f, false, style), reporter);
arc3A.compare(reporter, arc3B, TestCase::kAllDifferent_ComparisonExpecation);
// Test that an arc that traverses the entire oval (and then some) is equivalent to the
// oval itself unless there is a path effect.
TestCase ovalArc(GrShape::MakeArc(kOval1, 150.f, -790.f, false, style), reporter);
TestCase oval(GrShape(SkRRect::MakeOval(kOval1)), reporter);
auto ovalExpectations = style.hasPathEffect() ? TestCase::kAllDifferent_ComparisonExpecation
: TestCase::kAllSame_ComparisonExpecation;
if (style.strokeRec().getWidth() >= 0 && style.strokeRec().getCap() != SkPaint::kButt_Cap) {
ovalExpectations = TestCase::kAllDifferent_ComparisonExpecation;
}
ovalArc.compare(reporter, oval, ovalExpectations);
// If the the arc starts/ends at the center then it is then equivalent to the oval only for
// simple fills.
TestCase ovalArcWithCenter(GrShape::MakeArc(kOval1, 304.f, 1225.f, true, style), reporter);
ovalExpectations = style.isSimpleFill() ? TestCase::kAllSame_ComparisonExpecation
: TestCase::kAllDifferent_ComparisonExpecation;
ovalArcWithCenter.compare(reporter, oval, ovalExpectations);
}
}
#endif