Chromium Code Reviews| 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; |