[SVGDom] Add opacity support

Group opacity support.  Unlike the other presentation attributes we
support thus far, group opacity is not inherited.

R=robertphillips@google.com,stephana@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2246943002

Review-Url: https://codereview.chromium.org/2246943002
diff --git a/experimental/svg/model/SkSVGAttribute.h b/experimental/svg/model/SkSVGAttribute.h
index d2f0cf2..cc3e7a0 100644
--- a/experimental/svg/model/SkSVGAttribute.h
+++ b/experimental/svg/model/SkSVGAttribute.h
@@ -18,6 +18,7 @@
     kFill,
     kFillOpacity,
     kHeight,
+    kOpacity,
     kPoints,
     kRx,
     kRy,
@@ -48,6 +49,8 @@
     SkTLazy<SkSVGLineJoin>   fStrokeLineJoin;
     SkTLazy<SkSVGNumberType> fStrokeOpacity;
     SkTLazy<SkSVGLength>     fStrokeWidth;
+
+    SkTLazy<SkSVGNumberType> fOpacity;
 };
 
 #endif // SkSVGAttribute_DEFINED
diff --git a/experimental/svg/model/SkSVGDOM.cpp b/experimental/svg/model/SkSVGDOM.cpp
index c9d9e93..8e2667a 100644
--- a/experimental/svg/model/SkSVGDOM.cpp
+++ b/experimental/svg/model/SkSVGDOM.cpp
@@ -217,6 +217,7 @@
     { "fill"           , { SkSVGAttribute::kFill          , SetPaintAttribute     }},
     { "fill-opacity"   , { SkSVGAttribute::kFillOpacity   , SetNumberAttribute    }},
     { "height"         , { SkSVGAttribute::kHeight        , SetLengthAttribute    }},
+    { "opacity"        , { SkSVGAttribute::kOpacity       , SetNumberAttribute    }},
     { "points"         , { SkSVGAttribute::kPoints        , SetPointsAttribute    }},
     { "rx"             , { SkSVGAttribute::kRx            , SetLengthAttribute    }},
     { "ry"             , { SkSVGAttribute::kRy            , SetLengthAttribute    }},
diff --git a/experimental/svg/model/SkSVGNode.cpp b/experimental/svg/model/SkSVGNode.cpp
index a039b59..5a73ace 100644
--- a/experimental/svg/model/SkSVGNode.cpp
+++ b/experimental/svg/model/SkSVGNode.cpp
@@ -42,6 +42,11 @@
         SkSVGNumberType(SkTPin<SkScalar>(opacity.value(), 0, 1)));
 }
 
+void SkSVGNode::setOpacity(const SkSVGNumberType& opacity) {
+    fPresentationAttributes.fOpacity.set(
+        SkSVGNumberType(SkTPin<SkScalar>(opacity.value(), 0, 1)));
+}
+
 void SkSVGNode::setStroke(const SkSVGPaint& svgPaint) {
     fPresentationAttributes.fStroke.set(svgPaint);
 }
@@ -67,6 +72,11 @@
             this->setFillOpacity(*opacity);
         }
         break;
+    case SkSVGAttribute::kOpacity:
+        if (const SkSVGNumberValue* opacity = v.as<SkSVGNumberValue>()) {
+            this->setOpacity(*opacity);
+        }
+        break;
     case SkSVGAttribute::kStroke:
         if (const SkSVGPaintValue* paint = v.as<SkSVGPaintValue>()) {
             this->setStroke(*paint);
diff --git a/experimental/svg/model/SkSVGNode.h b/experimental/svg/model/SkSVGNode.h
index 8ffc6f9..0f95d77 100644
--- a/experimental/svg/model/SkSVGNode.h
+++ b/experimental/svg/model/SkSVGNode.h
@@ -39,6 +39,7 @@
 
     void setFill(const SkSVGPaint&);
     void setFillOpacity(const SkSVGNumberType&);
+    void setOpacity(const SkSVGNumberType&);
     void setStroke(const SkSVGPaint&);
     void setStrokeOpacity(const SkSVGNumberType&);
     void setStrokeWidth(const SkSVGLength&);
diff --git a/experimental/svg/model/SkSVGRenderContext.cpp b/experimental/svg/model/SkSVGRenderContext.cpp
index ee92c47..8ad8814 100644
--- a/experimental/svg/model/SkSVGRenderContext.cpp
+++ b/experimental/svg/model/SkSVGRenderContext.cpp
@@ -224,6 +224,15 @@
     ApplyLazyInheritedAttribute(StrokeWidth);
 
 #undef ApplyLazyInheritedAttribute
+
+    // Uninherited attributes.  Only apply to the current context.
+
+    if (auto* opacity = attrs.fOpacity.getMaybeNull()) {
+        SkPaint opacityPaint;
+        opacityPaint.setAlpha(static_cast<uint8_t>(opacity->value() * 255));
+        // Balanced in the destructor, via restoreToCount().
+        fCanvas->saveLayer(nullptr, &opacityPaint);
+    }
 }
 
 const SkPaint* SkSVGRenderContext::fillPaint() const {
diff --git a/infra/bots/recipes/swarm_test.py b/infra/bots/recipes/swarm_test.py
index 2be1195..5b9d993 100644
--- a/infra/bots/recipes/swarm_test.py
+++ b/infra/bots/recipes/swarm_test.py
@@ -259,6 +259,16 @@
     blacklist.extend([   '2ndpic-8888', 'gm', '_', test])
     blacklist.extend(['serialize-8888', 'gm', '_', test])
 
+  # SaveLayerDrawRestoreNooper diffs
+  for test in ['car.svg',
+               'gallardo.svg',
+               'rg1024_green_grapes.svg',
+               'Seal_of_Kansas.svg']:
+    blacklist.extend([       'sp-8888', 'svg', '_', test])
+    blacklist.extend([      'pic-8888', 'svg', '_', test])
+    blacklist.extend([   '2ndpic-8888', 'svg', '_', test])
+    blacklist.extend(['serialize-8888', 'svg', '_', test])
+
   # Extensions for RAW images
   r = ["arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw",
        "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW"]