Make GrShape track the winding direction and starting point for rrect types.
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2042813002
Review-Url: https://codereview.chromium.org/2042813002
diff --git a/src/gpu/GrShape.cpp b/src/gpu/GrShape.cpp
index e0ddc55..9fcc6ee 100644
--- a/src/gpu/GrShape.cpp
+++ b/src/gpu/GrShape.cpp
@@ -22,6 +22,8 @@
fPath.reset();
}
fRRect = that.fRRect;
+ fRRectDir = that.fRRectDir;
+ fRRectStart = that.fRRectStart;
break;
case Type::kPath:
if (wasPath) {
@@ -69,7 +71,8 @@
case Type::kRRect:
SkASSERT(!fInheritedKey.count());
SkASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t));
- return SkRRect::kSizeInMemory / sizeof(uint32_t);
+ // + 1 for the direction + start index.
+ return SkRRect::kSizeInMemory / sizeof(uint32_t) + 1;
case Type::kPath:
if (fPath.get()->isVolatile()) {
return -1;
@@ -95,6 +98,9 @@
case Type::kRRect:
fRRect.writeToMemory(key);
key += SkRRect::kSizeInMemory / sizeof(uint32_t);
+ *key = (fRRectDir == SkPath::kCCW_Direction) ? (1 << 31) : 0;
+ *key++ |= fRRectStart;
+ SkASSERT(fRRectStart < 8);
break;
case Type::kPath:
SkASSERT(!fPath.get()->isVolatile());
@@ -217,15 +223,17 @@
// the simpler shape so that applying both path effect and the strokerec all at
// once produces the same key.
SkRRect rrect;
- Type parentType = AttemptToReduceFromPathImpl(*fPath.get(), &rrect, nullptr,
- strokeRec);
+ SkPath::Direction dir;
+ unsigned start;
+ Type parentType = AttemptToReduceFromPathImpl(*fPath.get(), &rrect, &dir, &start,
+ nullptr, strokeRec);
switch (parentType) {
case Type::kEmpty:
tmpParent.init();
parentForKey = tmpParent.get();
break;
case Type::kRRect:
- tmpParent.init(rrect, GrStyle(strokeRec, nullptr));
+ tmpParent.init(rrect, dir, start, GrStyle(strokeRec, nullptr));
parentForKey = tmpParent.get();
case Type::kPath:
break;
@@ -255,3 +263,61 @@
this->attemptToReduceFromPath();
this->setInheritedKey(*parentForKey, apply, scale);
}
+
+GrShape::Type GrShape::AttemptToReduceFromPathImpl(const SkPath& path, SkRRect* rrect,
+ SkPath::Direction* rrectDir,
+ unsigned* rrectStart,
+ const SkPathEffect* pe,
+ const SkStrokeRec& strokeRec) {
+ if (path.isEmpty()) {
+ return Type::kEmpty;
+ }
+ if (path.isRRect(rrect, rrectDir, rrectStart)) {
+ // Currently SkPath does not acknowledge that empty, rect, or oval subtypes as rrects.
+ SkASSERT(!rrect->isEmpty());
+ SkASSERT(rrect->getType() != SkRRect::kRect_Type);
+ SkASSERT(rrect->getType() != SkRRect::kOval_Type);
+ if (!pe) {
+ *rrectStart = DefaultRRectDirAndStartIndex(*rrect, false, rrectDir);
+ }
+ return Type::kRRect;
+ }
+ SkRect rect;
+ if (path.isOval(&rect, rrectDir, rrectStart)) {
+ rrect->setOval(rect);
+ if (!pe) {
+ *rrectDir = kDefaultRRectDir;
+ *rrectStart = kDefaultRRectStart;
+ } else {
+ // convert from oval indexing to rrect indexiing.
+ *rrectStart *= 2;
+ }
+ return Type::kRRect;
+ }
+ // When there is a path effect we restrict rect detection to the narrower API that
+ // gives us the starting position. Otherwise, we will retry with the more aggressive isRect().
+ if (SkPathPriv::IsSimpleClosedRect(path, &rect, rrectDir, rrectStart)) {
+ if (!pe) {
+ *rrectDir = kDefaultRRectDir;
+ *rrectStart = kDefaultRRectStart;
+ } else {
+ // convert from rect indexing to rrect indexiing.
+ *rrectStart *= 2;
+ }
+ rrect->setRect(rect);
+ return Type::kRRect;
+ }
+ if (!pe) {
+ bool closed;
+ if (path.isRect(&rect, &closed, nullptr)) {
+ if (closed || strokeRec.isFillStyle()) {
+ rrect->setRect(rect);
+ // Since there is no path effect the dir and start index is immaterial.
+ *rrectDir = kDefaultRRectDir;
+ *rrectStart = kDefaultRRectStart;
+ return Type::kRRect;
+ }
+ }
+ }
+ return Type::kPath;
+}