| Index: src/gpu/GrShape.cpp
|
| diff --git a/src/gpu/GrShape.cpp b/src/gpu/GrShape.cpp
|
| index 7605cbf1ffabebfc7ec3d12713cef8fa94150c96..d2bec72cbfea4a6f51377339532a2159e6f0c37a 100644
|
| --- a/src/gpu/GrShape.cpp
|
| +++ b/src/gpu/GrShape.cpp
|
| @@ -24,6 +24,7 @@ GrShape& GrShape::operator=(const GrShape& that) {
|
| fRRect = that.fRRect;
|
| fRRectDir = that.fRRectDir;
|
| fRRectStart = that.fRRectStart;
|
| + fRRectIsInverted = that.fRRectIsInverted;
|
| break;
|
| case Type::kPath:
|
| if (wasPath) {
|
| @@ -71,13 +72,14 @@ int GrShape::unstyledKeySize() const {
|
| case Type::kRRect:
|
| SkASSERT(!fInheritedKey.count());
|
| SkASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t));
|
| - // + 1 for the direction + start index.
|
| + // + 1 for the direction, start index, and inverseness.
|
| return SkRRect::kSizeInMemory / sizeof(uint32_t) + 1;
|
| case Type::kPath:
|
| if (fPath.get()->isVolatile()) {
|
| return -1;
|
| } else {
|
| - return 1;
|
| + // The key is the path ID and fill type.
|
| + return 2;
|
| }
|
| }
|
| SkFAIL("Should never get here.");
|
| @@ -99,12 +101,16 @@ void GrShape::writeUnstyledKey(uint32_t* key) const {
|
| fRRect.writeToMemory(key);
|
| key += SkRRect::kSizeInMemory / sizeof(uint32_t);
|
| *key = (fRRectDir == SkPath::kCCW_Direction) ? (1 << 31) : 0;
|
| + *key |= fRRectIsInverted ? (1 << 30) : 0;
|
| *key++ |= fRRectStart;
|
| SkASSERT(fRRectStart < 8);
|
| break;
|
| case Type::kPath:
|
| SkASSERT(!fPath.get()->isVolatile());
|
| *key++ = fPath.get()->getGenerationID();
|
| + // We could canonicalize the fill rule for paths that don't differentiate between
|
| + // even/odd or winding fill (e.g. convex).
|
| + *key++ = fPath.get()->getFillType();
|
| break;
|
| }
|
| }
|
| @@ -163,6 +169,9 @@ GrShape::GrShape(const GrShape& that) : fType(that.fType), fStyle(that.fStyle) {
|
| return;
|
| case Type::kRRect:
|
| fRRect = that.fRRect;
|
| + fRRectDir = that.fRRectDir;
|
| + fRRectStart = that.fRRectStart;
|
| + fRRectIsInverted = that.fRRectIsInverted;
|
| return;
|
| case Type::kPath:
|
| fPath.set(*that.fPath.get());
|
| @@ -230,15 +239,16 @@ GrShape::GrShape(const GrShape& parent, GrStyle::Apply apply, SkScalar scale) {
|
| SkRRect rrect;
|
| SkPath::Direction dir;
|
| unsigned start;
|
| + bool inverted;
|
| Type parentType = AttemptToReduceFromPathImpl(*fPath.get(), &rrect, &dir, &start,
|
| - nullptr, strokeRec);
|
| + &inverted, nullptr, strokeRec);
|
| switch (parentType) {
|
| case Type::kEmpty:
|
| tmpParent.init();
|
| parentForKey = tmpParent.get();
|
| break;
|
| case Type::kRRect:
|
| - tmpParent.init(rrect, dir, start, GrStyle(strokeRec, nullptr));
|
| + tmpParent.init(rrect, dir, start, inverted, GrStyle(strokeRec, nullptr));
|
| parentForKey = tmpParent.get();
|
| case Type::kPath:
|
| break;
|
| @@ -269,9 +279,25 @@ GrShape::GrShape(const GrShape& parent, GrStyle::Apply apply, SkScalar scale) {
|
| this->setInheritedKey(*parentForKey, apply, scale);
|
| }
|
|
|
| +static inline bool rrect_path_is_inverse_filled(const SkPath& path, const SkStrokeRec& strokeRec,
|
| + const SkPathEffect* pe) {
|
| + // Dashing doesn't use the path fill type. Dashing only works with stroking
|
| + if (pe && pe->asADash(nullptr)) {
|
| + pe = nullptr;
|
| + }
|
| +
|
| + SkStrokeRec::Style style = strokeRec.getStyle();
|
| + if (!pe && (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style)) {
|
| + // stroking ignores the path fill rule.
|
| + return false;
|
| + }
|
| + return path.isInverseFillType();
|
| +}
|
| +
|
| GrShape::Type GrShape::AttemptToReduceFromPathImpl(const SkPath& path, SkRRect* rrect,
|
| SkPath::Direction* rrectDir,
|
| unsigned* rrectStart,
|
| + bool* rrectIsInverted,
|
| const SkPathEffect* pe,
|
| const SkStrokeRec& strokeRec) {
|
| if (path.isEmpty()) {
|
| @@ -285,6 +311,7 @@ GrShape::Type GrShape::AttemptToReduceFromPathImpl(const SkPath& path, SkRRect*
|
| if (!pe) {
|
| *rrectStart = DefaultRRectDirAndStartIndex(*rrect, false, rrectDir);
|
| }
|
| + *rrectIsInverted = rrect_path_is_inverse_filled(path, strokeRec, pe);
|
| return Type::kRRect;
|
| }
|
| SkRect rect;
|
| @@ -297,6 +324,7 @@ GrShape::Type GrShape::AttemptToReduceFromPathImpl(const SkPath& path, SkRRect*
|
| // convert from oval indexing to rrect indexiing.
|
| *rrectStart *= 2;
|
| }
|
| + *rrectIsInverted = rrect_path_is_inverse_filled(path, strokeRec, pe);
|
| return Type::kRRect;
|
| }
|
| // When there is a path effect we restrict rect detection to the narrower API that
|
| @@ -310,6 +338,7 @@ GrShape::Type GrShape::AttemptToReduceFromPathImpl(const SkPath& path, SkRRect*
|
| *rrectStart *= 2;
|
| }
|
| rrect->setRect(rect);
|
| + *rrectIsInverted = rrect_path_is_inverse_filled(path, strokeRec, pe);
|
| return Type::kRRect;
|
| }
|
| if (!pe) {
|
| @@ -320,6 +349,7 @@ GrShape::Type GrShape::AttemptToReduceFromPathImpl(const SkPath& path, SkRRect*
|
| // Since there is no path effect the dir and start index is immaterial.
|
| *rrectDir = kDefaultRRectDir;
|
| *rrectStart = kDefaultRRectStart;
|
| + *rrectIsInverted = rrect_path_is_inverse_filled(path, strokeRec, pe);
|
| return Type::kRRect;
|
| }
|
| }
|
|
|