Use a union inside GrShape to hold geometry
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2094023002

Review-Url: https://codereview.chromium.org/2094023002
diff --git a/src/gpu/GrShape.cpp b/src/gpu/GrShape.cpp
index b40d696..45ddb77 100644
--- a/src/gpu/GrShape.cpp
+++ b/src/gpu/GrShape.cpp
@@ -8,31 +8,19 @@
 #include "GrShape.h"
 
 GrShape& GrShape::operator=(const GrShape& that) {
-    bool wasPath = Type::kPath == fType;
     fStyle = that.fStyle;
-    fType = that.fType;
+    this->changeType(that.fType, Type::kPath == that.fType ? &that.path() : nullptr);
     switch (fType) {
         case Type::kEmpty:
-            if (wasPath) {
-                fPath.reset();
-            }
             break;
         case Type::kRRect:
-            if (wasPath) {
-                fPath.reset();
-            }
-            fRRect = that.fRRect;
-            fRRectDir = that.fRRectDir;
-            fRRectStart = that.fRRectStart;
-            fRRectIsInverted = that.fRRectIsInverted;
+            fRRectData.fRRect = that.fRRectData.fRRect;
+            fRRectData.fDir = that.fRRectData.fDir;
+            fRRectData.fStart = that.fRRectData.fStart;
+            fRRectData.fInverted = that.fRRectData.fInverted;
             break;
         case Type::kPath:
-            if (wasPath) {
-                *fPath.get() = *that.fPath.get();
-            } else {
-                fPath.set(*that.fPath.get());
-            }
-            fPathGenID = that.fPathGenID;
+            fPathData.fGenID = that.fPathData.fGenID;
             break;
     }
     fInheritedKey.reset(that.fInheritedKey.count());
@@ -47,9 +35,9 @@
         case Type::kEmpty:
             return kEmpty;
         case Type::kRRect:
-            return fRRect.getBounds();
+            return fRRectData.fRRect.getBounds();
         case Type::kPath:
-            return fPath.get()->getBounds();
+            return this->path().getBounds();
     }
     SkFAIL("Unknown shape type");
     return kEmpty;
@@ -76,7 +64,7 @@
             // + 1 for the direction, start index, and inverseness.
             return SkRRect::kSizeInMemory / sizeof(uint32_t) + 1;
         case Type::kPath:
-            if (0 == fPathGenID) {
+            if (0 == fPathData.fGenID) {
                 return -1;
             } else {
                 // The key is the path ID and fill type.
@@ -99,19 +87,19 @@
                 *key++ = 1;
                 break;
             case Type::kRRect:
-                fRRect.writeToMemory(key);
+                fRRectData.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);
+                *key = (fRRectData.fDir == SkPath::kCCW_Direction) ? (1 << 31) : 0;
+                *key |= fRRectData.fInverted ? (1 << 30) : 0;
+                *key++ |= fRRectData.fStart;
+                SkASSERT(fRRectData.fStart < 8);
                 break;
             case Type::kPath:
-                SkASSERT(fPathGenID);
-                *key++ = fPathGenID;
+                SkASSERT(fPathData.fGenID);
+                *key++ = fPathData.fGenID;
                 // 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();
+                *key++ = this->path().getFillType();
                 break;
         }
     }
@@ -134,7 +122,7 @@
             parentCnt = parent.unstyledKeySize();
             if (parentCnt < 0) {
                 // The parent's geometry has no key so we will have no key.
-                fPathGenID = 0;
+                fPathData.fGenID = 0;
                 return;
             }
         }
@@ -146,7 +134,7 @@
         if (styleCnt < 0) {
             // The style doesn't allow a key, set the path gen ID to 0 so that we fail when
             // we try to get a key for the shape.
-            fPathGenID = 0;
+            fPathData.fGenID = 0;
             return;
         }
         fInheritedKey.reset(parentCnt + styleCnt);
@@ -164,19 +152,20 @@
     }
 }
 
