diff options
author | Brian Salomon <bsalomon@google.com> | 2018-04-23 16:32:52 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-04-23 23:27:53 +0000 |
commit | 255bcf57ffd9db368cd66ca9697549efd799153e (patch) | |
tree | 025592c31e850e208a955b859a0962740abfedf4 /src/gpu/GrShape.cpp | |
parent | 3b8feb331a11989fdd82c2d8d18e576df98e8895 (diff) |
Add arcs as a specialized geometry to GrShape.
BUG: skia:7794
Change-Id: I484693711f48e55631732a0f4ee97e2848dec89d
Reviewed-on: https://skia-review.googlesource.com/122900
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Diffstat (limited to 'src/gpu/GrShape.cpp')
-rw-r--r-- | src/gpu/GrShape.cpp | 82 |
1 files changed, 81 insertions, 1 deletions
diff --git a/src/gpu/GrShape.cpp b/src/gpu/GrShape.cpp index 2d2bccbc0f..4cab0188d9 100644 --- a/src/gpu/GrShape.cpp +++ b/src/gpu/GrShape.cpp @@ -18,6 +18,9 @@ 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; @@ -82,6 +85,14 @@ 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)) { @@ -144,6 +155,9 @@ 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(); } @@ -215,9 +229,13 @@ int GrShape::unstyledKeySize() const { return 1; case Type::kRRect: SkASSERT(!fInheritedKey.count()); - SkASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t)); + GR_STATIC_ASSERT(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 @@ -260,6 +278,10 @@ 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; @@ -349,6 +371,20 @@ void GrShape::addGenIDChangeListener(SkPathRef::GenIDChangeListener* listener) c } } +GrShape GrShape::MakeArc(const SkRect& oval, SkScalar startAngleDegrees, SkScalar sweepAngleDegrees, + bool useCenter, const GrStyle& style) { + 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; +} + GrShape::GrShape(const GrShape& that) : fStyle(that.fStyle) { const SkPath* thatPath = Type::kPath == that.fType ? &that.fPathData.fPath : nullptr; this->initType(that.fType, thatPath); @@ -360,6 +396,9 @@ 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; @@ -588,6 +627,7 @@ 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() && @@ -640,6 +680,46 @@ 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); |