Index: src/gpu/GrShape.h |
diff --git a/src/gpu/GrShape.h b/src/gpu/GrShape.h |
index 12093f41436e492dbb9af9d0de61abdb5548f032..1728b3b2f14ed17820d96722855f9a8ca532a666 100644 |
--- a/src/gpu/GrShape.h |
+++ b/src/gpu/GrShape.h |
@@ -10,6 +10,7 @@ |
#include "GrStyle.h" |
#include "SkPath.h" |
+#include "SkPathPriv.h" |
#include "SkRRect.h" |
#include "SkTemplates.h" |
#include "SkTLazy.h" |
@@ -27,29 +28,33 @@ |
* to two shapes that reflect the same underlying geometry the computed keys of the stylized shapes |
* will be the same. |
* |
- * Currently this can only be constructed from a rrect, though it can become a path by applying |
- * style to the geometry. The idea is to expand this to cover most or all of the geometries that |
- * have SkCanvas::draw APIs. |
+ * Currently this can only be constructed from a path, rect, or rrect though it can become a path |
+ * applying style to the geometry. The idea is to expand this to cover most or all of the geometries |
+ * that have SkCanvas::draw APIs. |
*/ |
class GrShape { |
public: |
GrShape() : fType(Type::kEmpty) {} |
explicit GrShape(const SkPath& path) |
- : fType(Type::kPath) |
- , fPath(&path) { |
+ : fType(Type::kPath) |
+ , fPath(&path) { |
this->attemptToReduceFromPath(); |
} |
explicit GrShape(const SkRRect& rrect) |
: fType(Type::kRRect) |
- , fRRect(rrect) { |
+ , fRRect(rrect) |
+ , fRRectDir(SkPath::kCW_Direction) |
+ , fRRectStart(DefaultRRectStartIndex(rrect, false)) { |
this->attemptToReduceFromRRect(); |
} |
explicit GrShape(const SkRect& rect) |
: fType(Type::kRRect) |
- , fRRect(SkRRect::MakeRect(rect)) { |
+ , fRRect(SkRRect::MakeRect(rect)) |
+ , fRRectDir(SkPath::kCW_Direction) |
+ , fRRectStart(1) { |
this->attemptToReduceFromRRect(); |
} |
@@ -63,7 +68,23 @@ public: |
GrShape(const SkRRect& rrect, const GrStyle& style) |
: fType(Type::kRRect) |
, fRRect(rrect) |
+ , fRRectDir(SkPath::kCW_Direction) |
+ , fRRectStart(DefaultRRectStartIndex(rrect, SkToBool(style.pathEffect()))) |
+ , fStyle(style) { |
+ this->attemptToReduceFromRRect(); |
+ } |
+ |
+ GrShape(const SkRRect& rrect, SkPath::Direction dir, unsigned start, const GrStyle& style) |
+ : fType(Type::kRRect) |
+ , fRRect(rrect) |
, fStyle(style) { |
+ if (style.pathEffect()) { |
+ fRRectDir = dir; |
+ fRRectStart = start; |
+ } else { |
+ fRRectDir = SkPath::kCW_Direction; |
+ fRRectStart = DefaultRRectStartIndex(rrect, false); |
+ } |
this->attemptToReduceFromRRect(); |
} |
@@ -71,6 +92,7 @@ public: |
: fType(Type::kRRect) |
, fRRect(SkRRect::MakeRect(rect)) |
, fStyle(style) { |
+ fRRectStart = DefaultRectDirAndStartIndex(rect, style.pathEffect(), &fRRectDir); |
this->attemptToReduceFromRRect(); |
} |
@@ -84,7 +106,9 @@ public: |
GrShape(const SkRRect& rrect, const SkPaint& paint) |
: fType(Type::kRRect) |
, fRRect(rrect) |
+ , fRRectDir(SkPath::kCW_Direction) |
, fStyle(paint) { |
+ fRRectStart = DefaultRRectStartIndex(rrect, SkToBool(fStyle.pathEffect())); |
this->attemptToReduceFromRRect(); |
} |
@@ -92,6 +116,7 @@ public: |
: fType(Type::kRRect) |
, fRRect(SkRRect::MakeRect(rect)) |
, fStyle(paint) { |
+ fRRectStart = DefaultRectDirAndStartIndex(rect, fStyle.pathEffect(), &fRRectDir); |
this->attemptToReduceFromRRect(); |
} |
@@ -116,13 +141,19 @@ public: |
} |
/** Returns the unstyled geometry as a rrect if possible. */ |
- bool asRRect(SkRRect* rrect) const { |
+ bool asRRect(SkRRect* rrect, SkPath::Direction* dir, unsigned* start) const { |
if (Type::kRRect != fType) { |
return false; |
} |
if (rrect) { |
*rrect = fRRect; |
} |
+ if (dir) { |
+ *dir = fRRectDir; |
+ } |
+ if (start) { |
+ *start = fRRectStart; |
+ } |
return true; |
} |
@@ -134,7 +165,7 @@ public: |
break; |
case Type::kRRect: |
out->reset(); |
- out->addRRect(fRRect); |
+ out->addRRect(fRRect, fRRectDir, fRRectStart); |
break; |
case Type::kPath: |
*out = *fPath.get(); |
@@ -190,7 +221,6 @@ private: |
kPath, |
}; |
- |
/** Constructor used by the applyStyle() function */ |
GrShape(const GrShape& parentShape, GrStyle::Apply, SkScalar scale); |
@@ -202,8 +232,8 @@ private: |
void attemptToReduceFromPath() { |
SkASSERT(Type::kPath == fType); |
- fType = AttemptToReduceFromPathImpl(*fPath.get(), &fRRect, fStyle.pathEffect(), |
- fStyle.strokeRec()); |
+ fType = AttemptToReduceFromPathImpl(*fPath.get(), &fRRect, &fRRectDir, &fRRectStart, |
+ fStyle.pathEffect(), fStyle.strokeRec()); |
if (Type::kPath != fType) { |
fPath.reset(); |
fInheritedKey.reset(0); |
@@ -219,31 +249,62 @@ private: |
} |
static Type AttemptToReduceFromPathImpl(const SkPath& path, SkRRect* rrect, |
- const SkPathEffect* pe, const SkStrokeRec& strokeRec) { |
- if (path.isEmpty()) { |
- return Type::kEmpty; |
- } |
- if (path.isRRect(rrect)) { |
- SkASSERT(!rrect->isEmpty()); |
- return Type::kRRect; |
+ SkPath::Direction* rrectDir, unsigned* rrectStart, |
+ const SkPathEffect* pe, const SkStrokeRec& strokeRec); |
+ |
+ static unsigned DefaultRectDirAndStartIndex(const SkRect& rect, bool hasPathEffect, |
+ SkPath::Direction* dir) { |
+ // This is the default direction when a rect is added to a path. |
+ *dir = SkPath::kCW_Direction; |
+ // This comes from SkPath's interface. The default for adding a SkRect is counter clockwise |
+ // beginning at index 0 (which happens to correspond to rrect index 0 or 7). |
+ if (!hasPathEffect) { |
+ return 0; |
} |
- SkRect rect; |
- if (path.isOval(&rect)) { |
- rrect->setOval(rect); |
- return Type::kRRect; |
+ // We store rects as rrects. RRects don't preserve the invertedness, but rather sort the |
+ // rect edges. Thus, we may need to modify the rrect's start index to account for the sort. |
+ *dir = SkPath::kCW_Direction; |
egdaniel
2016/06/06 15:50:29
This line is repeated above
bsalomon
2016/06/06 16:28:05
Done.
|
+ bool swapX = rect.fLeft > rect.fRight; |
+ bool swapY = rect.fTop > rect.fBottom; |
+ if (swapX && swapY) { |
+ // 0 becomes start index 2 and times 2 to convert from rect the rrect indices. |
+ return 2 * 2; |
+ } else if (swapX) { |
+ *dir = SkPath::kCW_Direction; |
egdaniel
2016/06/06 15:50:29
CCW?
bsalomon
2016/06/06 16:28:04
Done.
|
+ // 0 becomes start index 1 and times 2 to convert from rect the rrect indices. |
+ return 2 * 1; |
+ } else if (swapY) { |
+ *dir = SkPath::kCW_Direction; |
egdaniel
2016/06/06 15:50:29
CCW?
bsalomon
2016/06/06 16:28:05
Done.
|
+ // 0 becomes start index 3 and times 2 to convert from rect the rrect indices. |
+ return 2 * 3; |
} |
- bool closed; |
- if (path.isRect(&rect, &closed, nullptr)) { |
- if (closed || (!pe && strokeRec.isFillStyle())) { |
- rrect->setRect(rect); |
- return Type::kRRect; |
+ return 0; |
+ } |
+ |
+ static unsigned DefaultRRectStartIndex(const SkRRect& rrect, bool hasPathEffect) { |
+ // This comes from SkPath's interface. The default for adding a SkRRect to a path is |
+ // clockwise beginning at starting index 6. |
+ static constexpr unsigned kDefaultRRectStartIdx = 6; |
+ if (!hasPathEffect) { |
+ // Rect and Oval subtypes have their own default/canonical starting index. This agrees |
+ // with AttemptToReduceFromPathImpl and SkPath's add[Oval Rect] methods. |
+ if (rrect.getType() == SkRRect::kRect_Type) { |
+ // The default rect starting point in SkPath::addRect is 0 which stays 0 |
+ // in terms of rrect indices. |
+ return 0; |
+ } else if (rrect.getType() == SkRRect::kOval_Type) { |
+ // The default oval starting point in SkPath::addOval is 1 which converts to 2 |
+ // in terms of rrect indices. |
+ return 2; |
} |
} |
- return Type::kPath; |
+ return kDefaultRRectStartIdx; |
} |
Type fType; |
SkRRect fRRect; |
+ SkPath::Direction fRRectDir; |
+ unsigned fRRectStart; |
SkTLazy<SkPath> fPath; |
GrStyle fStyle; |
SkAutoSTArray<8, uint32_t> fInheritedKey; |