-GrShape::GrShape(const GrShape& that) : fType(that.fType), fStyle(that.fStyle) {
+GrShape::GrShape(const GrShape& that) : fStyle(that.fStyle) {
+    const SkPath* thatPath = Type::kPath == that.fType ? &that.fPathData.fPath : nullptr;
+    this->initType(that.fType, thatPath);
     switch (fType) {
         case Type::kEmpty:
             break;
         case Type::kRRect:
-            fRRect = that.fRRect;
-            fRRectDir = that.fRRectDir;
-            fRRectStart = that.fRRectStart;
-            fRRectIsInverted = that.fRRectIsInverted;
+            fRRectData.fRRect = that.fRRectData.fRRect;
+            fRRectData.fDir = that.fRRectData.fDir;
+            fRRectData.fStart = that.fRRectData.fStart;
+            fRRectData.fInverted = that.fRRectData.fInverted;
             break;
         case Type::kPath:
-            fPath.set(*that.fPath.get());
-            fPathGenID = that.fPathGenID;
+            fPathData.fGenID = that.fPathData.fGenID;
             break;
     }
     fInheritedKey.reset(that.fInheritedKey.count());
@@ -191,7 +180,7 @@
     // stroke of a rect).
     if (!parent.style().applies() ||
         (GrStyle::Apply::kPathEffectOnly == apply && !parent.style().pathEffect())) {
-        fType = Type::kEmpty;
+        this->initType(Type::kEmpty);
         *this = parent;
         return;
     }
@@ -200,12 +189,12 @@
     SkTLazy<SkPath> tmpPath;
     const GrShape* parentForKey = &parent;
     SkTLazy<GrShape> tmpParent;
-    fType = Type::kPath;
-    fPath.init();
+    this->initType(Type::kPath);
+    fPathData.fGenID = 0;
     if (pe) {
-        SkPath* srcForPathEffect;
+        const SkPath* srcForPathEffect;
         if (parent.fType == Type::kPath) {
-            srcForPathEffect = parent.fPath.get();
+            srcForPathEffect = &parent.path();
         } else {
             srcForPathEffect = tmpPath.init();
             parent.asPath(tmpPath.get());
@@ -213,18 +202,19 @@
         // Should we consider bounds? Would have to include in key, but it'd be nice to know
         // if the bounds actually modified anything before including in key.
         SkStrokeRec strokeRec = parent.fStyle.strokeRec();
-        if (!parent.fStyle.applyPathEffectToPath(fPath.get(), &strokeRec, *srcForPathEffect,
+        if (!parent.fStyle.applyPathEffectToPath(&this->path(), &strokeRec, *srcForPathEffect,
                                                  scale)) {
             // If the path effect fails then we continue as though there was no path effect.
             // If the original was a rrect that we couldn't canonicalize because of the path
             // effect, then do so now.
-            if (parent.fType == Type::kRRect && (parent.fRRectDir != kDefaultRRectDir ||
-                                                 parent.fRRectStart != kDefaultRRectStart)) {
+            if (parent.fType == Type::kRRect && (parent.fRRectData.fDir != kDefaultRRectDir ||
+                                                 parent.fRRectData.fStart != kDefaultRRectStart)) {
                 SkASSERT(srcForPathEffect == tmpPath.get());
                 tmpPath.get()->reset();
-                tmpPath.get()->addRRect(parent.fRRect, kDefaultRRectDir, kDefaultRRectDir);
+                tmpPath.get()->addRRect(parent.fRRectData.fRRect, kDefaultRRectDir,
+                                        kDefaultRRectDir);
             }
-            *fPath.get() = *srcForPathEffect;
+            this->path() = *srcForPathEffect;
         }
         // A path effect has access to change the res scale but we aren't expecting it to and it
         // would mess up our key computation.
@@ -237,14 +227,14 @@
             // We detect that case here and change parentForKey to a temporary that represents
             // the simpler shape so that applying both path effect and the strokerec all at
             // once produces the same key.
-            tmpParent.init(*fPath.get(), GrStyle(strokeRec, nullptr));
+            tmpParent.init(this->path(), GrStyle(strokeRec, nullptr));
             tmpParent.get()->setInheritedKey(parent, GrStyle::Apply::kPathEffectOnly, scale);
             if (!tmpPath.isValid()) {
                 tmpPath.init();
             }
             tmpParent.get()->asPath(tmpPath.get());
             SkStrokeRec::InitStyle fillOrHairline;
-            SkAssertResult(tmpParent.get()->style().applyToPath(fPath.get(), &fillOrHairline,
+            SkAssertResult(tmpParent.get()->style().applyToPath(&this->path(), &fillOrHairline,
                                                                 *tmpPath.get(), scale));
             fStyle.resetToInitStyle(fillOrHairline);
             parentForKey = tmpParent.get();
@@ -254,7 +244,7 @@
     } else {
         const SkPath* srcForParentStyle;
         if (parent.fType == Type::kPath) {
-            srcForParentStyle = parent.fPath.get();
+            srcForParentStyle = &parent.path();
         } else {
             srcForParentStyle = tmpPath.init();
             parent.asPath(tmpPath.get());
@@ -262,7 +252,7 @@
         SkStrokeRec::InitStyle fillOrHairline;
         SkASSERT(parent.fStyle.applies());
         SkASSERT(!parent.fStyle.pathEffect());
-        SkAssertResult(parent.fStyle.applyToPath(fPath.get(), &fillOrHairline, *srcForParentStyle,
+        SkAssertResult(parent.fStyle.applyToPath(&this->path(), &fillOrHairline, *srcForParentStyle,
                                                  scale));
         fStyle.resetToInitStyle(fillOrHairline);
     }
@@ -271,65 +261,72 @@
 }
 
 void GrShape::attemptToSimplifyPath() {
-    SkASSERT(Type::kPath == fType);
     SkRect rect;
-    if (fPath.get()->isEmpty()) {
-        fType = Type::kEmpty;
-    } else if (fPath.get()->isRRect(&fRRect, &fRRectDir, &fRRectStart)) {
+    SkRRect rrect;
+    SkPath::Direction rrectDir;
+    unsigned rrectStart;
+    bool inverted = this->path().isInverseFillType();
+    if (this->path().isEmpty()) {
+        this->changeType(Type::kEmpty);
+    } else if (this->path().isRRect(&rrect, &rrectDir, &rrectStart)) {
+        this->changeType(Type::kRRect);
+        fRRectData.fRRect = rrect;
+        fRRectData.fDir = rrectDir;
+        fRRectData.fStart = rrectStart;
+        fRRectData.fInverted = inverted;
         // Currently SkPath does not acknowledge that empty, rect, or oval subtypes as rrects.
-        SkASSERT(!fRRect.isEmpty());
-        SkASSERT(fRRect.getType() != SkRRect::kRect_Type);
-        SkASSERT(fRRect.getType() != SkRRect::kOval_Type);
-        fRRectIsInverted = fPath.get()->isInverseFillType();
-        fType = Type::kRRect;
-    } else if (fPath.get()->isOval(&rect, &fRRectDir, &fRRectStart)) {
-        fRRect.setOval(rect);
-        fRRectIsInverted = fPath.get()->isInverseFillType();
+        SkASSERT(!fRRectData.fRRect.isEmpty());
+        SkASSERT(fRRectData.fRRect.getType() != SkRRect::kRect_Type);
+        SkASSERT(fRRectData.fRRect.getType() != SkRRect::kOval_Type);
+    } else if (this->path().isOval(&rect, &rrectDir, &rrectStart)) {
+        this->changeType(Type::kRRect);
+        fRRectData.fRRect.setOval(rect);
+        fRRectData.fDir = rrectDir;
+        fRRectData.fInverted = inverted;
         // convert from oval indexing to rrect indexiing.
-        fRRectStart *= 2;
-        fType = Type::kRRect;
-    } else if (SkPathPriv::IsSimpleClosedRect(*fPath.get(), &rect, &fRRectDir, &fRRectStart)) {
+        fRRectData.fStart = 2 * rrectStart;
+    } else if (SkPathPriv::IsSimpleClosedRect(this->path(), &rect, &rrectDir, &rrectStart)) {
+        this->changeType(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().
-        fRRect.setRect(rect);
-        fRRectIsInverted = fPath.get()->isInverseFillType();
+        fRRectData.fRRect.setRect(rect);
+        fRRectData.fInverted = inverted;
+        fRRectData.fDir = rrectDir;
         // convert from rect indexing to rrect indexiing.
-        fRRectStart *= 2;
-        fType = Type::kRRect;
+        fRRectData.fStart = 2 * rrectStart;
     } else if (!this->style().hasPathEffect()) {
         bool closed;
-        if (fPath.get()->isRect(&rect, &closed, nullptr)) {
+        if (this->path().isRect(&rect, &closed, nullptr)) {
             if (closed || this->style().isSimpleFill()) {
-                fRRect.setRect(rect);
+                this->changeType(Type::kRRect);
+                fRRectData.fRRect.setRect(rect);
                 // Since there is no path effect the dir and start index is immaterial.
-                fRRectDir = kDefaultRRectDir;
-                fRRectStart = kDefaultRRectStart;
+                fRRectData.fDir = kDefaultRRectDir;
+                fRRectData.fStart = kDefaultRRectStart;
                 // There isn't dashing so we will have to preserver inverseness.
-                fRRectIsInverted = fPath.get()->isInverseFillType();
-                fType = Type::kRRect;
+                fRRectData.fInverted = inverted;
             }
         }
     }
     if (Type::kPath != fType) {
-        fPath.reset();
         fInheritedKey.reset(0);
         if (Type::kRRect == fType) {
             this->attemptToSimplifyRRect();
         }
     } else {
-        if (fInheritedKey.count() || fPath.get()->isVolatile()) {
-            fPathGenID = 0;
+        if (fInheritedKey.count() || this->path().isVolatile()) {
+            fPathData.fGenID = 0;
         } else {
-            fPathGenID = fPath.get()->getGenerationID();
+            fPathData.fGenID = this->path().getGenerationID();
         }
         if (this->style().isSimpleFill()) {
             // Filled paths are treated as though all their contours were closed.
             // Since SkPath doesn't track individual contours, this will only close the last. :(
             // There is no point in closing lines, though, since they loose their line-ness.
-            if (!fPath.get()->isLine(nullptr)) {
-                fPath.get()->close();
-                fPath.get()->setIsVolatile(true);
+            if (!this->path().isLine(nullptr)) {
+                this->path().close();
+                this->path().setIsVolatile(true);
             }
         }
         if (!this->style().hasNonDashPathEffect()) {
@@ -337,19 +334,19 @@
                 this->style().strokeRec().getStyle() == SkStrokeRec::kHairline_Style) {
                 // Stroke styles don't differentiate between winding and even/odd.
                 // Moreover, dashing ignores inverseness (skbug.com/5421)
-                bool inverse = !this->style().isDashed() && fPath.get()->isInverseFillType();
+                bool inverse = !this->style().isDashed() && this->path().isInverseFillType();
                 if (inverse) {
-                    fPath.get()->setFillType(kDefaultPathInverseFillType);
+                    this->path().setFillType(kDefaultPathInverseFillType);
                 } else {
-                    fPath.get()->setFillType(kDefaultPathFillType);
+                    this->path().setFillType(kDefaultPathFillType);
                 }
-            } else if (fPath.get()->isConvex()) {
+            } else if (this->path().isConvex()) {
                 // There is no distinction between even/odd and non-zero winding count for convex
                 // paths.
-                if (fPath.get()->isInverseFillType()) {
-                    fPath.get()->setFillType(kDefaultPathInverseFillType);
+                if (this->path().isInverseFillType()) {
+                    this->path().setFillType(kDefaultPathInverseFillType);
                 } else {
-                    fPath.get()->setFillType(kDefaultPathFillType);
+                    this->path().setFillType(kDefaultPathFillType);
                 }
             }
         }
@@ -359,15 +356,15 @@
 void GrShape::attemptToSimplifyRRect() {
     SkASSERT(Type::kRRect == fType);
     SkASSERT(!fInheritedKey.count());
-    if (fRRect.isEmpty()) {
+    if (fRRectData.fRRect.isEmpty()) {
         fType = Type::kEmpty;
         return;
     }
     if (!this->style().hasPathEffect()) {
-        fRRectDir = kDefaultRRectDir;
-        fRRectStart = kDefaultRRectStart;
+        fRRectData.fDir = kDefaultRRectDir;
+        fRRectData.fStart = kDefaultRRectStart;
     } else if (fStyle.isDashed()) {
         // Dashing ignores the inverseness (currently). skbug.com/5421
-        fRRectIsInverted = false;
+        fRRectData.fInverted = false;
     }
 }