Reland "Revert "Add arcs as a specialized geometry to GrShape.""
This reverts commit8a98bc9674
. Reason for revert: <INSERT REASONING HERE> Original change's description: > Revert "Revert "Add arcs as a specialized geometry to GrShape."" > > This reverts commitaf88ec3712
. > > 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:
parent
46b08123b3
commit
580aee2fa4
@ -1304,25 +1304,6 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
|
|||||||
|
|
||||||
SkPoint singlePt;
|
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
|
// 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
|
// indicates that the sweepAngle is too small such that angles_to_unit_vectors
|
||||||
// cannot handle it.
|
// 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.
|
// make sin(endAngle) to be 0 which will then draw a dot.
|
||||||
singlePt.set(oval.centerX() + radiusX * sk_float_cos(endAngle),
|
singlePt.set(oval.centerX() + radiusX * sk_float_cos(endAngle),
|
||||||
oval.centerY() + radiusY * sk_float_sin(endAngle));
|
oval.centerY() + radiusY * sk_float_sin(endAngle));
|
||||||
addPt(singlePt);
|
forceMoveTo ? this->moveTo(singlePt) : this->lineTo(singlePt);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1346,12 +1327,12 @@ void SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
|
|||||||
if (count) {
|
if (count) {
|
||||||
this->incReserve(count * 2 + 1);
|
this->incReserve(count * 2 + 1);
|
||||||
const SkPoint& pt = conics[0].fPts[0];
|
const SkPoint& pt = conics[0].fPts[0];
|
||||||
addPt(pt);
|
forceMoveTo ? this->moveTo(pt) : this->lineTo(pt);
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
this->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW);
|
this->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW);
|
||||||
}
|
}
|
||||||
} else {
|
} 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;
|
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,
|
void SkPathPriv::CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar startAngle,
|
||||||
SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect) {
|
SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect) {
|
||||||
SkASSERT(!oval.isEmpty());
|
SkASSERT(!oval.isEmpty());
|
||||||
@ -3386,15 +3353,11 @@ void SkPathPriv::CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar st
|
|||||||
path->setFillType(SkPath::kWinding_FillType);
|
path->setFillType(SkPath::kWinding_FillType);
|
||||||
if (isFillNoPathEffect && SkScalarAbs(sweepAngle) >= 360.f) {
|
if (isFillNoPathEffect && SkScalarAbs(sweepAngle) >= 360.f) {
|
||||||
path->addOval(oval);
|
path->addOval(oval);
|
||||||
SkASSERT(path->isConvex() && DrawArcIsConvex(sweepAngle, false, isFillNoPathEffect));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (useCenter) {
|
if (useCenter) {
|
||||||
path->moveTo(oval.centerX(), oval.centerY());
|
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.
|
// Arc to mods at 360 and drawArc is not supposed to.
|
||||||
bool forceMoveTo = !useCenter;
|
bool forceMoveTo = !useCenter;
|
||||||
while (sweepAngle <= -360.f) {
|
while (sweepAngle <= -360.f) {
|
||||||
@ -3417,8 +3380,6 @@ void SkPathPriv::CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar st
|
|||||||
if (useCenter) {
|
if (useCenter) {
|
||||||
path->close();
|
path->close();
|
||||||
}
|
}
|
||||||
path->setConvexity(convex ? SkPath::kConvex_Convexity : SkPath::kConcave_Convexity);
|
|
||||||
path->fFirstDirection.store(firstDir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -105,12 +105,6 @@ public:
|
|||||||
static void CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar startAngle,
|
static void CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar startAngle,
|
||||||
SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect);
|
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:
|
* Returns a C++11-iterable object that traverses a path's verbs in order. e.g:
|
||||||
*
|
*
|
||||||
|
@ -136,7 +136,6 @@ void SkStrokeRec::applyToPaint(SkPaint* paint) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline SkScalar get_inflation_bounds(SkPaint::Join join,
|
static inline SkScalar get_inflation_bounds(SkPaint::Join join,
|
||||||
SkPaint::Cap cap,
|
|
||||||
SkScalar strokeWidth,
|
SkScalar strokeWidth,
|
||||||
SkScalar miterLimit) {
|
SkScalar miterLimit) {
|
||||||
if (strokeWidth < 0) { // fill
|
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)
|
// since we're stroked, outset the rect by the radius (and join type)
|
||||||
SkScalar radius = SkScalarHalf(strokeWidth);
|
SkScalar radius = SkScalarHalf(strokeWidth);
|
||||||
SkScalar inflation = radius;
|
|
||||||
if (SkPaint::kMiter_Join == join) {
|
if (SkPaint::kMiter_Join == join) {
|
||||||
if (miterLimit > SK_Scalar1) {
|
if (miterLimit > SK_Scalar1) {
|
||||||
inflation *= miterLimit;
|
radius *= miterLimit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// A square cap at a 45 degree angle can add sqrt(2)*radius.
|
return radius;
|
||||||
if (SkPaint::kSquare_Cap == cap) {
|
|
||||||
inflation = SkTMax(inflation, radius * SK_ScalarSqrt2);
|
|
||||||
}
|
|
||||||
return inflation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SkScalar SkStrokeRec::getInflationRadius() const {
|
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 SkStrokeRec::GetInflationRadius(const SkPaint& paint, SkPaint::Style style) {
|
||||||
SkScalar width = SkPaint::kFill_Style == style ? -SK_Scalar1 : paint.getStrokeWidth();
|
SkScalar width = SkPaint::kFill_Style == style ? -SK_Scalar1 : paint.getStrokeWidth();
|
||||||
return get_inflation_bounds(paint.getStrokeJoin(), paint.getStrokeCap(), width,
|
return get_inflation_bounds(paint.getStrokeJoin(), width, paint.getStrokeMiter());
|
||||||
paint.getStrokeMiter());
|
|
||||||
}
|
}
|
||||||
|
@ -1353,9 +1353,10 @@ void GrRenderTargetContext::drawArc(const GrClip& clip,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->drawShapeUsingPathRenderer(
|
SkPath path;
|
||||||
clip, std::move(paint), aa, viewMatrix,
|
SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter,
|
||||||
GrShape::MakeArc(oval, startAngle, sweepAngle, useCenter, style));
|
style.isSimpleFill());
|
||||||
|
this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path, style));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
|
void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
|
||||||
|
@ -18,9 +18,6 @@ GrShape& GrShape::operator=(const GrShape& that) {
|
|||||||
case Type::kRRect:
|
case Type::kRRect:
|
||||||
fRRectData = that.fRRectData;
|
fRRectData = that.fRRectData;
|
||||||
break;
|
break;
|
||||||
case Type::kArc:
|
|
||||||
fArcData = that.fArcData;
|
|
||||||
break;
|
|
||||||
case Type::kLine:
|
case Type::kLine:
|
||||||
fLineData = that.fLineData;
|
fLineData = that.fLineData;
|
||||||
break;
|
break;
|
||||||
@ -85,14 +82,6 @@ GrShape GrShape::MakeFilled(const GrShape& original, FillInversion inversion) {
|
|||||||
result.fRRectData.fStart = kDefaultRRectStart;
|
result.fRRectData.fStart = kDefaultRRectStart;
|
||||||
result.fRRectData.fInverted = is_inverted(original.fRRectData.fInverted, inversion);
|
result.fRRectData.fInverted = is_inverted(original.fRRectData.fInverted, inversion);
|
||||||
break;
|
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:
|
case Type::kLine:
|
||||||
// Lines don't fill.
|
// Lines don't fill.
|
||||||
if (is_inverted(original.fLineData.fInverted, inversion)) {
|
if (is_inverted(original.fLineData.fInverted, inversion)) {
|
||||||
@ -155,9 +144,6 @@ SkRect GrShape::bounds() const {
|
|||||||
}
|
}
|
||||||
case Type::kRRect:
|
case Type::kRRect:
|
||||||
return fRRectData.fRRect.getBounds();
|
return fRRectData.fRRect.getBounds();
|
||||||
case Type::kArc:
|
|
||||||
// Could make this less conservative by looking at angles.
|
|
||||||
return fArcData.fOval;
|
|
||||||
case Type::kPath:
|
case Type::kPath:
|
||||||
return this->path().getBounds();
|
return this->path().getBounds();
|
||||||
}
|
}
|
||||||
@ -229,13 +215,9 @@ int GrShape::unstyledKeySize() const {
|
|||||||
return 1;
|
return 1;
|
||||||
case Type::kRRect:
|
case Type::kRRect:
|
||||||
SkASSERT(!fInheritedKey.count());
|
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.
|
// + 1 for the direction, start index, and inverseness.
|
||||||
return SkRRect::kSizeInMemory / sizeof(uint32_t) + 1;
|
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:
|
case Type::kLine:
|
||||||
GR_STATIC_ASSERT(2 * sizeof(uint32_t) == sizeof(SkPoint));
|
GR_STATIC_ASSERT(2 * sizeof(uint32_t) == sizeof(SkPoint));
|
||||||
// 4 for the end points and 1 for the inverseness
|
// 4 for the end points and 1 for the inverseness
|
||||||
@ -278,10 +260,6 @@ void GrShape::writeUnstyledKey(uint32_t* key) const {
|
|||||||
*key++ |= fRRectData.fStart;
|
*key++ |= fRRectData.fStart;
|
||||||
SkASSERT(fRRectData.fStart < 8);
|
SkASSERT(fRRectData.fStart < 8);
|
||||||
break;
|
break;
|
||||||
case Type::kArc:
|
|
||||||
memcpy(key, &fArcData, sizeof(fArcData));
|
|
||||||
key += sizeof(fArcData) / sizeof(uint32_t);
|
|
||||||
break;
|
|
||||||
case Type::kLine:
|
case Type::kLine:
|
||||||
memcpy(key, fLineData.fPts, 2 * sizeof(SkPoint));
|
memcpy(key, fLineData.fPts, 2 * sizeof(SkPoint));
|
||||||
key += 4;
|
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) {
|
GrShape::GrShape(const GrShape& that) : fStyle(that.fStyle) {
|
||||||
const SkPath* thatPath = Type::kPath == that.fType ? &that.fPathData.fPath : nullptr;
|
const SkPath* thatPath = Type::kPath == that.fType ? &that.fPathData.fPath : nullptr;
|
||||||
this->initType(that.fType, thatPath);
|
this->initType(that.fType, thatPath);
|
||||||
@ -405,9 +360,6 @@ GrShape::GrShape(const GrShape& that) : fStyle(that.fStyle) {
|
|||||||
case Type::kRRect:
|
case Type::kRRect:
|
||||||
fRRectData = that.fRRectData;
|
fRRectData = that.fRRectData;
|
||||||
break;
|
break;
|
||||||
case Type::kArc:
|
|
||||||
fArcData = that.fArcData;
|
|
||||||
break;
|
|
||||||
case Type::kLine:
|
case Type::kLine:
|
||||||
fLineData = that.fLineData;
|
fLineData = that.fLineData;
|
||||||
break;
|
break;
|
||||||
@ -636,7 +588,6 @@ void GrShape::attemptToSimplifyRRect() {
|
|||||||
} else if (fStyle.isDashed()) {
|
} else if (fStyle.isDashed()) {
|
||||||
// Dashing ignores the inverseness (currently). skbug.com/5421
|
// Dashing ignores the inverseness (currently). skbug.com/5421
|
||||||
fRRectData.fInverted = false;
|
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.
|
// Turn a stroke-and-filled miter rect into a filled rect. TODO: more rrect stroke shortcuts.
|
||||||
if (!fStyle.hasPathEffect() &&
|
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() {
|
bool GrShape::attemptToSimplifyStrokedLineToRRect() {
|
||||||
SkASSERT(Type::kLine == fType);
|
SkASSERT(Type::kLine == fType);
|
||||||
SkASSERT(fStyle.strokeRec().getStyle() == SkStrokeRec::kStroke_Style);
|
SkASSERT(fStyle.strokeRec().getStyle() == SkStrokeRec::kStroke_Style);
|
||||||
|
@ -116,9 +116,6 @@ public:
|
|||||||
this->attemptToSimplifyRRect();
|
this->attemptToSimplifyRRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
static GrShape MakeArc(const SkRect& oval, SkScalar startAngleDegrees,
|
|
||||||
SkScalar sweepAngleDegrees, bool useCenter, const GrStyle& style);
|
|
||||||
|
|
||||||
GrShape(const GrShape&);
|
GrShape(const GrShape&);
|
||||||
GrShape& operator=(const GrShape& that);
|
GrShape& operator=(const GrShape& that);
|
||||||
|
|
||||||
@ -212,16 +209,6 @@ public:
|
|||||||
out->setFillType(kDefaultPathFillType);
|
out->setFillType(kDefaultPathFillType);
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case Type::kLine:
|
||||||
out->reset();
|
out->reset();
|
||||||
out->moveTo(fLineData.fPts[0]);
|
out->moveTo(fLineData.fPts[0]);
|
||||||
@ -269,10 +256,6 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
case Type::kRRect:
|
case Type::kRRect:
|
||||||
return true;
|
return true;
|
||||||
case Type::kArc:
|
|
||||||
return SkPathPriv::DrawArcIsConvex(fArcData.fSweepAngleDegrees,
|
|
||||||
SkToBool(fArcData.fUseCenter),
|
|
||||||
fStyle.isSimpleFill());
|
|
||||||
case Type::kLine:
|
case Type::kLine:
|
||||||
return true;
|
return true;
|
||||||
case Type::kPath:
|
case Type::kPath:
|
||||||
@ -299,9 +282,6 @@ public:
|
|||||||
case Type::kRRect:
|
case Type::kRRect:
|
||||||
ret = fRRectData.fInverted;
|
ret = fRRectData.fInverted;
|
||||||
break;
|
break;
|
||||||
case Type::kArc:
|
|
||||||
ret = fArcData.fInverted;
|
|
||||||
break;
|
|
||||||
case Type::kLine:
|
case Type::kLine:
|
||||||
ret = fLineData.fInverted;
|
ret = fLineData.fInverted;
|
||||||
break;
|
break;
|
||||||
@ -340,8 +320,6 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
case Type::kRRect:
|
case Type::kRRect:
|
||||||
return true;
|
return true;
|
||||||
case Type::kArc:
|
|
||||||
return fArcData.fUseCenter;
|
|
||||||
case Type::kLine:
|
case Type::kLine:
|
||||||
return false;
|
return false;
|
||||||
case Type::kPath:
|
case Type::kPath:
|
||||||
@ -365,11 +343,6 @@ public:
|
|||||||
return SkPath::kLine_SegmentMask;
|
return SkPath::kLine_SegmentMask;
|
||||||
}
|
}
|
||||||
return SkPath::kLine_SegmentMask | SkPath::kConic_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:
|
case Type::kLine:
|
||||||
return SkPath::kLine_SegmentMask;
|
return SkPath::kLine_SegmentMask;
|
||||||
case Type::kPath:
|
case Type::kPath:
|
||||||
@ -414,7 +387,6 @@ private:
|
|||||||
kEmpty,
|
kEmpty,
|
||||||
kInvertedEmpty,
|
kInvertedEmpty,
|
||||||
kRRect,
|
kRRect,
|
||||||
kArc,
|
|
||||||
kLine,
|
kLine,
|
||||||
kPath,
|
kPath,
|
||||||
};
|
};
|
||||||
@ -466,7 +438,6 @@ private:
|
|||||||
void attemptToSimplifyPath();
|
void attemptToSimplifyPath();
|
||||||
void attemptToSimplifyRRect();
|
void attemptToSimplifyRRect();
|
||||||
void attemptToSimplifyLine();
|
void attemptToSimplifyLine();
|
||||||
void attemptToSimplifyArc();
|
|
||||||
|
|
||||||
bool attemptToSimplifyStrokedLineToRRect();
|
bool attemptToSimplifyStrokedLineToRRect();
|
||||||
|
|
||||||
@ -523,33 +494,26 @@ private:
|
|||||||
return kPathRRectStartIdx;
|
return kPathRRectStartIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type fType;
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
SkRRect fRRect;
|
SkRRect fRRect;
|
||||||
SkPath::Direction fDir;
|
SkPath::Direction fDir;
|
||||||
unsigned fStart;
|
unsigned fStart;
|
||||||
bool fInverted;
|
bool fInverted;
|
||||||
} fRRectData;
|
} fRRectData;
|
||||||
struct {
|
struct {
|
||||||
SkRect fOval;
|
SkPath fPath;
|
||||||
SkScalar fStartAngleDegrees;
|
|
||||||
SkScalar fSweepAngleDegrees;
|
|
||||||
int16_t fUseCenter;
|
|
||||||
int16_t fInverted;
|
|
||||||
} fArcData;
|
|
||||||
struct {
|
|
||||||
SkPath fPath;
|
|
||||||
// Gen ID of the original path (fPath may be modified)
|
// Gen ID of the original path (fPath may be modified)
|
||||||
int32_t fGenID;
|
int32_t fGenID;
|
||||||
} fPathData;
|
} fPathData;
|
||||||
struct {
|
struct {
|
||||||
SkPoint fPts[2];
|
SkPoint fPts[2];
|
||||||
bool fInverted;
|
bool fInverted;
|
||||||
} fLineData;
|
} fLineData;
|
||||||
};
|
};
|
||||||
GrStyle fStyle;
|
GrStyle fStyle;
|
||||||
SkTLazy<SkPath> fInheritedPathForListeners;
|
SkTLazy<SkPath> fInheritedPathForListeners;
|
||||||
SkAutoSTArray<8, uint32_t> fInheritedKey;
|
SkAutoSTArray<8, uint32_t> fInheritedKey;
|
||||||
Type fType;
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -60,7 +60,7 @@ static bool test_bounds_by_rasterizing(const SkPath& path, const SkRect& bounds)
|
|||||||
// everything got clipped out.
|
// everything got clipped out.
|
||||||
static constexpr int kRes = 2000;
|
static constexpr int kRes = 2000;
|
||||||
// This tolerance is in units of 1/kRes fractions of the bounds width/height.
|
// 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);
|
GR_STATIC_ASSERT(kRes % 4 == 0);
|
||||||
SkImageInfo info = SkImageInfo::MakeA8(kRes, kRes);
|
SkImageInfo info = SkImageInfo::MakeA8(kRes, kRes);
|
||||||
sk_sp<SkSurface> surface = SkSurface::MakeRaster(info);
|
sk_sp<SkSurface> surface = SkSurface::MakeRaster(info);
|
||||||
@ -389,34 +389,6 @@ private:
|
|||||||
SkRRect fRRect;
|
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 {
|
class PathGeo : public Geo {
|
||||||
public:
|
public:
|
||||||
enum class Invert { kNo, kYes };
|
enum class Invert { kNo, kYes };
|
||||||
@ -2149,10 +2121,6 @@ DEF_TEST(GrShape, reporter) {
|
|||||||
PathGeo::Invert::kNo));
|
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;
|
SkPath openRectPath;
|
||||||
openRectPath.moveTo(0, 0);
|
openRectPath.moveTo(0, 0);
|
||||||
@ -2253,80 +2221,4 @@ DEF_TEST(GrShape, reporter) {
|
|||||||
test_volatile_path(reporter, PathGeo(SkPath(), PathGeo::Invert::kNo));
|
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
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user