Index: src/gpu/GrShape.h |
diff --git a/src/gpu/GrShape.h b/src/gpu/GrShape.h |
index 12093f41436e492dbb9af9d0de61abdb5548f032..30a1b83bf896c018add3aaff51b7210cb8958922 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,31 @@ |
* 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) { |
+ fRRectStart = DefaultRRectDirAndStartIndex(rrect, false, &fRRectDir); |
this->attemptToReduceFromRRect(); |
} |
explicit GrShape(const SkRect& rect) |
: fType(Type::kRRect) |
, fRRect(SkRRect::MakeRect(rect)) { |
+ fRRectStart = DefaultRectDirAndStartIndex(rect, false, &fRRectDir); |
this->attemptToReduceFromRRect(); |
} |
@@ -64,6 +67,20 @@ public: |
: fType(Type::kRRect) |
, fRRect(rrect) |
, fStyle(style) { |
+ fRRectStart = DefaultRRectDirAndStartIndex(rrect, style.hasPathEffect(), &fRRectDir); |
+ 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 { |
+ fRRectStart = DefaultRRectDirAndStartIndex(rrect, false, &fRRectDir); |
+ } |
this->attemptToReduceFromRRect(); |
} |
@@ -71,6 +88,7 @@ public: |
: fType(Type::kRRect) |
, fRRect(SkRRect::MakeRect(rect)) |
, fStyle(style) { |
+ fRRectStart = DefaultRectDirAndStartIndex(rect, style.hasPathEffect(), &fRRectDir); |
this->attemptToReduceFromRRect(); |
} |
@@ -85,6 +103,7 @@ public: |
: fType(Type::kRRect) |
, fRRect(rrect) |
, fStyle(paint) { |
+ fRRectStart = DefaultRRectDirAndStartIndex(rrect, fStyle.hasPathEffect(), &fRRectDir); |
this->attemptToReduceFromRRect(); |
} |
@@ -92,6 +111,7 @@ public: |
: fType(Type::kRRect) |
, fRRect(SkRRect::MakeRect(rect)) |
, fStyle(paint) { |
+ fRRectStart = DefaultRectDirAndStartIndex(rect, fStyle.hasPathEffect(), &fRRectDir); |
this->attemptToReduceFromRRect(); |
} |
@@ -116,13 +136,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 +160,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 +216,6 @@ private: |
kPath, |
}; |
- |
/** Constructor used by the applyStyle() function */ |
GrShape(const GrShape& parentShape, GrStyle::Apply, SkScalar scale); |
@@ -202,8 +227,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 +244,58 @@ private: |
} |
static Type AttemptToReduceFromPathImpl(const SkPath& path, SkRRect* rrect, |
- const SkPathEffect* pe, const SkStrokeRec& strokeRec) { |
- if (path.isEmpty()) { |
- return Type::kEmpty; |
+ SkPath::Direction* rrectDir, unsigned* rrectStart, |
+ const SkPathEffect* pe, const SkStrokeRec& strokeRec); |
+ |
+ static constexpr SkPath::Direction kDefaultRRectDir = SkPath::kCW_Direction; |
+ static constexpr unsigned kDefaultRRectStart = 0; |
+ |
+ static unsigned DefaultRectDirAndStartIndex(const SkRect& rect, bool hasPathEffect, |
+ SkPath::Direction* dir) { |
+ *dir = kDefaultRRectDir; |
+ // 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) { |
+ // It doesn't matter what start we use, just be consistent to avoid redundant keys. |
+ return kDefaultRRectStart; |
} |
- if (path.isRRect(rrect)) { |
- SkASSERT(!rrect->isEmpty()); |
- return Type::kRRect; |
+ // In SkPath a rect starts at index 0 by default. This is the top left corner. However, |
+ // 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. |
+ 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::kCCW_Direction; |
+ // 0 becomes start index 1 and times 2 to convert from rect the rrect indices. |
+ return 2 * 1; |
+ } else if (swapY) { |
+ *dir = SkPath::kCCW_Direction; |
+ // 0 becomes start index 3 and times 2 to convert from rect the rrect indices. |
+ return 2 * 3; |
} |
- SkRect rect; |
- if (path.isOval(&rect)) { |
- rrect->setOval(rect); |
- return Type::kRRect; |
- } |
- bool closed; |
- if (path.isRect(&rect, &closed, nullptr)) { |
- if (closed || (!pe && strokeRec.isFillStyle())) { |
- rrect->setRect(rect); |
- return Type::kRRect; |
- } |
+ return 0; |
+ } |
+ |
+ static unsigned DefaultRRectDirAndStartIndex(const SkRRect& rrect, bool hasPathEffect, |
+ SkPath::Direction* dir) { |
+ // 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 kPathRRectStartIdx = 6; |
+ *dir = kDefaultRRectDir; |
+ if (!hasPathEffect) { |
+ // It doesn't matter what start we use, just be consistent to avoid redundant keys. |
+ return kDefaultRRectStart; |
} |
- return Type::kPath; |
+ return kPathRRectStartIdx; |
} |
Type fType; |
SkRRect fRRect; |
+ SkPath::Direction fRRectDir; |
+ unsigned fRRectStart; |
SkTLazy<SkPath> fPath; |
GrStyle fStyle; |
SkAutoSTArray<8, uint32_t> fInheritedKey; |