Make GrShape capable of representing inverse filled rrects.
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2056523002

Review-Url: https://codereview.chromium.org/2056523002
diff --git a/src/gpu/GrShape.cpp b/src/gpu/GrShape.cpp
index 7605cbf..d2bec72 100644
--- a/src/gpu/GrShape.cpp
+++ b/src/gpu/GrShape.cpp
@@ -24,6 +24,7 @@
             fRRect = that.fRRect;
             fRRectDir = that.fRRectDir;
             fRRectStart = that.fRRectStart;
+            fRRectIsInverted = that.fRRectIsInverted;
             break;
         case Type::kPath:
             if (wasPath) {
@@ -71,13 +72,14 @@
         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 @@
                 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 @@
             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 @@
                 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 @@
     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 @@
         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 @@
             // 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 @@
             *rrectStart *= 2;
         }
         rrect->setRect(rect);
+        *rrectIsInverted = rrect_path_is_inverse_filled(path, strokeRec, pe);
         return Type::kRRect;
     }
     if (!pe) {
@@ -320,6 +349,7 @@
                 // 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;
             }
         }