[svg] Implement 'display:none'

The full 'display' presentation attribute [1] has a number of settings
that we likely don't want to support. However, 'display:none' has some
practical uses and is easy enough to support. This progresses some
local tests as well as a few W3C tests.

[1] https://www.w3.org/TR/SVG11/painting.html#DisplayProperty

Bug: skia:10842
Change-Id: I60fef959fb45c3cfb229b85b720dfa69fc458bc3
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/403438
Commit-Queue: Tyler Denniston <tdenniston@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/modules/svg/include/SkSVGAttribute.h b/modules/svg/include/SkSVGAttribute.h
index c27bce6..d699663 100644
--- a/modules/svg/include/SkSVGAttribute.h
+++ b/modules/svg/include/SkSVGAttribute.h
@@ -100,6 +100,7 @@
     // uninherited
     SkSVGProperty<SkSVGNumberType, false> fOpacity;
     SkSVGProperty<SkSVGFuncIRI   , false> fClipPath;
+    SkSVGProperty<SkSVGDisplay   , false> fDisplay;
     SkSVGProperty<SkSVGFuncIRI   , false> fMask;
     SkSVGProperty<SkSVGFuncIRI   , false> fFilter;
     SkSVGProperty<SkSVGColor     , false> fStopColor;
diff --git a/modules/svg/include/SkSVGNode.h b/modules/svg/include/SkSVGNode.h
index 357050f..8079c85 100644
--- a/modules/svg/include/SkSVGNode.h
+++ b/modules/svg/include/SkSVGNode.h
@@ -135,6 +135,7 @@
 
     // not inherited
     SVG_PRES_ATTR(ClipPath                 , SkSVGFuncIRI   , false)
+    SVG_PRES_ATTR(Display                  , SkSVGDisplay   , false)
     SVG_PRES_ATTR(Mask                     , SkSVGFuncIRI   , false)
     SVG_PRES_ATTR(Filter                   , SkSVGFuncIRI   , false)
     SVG_PRES_ATTR(Opacity                  , SkSVGNumberType, false)
diff --git a/modules/svg/include/SkSVGTypes.h b/modules/svg/include/SkSVGTypes.h
index 4cc2cb2..7e0393a 100644
--- a/modules/svg/include/SkSVGTypes.h
+++ b/modules/svg/include/SkSVGTypes.h
@@ -682,4 +682,10 @@
     kLinearRGB,
 };
 
+// https://www.w3.org/TR/SVG11/painting.html#DisplayProperty
+enum class SkSVGDisplay {
+    kInline,
+    kNone,
+};
+
 #endif // SkSVGTypes_DEFINED
diff --git a/modules/svg/src/SkSVGAttribute.cpp b/modules/svg/src/SkSVGAttribute.cpp
index f636adb..ac99e64 100644
--- a/modules/svg/src/SkSVGAttribute.cpp
+++ b/modules/svg/src/SkSVGAttribute.cpp
@@ -36,6 +36,8 @@
     result.fFontWeight.init(SkSVGFontWeight::Type::kNormal);
     result.fTextAnchor.init(SkSVGTextAnchor::Type::kStart);
 
+    result.fDisplay.init(SkSVGDisplay::kInline);
+
     result.fStopColor.set(SkSVGColor(SK_ColorBLACK));
     result.fStopOpacity.set(SkSVGNumberType(1));
     result.fFloodColor.set(SkSVGColor(SK_ColorBLACK));
diff --git a/modules/svg/src/SkSVGAttributeParser.cpp b/modules/svg/src/SkSVGAttributeParser.cpp
index 6fdb90d..f1e412d 100644
--- a/modules/svg/src/SkSVGAttributeParser.cpp
+++ b/modules/svg/src/SkSVGAttributeParser.cpp
@@ -963,3 +963,26 @@
 
     return this->parseEnumMap(gColorspaceMap, colorspace) && this->parseEOSToken();
 }
+
+// https://www.w3.org/TR/SVG11/painting.html#DisplayProperty
+template <>
+bool SkSVGAttributeParser::parse(SkSVGDisplay* display) {
+    static const struct {
+        SkSVGDisplay fType;
+        const char*  fName;
+    } gDisplayInfo[] = {
+        { SkSVGDisplay::kInline, "inline" },
+        { SkSVGDisplay::kNone  , "none"   },
+    };
+
+    bool parsedValue = false;
+    for (const auto& parseInfo : gDisplayInfo) {
+        if (this->parseExpectedStringToken(parseInfo.fName)) {
+            *display = SkSVGDisplay(parseInfo.fType);
+            parsedValue = true;
+            break;
+        }
+    }
+
+    return parsedValue && this->parseEOSToken();
+}
diff --git a/modules/svg/src/SkSVGNode.cpp b/modules/svg/src/SkSVGNode.cpp
index 9f3a3e6..13aefa5 100644
--- a/modules/svg/src/SkSVGNode.cpp
+++ b/modules/svg/src/SkSVGNode.cpp
@@ -63,9 +63,13 @@
     ctx->applyPresentationAttributes(fPresentationAttributes,
                                      this->hasChildren() ? 0 : SkSVGRenderContext::kLeaf);
 
-    // visibility:hidden disables rendering
+    // visibility:hidden and display:none disable rendering.
+    // TODO: if display is not a value (true when display="inherit"), we currently
+    //   ignore it. Eventually we should be able to add SkASSERT(display.isValue()).
     const auto visibility = ctx->presentationContext().fInherited.fVisibility->type();
-    return visibility != SkSVGVisibility::Type::kHidden;
+    const auto display = fPresentationAttributes.fDisplay;  // display is uninherited
+    return visibility != SkSVGVisibility::Type::kHidden &&
+           (!display.isValue() || *display != SkSVGDisplay::kNone);
 }
 
 void SkSVGNode::setAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
@@ -94,6 +98,7 @@
            || PARSE_AND_SET("color"                      , Color)
            || PARSE_AND_SET("color-interpolation"        , ColorInterpolation)
            || PARSE_AND_SET("color-interpolation-filters", ColorInterpolationFilters)
+           || PARSE_AND_SET("display"                    , Display)
            || PARSE_AND_SET("fill"                       , Fill)
            || PARSE_AND_SET("fill-opacity"               , FillOpacity)
            || PARSE_AND_SET("fill-rule"                  , FillRule)