Index: src/gpu/GrShape.cpp |
diff --git a/src/gpu/GrShape.cpp b/src/gpu/GrShape.cpp |
index 5ffd32d46de2f36b61f8093d614e8e408624f49d..698ff48373cdf039c8ca81be298af885824140fa 100644 |
--- a/src/gpu/GrShape.cpp |
+++ b/src/gpu/GrShape.cpp |
@@ -30,10 +30,12 @@ GrShape& GrShape::operator=(const GrShape& that) { |
} |
SkRect GrShape::bounds() const { |
- static constexpr SkRect kEmpty = SkRect::MakeEmpty(); |
+ // Bounds where left == bottom or top == right can indicate a line or point shape. We return |
+ // inverted bounds for a truly empty shape. |
+ static constexpr SkRect kInverted = SkRect::MakeLTRB(1, 1, -1, -1); |
switch (fType) { |
case Type::kEmpty: |
- return kEmpty; |
+ return kInverted; |
case Type::kLine: { |
SkRect bounds; |
if (fLineData.fPts[0].fX < fLineData.fPts[1].fX) { |
@@ -58,7 +60,7 @@ SkRect GrShape::bounds() const { |
return this->path().getBounds(); |
} |
SkFAIL("Unknown shape type"); |
- return kEmpty; |
+ return kInverted; |
} |
SkRect GrShape::styledBounds() const { |
@@ -158,6 +160,9 @@ void GrShape::setInheritedKey(const GrShape &parent, GrStyle::Apply apply, SkSca |
if (parent.knownToBeClosed()) { |
styleKeyFlags |= GrStyle::kClosed_KeyFlag; |
} |
+ if (parent.asLine(nullptr, nullptr)) { |
+ styleKeyFlags |= GrStyle::kNoJoins_KeyFlag; |
+ } |
int styleCnt = GrStyle::KeySize(parent.fStyle, apply, styleKeyFlags); |
if (styleCnt < 0) { |
// The style doesn't allow a key, set the path gen ID to 0 so that we fail when |
@@ -232,17 +237,9 @@ GrShape::GrShape(const GrShape& parent, GrStyle::Apply apply, SkScalar scale) { |
SkStrokeRec strokeRec = parent.fStyle.strokeRec(); |
if (!parent.fStyle.applyPathEffectToPath(&this->path(), &strokeRec, *srcForPathEffect, |
scale)) { |
- // If the path effect fails then we continue as though there was no path effect. |
- // If the original was a rrect that we couldn't canonicalize because of the path |
- // effect, then do so now. |
- if (parent.fType == Type::kRRect && (parent.fRRectData.fDir != kDefaultRRectDir || |
- parent.fRRectData.fStart != kDefaultRRectStart)) { |
- SkASSERT(srcForPathEffect == tmpPath.get()); |
- tmpPath.get()->reset(); |
- tmpPath.get()->addRRect(parent.fRRectData.fRRect, kDefaultRRectDir, |
- kDefaultRRectDir); |
- } |
- this->path() = *srcForPathEffect; |
+ tmpParent.init(*srcForPathEffect, GrStyle(strokeRec, nullptr)); |
+ *this = tmpParent.get()->applyStyle(apply, scale); |
+ return; |
} |
// A path effect has access to change the res scale but we aren't expecting it to and it |
// would mess up our key computation. |
@@ -262,8 +259,16 @@ GrShape::GrShape(const GrShape& parent, GrStyle::Apply apply, SkScalar scale) { |
} |
tmpParent.get()->asPath(tmpPath.get()); |
SkStrokeRec::InitStyle fillOrHairline; |
- SkAssertResult(tmpParent.get()->style().applyToPath(&this->path(), &fillOrHairline, |
- *tmpPath.get(), scale)); |
+ // The parent shape may have simplified away the strokeRec, check for that here. |
+ if (tmpParent.get()->style().applies()) { |
+ SkAssertResult(tmpParent.get()->style().applyToPath(&this->path(), &fillOrHairline, |
+ *tmpPath.get(), scale)); |
+ } else if (tmpParent.get()->style().isSimpleFill()) { |
+ fillOrHairline = SkStrokeRec::kFill_InitStyle; |
+ } else { |
+ SkASSERT(tmpParent.get()->style().isSimpleHairline()); |
+ fillOrHairline = SkStrokeRec::kHairline_InitStyle; |
+ } |
fStyle.resetToInitStyle(fillOrHairline); |
parentForKey = tmpParent.get(); |
} else { |
@@ -401,19 +406,76 @@ void GrShape::attemptToSimplifyRRect() { |
} |
void GrShape::attemptToSimplifyLine() { |
+ SkASSERT(Type::kLine == fType); |
+ SkASSERT(!fInheritedKey.count()); |
+ if (fStyle.isDashed()) { |
+ // Dashing ignores inverseness. |
+ fLineData.fInverted = false; |
+ return; |
+ } else if (fStyle.hasPathEffect()) { |
+ return; |
+ } |
+ if (fStyle.strokeRec().getStyle() == SkStrokeRec::kStrokeAndFill_Style) { |
+ // Make stroke + fill be stroke since the fill is empty. |
+ SkStrokeRec rec = fStyle.strokeRec(); |
+ rec.setStrokeStyle(fStyle.strokeRec().getWidth(), false); |
+ fStyle = GrStyle(rec, nullptr); |
+ } |
if (fStyle.isSimpleFill() && !fLineData.fInverted) { |
this->changeType(Type::kEmpty); |
- } else { |
- // Only path effects could care about the order of the points. Otherwise canonicalize |
- // the point order |
- if (!fStyle.hasPathEffect()) { |
- SkPoint* pts = fLineData.fPts; |
- if (pts[1].fY < pts[0].fY || (pts[1].fY == pts[0].fY && pts[1].fX < pts[0].fX)) { |
- SkTSwap(pts[0], pts[1]); |
+ return; |
+ } |
+ SkPoint* pts = fLineData.fPts; |
+ if (fStyle.strokeRec().getStyle() == SkStrokeRec::kStroke_Style) { |
+ // If it is horizontal or vertical we will turn it into a filled rrect. |
+ SkRect rect; |
+ rect.fLeft = SkTMin(pts[0].fX, pts[1].fX); |
+ rect.fRight = SkTMax(pts[0].fX, pts[1].fX); |
+ rect.fTop = SkTMin(pts[0].fY, pts[1].fY); |
+ rect.fBottom = SkTMax(pts[0].fY, pts[1].fY); |
+ bool eqX = rect.fLeft == rect.fRight; |
+ bool eqY = rect.fTop == rect.fBottom; |
+ if (eqX || eqY) { |
+ SkScalar r = fStyle.strokeRec().getWidth() / 2; |
+ bool inverted = fLineData.fInverted; |
+ this->changeType(Type::kRRect); |
+ switch (fStyle.strokeRec().getCap()) { |
+ case SkPaint::kButt_Cap: |
+ if (eqX && eqY) { |
+ this->changeType(Type::kEmpty); |
+ return; |
+ } |
+ if (eqX) { |
+ rect.outset(r, 0); |
+ } else { |
+ rect.outset(0, r); |
+ } |
+ fRRectData.fRRect = SkRRect::MakeRect(rect); |
+ break; |
+ case SkPaint::kSquare_Cap: |
+ rect.outset(r, r); |
+ fRRectData.fRRect = SkRRect::MakeRect(rect); |
+ break; |
+ case SkPaint::kRound_Cap: |
+ rect.outset(r, r); |
+ fRRectData.fRRect = SkRRect::MakeRectXY(rect, r, r); |
+ break; |
} |
- } else if (fStyle.isDashed()) { |
- // Dashing ignores inverseness. |
- fLineData.fInverted = false; |
+ fRRectData.fInverted = inverted; |
+ fRRectData.fDir = kDefaultRRectDir; |
+ fRRectData.fStart = kDefaultRRectStart; |
+ if (fRRectData.fRRect.isEmpty()) { |
+ // This can happen when r is very small relative to the rect edges. |
+ this->changeType(Type::kEmpty); |
+ return; |
+ } |
+ fStyle = GrStyle::SimpleFill(); |
+ return; |
} |
} |
+ // Only path effects could care about the order of the points. Otherwise canonicalize |
+ // the point order. |
+ if (pts[1].fY < pts[0].fY || (pts[1].fY == pts[0].fY && pts[1].fX < pts[0].fX)) { |
+ SkTSwap(pts[0], pts[1]); |
+ } |
} |