[svg] Add gradientUnits attribute, value, and parsing
Specifying gradientUnits will allow gradient coordinates to be specified
relative to object bounding boxes, as seen in test 'coords-units-01-b'.
Not yet used with this CL.
Bug: skia:10842
Change-Id: I6038cf3995a94c7e3a7ac73ad8305872353a403c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/328977
Reviewed-by: Florin Malita <fmalita@chromium.org>
Auto-Submit: Tyler Denniston <tdenniston@google.com>
Commit-Queue: Tyler Denniston <tdenniston@google.com>
diff --git a/modules/svg/include/SkSVGAttribute.h b/modules/svg/include/SkSVGAttribute.h
index cd64e91..bd8204a 100644
--- a/modules/svg/include/SkSVGAttribute.h
+++ b/modules/svg/include/SkSVGAttribute.h
@@ -29,6 +29,7 @@
kFontWeight,
kFx, // <radialGradient>: focal point x position
kFy, // <radialGradient>: focal point y position
+ kGradientUnits,
kGradientTransform,
kHeight,
kHref,
diff --git a/modules/svg/include/SkSVGAttributeParser.h b/modules/svg/include/SkSVGAttributeParser.h
index 1ac9aac..1876dea 100644
--- a/modules/svg/include/SkSVGAttributeParser.h
+++ b/modules/svg/include/SkSVGAttributeParser.h
@@ -29,6 +29,7 @@
bool parseIRI(SkSVGStringType*);
bool parseSpreadMethod(SkSVGSpreadMethod*);
bool parseStopColor(SkSVGStopColor*);
+ bool parseGradientUnits(SkSVGGradientUnits*);
bool parseVisibility(SkSVGVisibility*);
bool parseDashArray(SkSVGDashArray*);
diff --git a/modules/svg/include/SkSVGGradient.h b/modules/svg/include/SkSVGGradient.h
index 469bfe6..301a698 100644
--- a/modules/svg/include/SkSVGGradient.h
+++ b/modules/svg/include/SkSVGGradient.h
@@ -23,6 +23,7 @@
void setHref(const SkSVGStringType&);
void setGradientTransform(const SkSVGTransformType&);
void setSpreadMethod(const SkSVGSpreadMethod&);
+ void setGradientUnits(const SkSVGGradientUnits&);
protected:
explicit SkSVGGradient(SkSVGTag t) : INHERITED(t) {}
@@ -44,6 +45,7 @@
SkSVGStringType fHref;
SkSVGTransformType fGradientTransform = SkSVGTransformType(SkMatrix::I());
SkSVGSpreadMethod fSpreadMethod = SkSVGSpreadMethod(SkSVGSpreadMethod::Type::kPad);
+ SkSVGGradientUnits fGradientUnits = SkSVGGradientUnits(SkSVGGradientUnits::Type::kUserSpaceOnUse);
using INHERITED = SkSVGHiddenContainer;
};
diff --git a/modules/svg/include/SkSVGTypes.h b/modules/svg/include/SkSVGTypes.h
index e0ea73e..5f535de 100644
--- a/modules/svg/include/SkSVGTypes.h
+++ b/modules/svg/include/SkSVGTypes.h
@@ -308,6 +308,27 @@
SkSVGColorType fColor;
};
+class SkSVGGradientUnits {
+public:
+ enum class Type {
+ kUserSpaceOnUse,
+ kObjectBoundingBox,
+ };
+
+ SkSVGGradientUnits() : fType(Type::kUserSpaceOnUse) {}
+ explicit SkSVGGradientUnits(Type t) : fType(t) {}
+
+ bool operator==(const SkSVGGradientUnits& other) const {
+ return fType == other.fType;
+ }
+ bool operator!=(const SkSVGGradientUnits& other) const { return !(*this == other); }
+
+ Type type() const { return fType; }
+
+private:
+ Type fType;
+};
+
class SkSVGFontFamily {
public:
enum class Type {
diff --git a/modules/svg/include/SkSVGValue.h b/modules/svg/include/SkSVGValue.h
index 0144a70..9c9f251 100644
--- a/modules/svg/include/SkSVGValue.h
+++ b/modules/svg/include/SkSVGValue.h
@@ -26,6 +26,7 @@
kFontSize,
kFontStyle,
kFontWeight,
+ kGradientUnits,
kLength,
kLineCap,
kLineJoin,
@@ -95,6 +96,8 @@
using SkSVGSpreadMethodValue = SkSVGWrapperValue<SkSVGSpreadMethod ,
SkSVGValue::Type::kSpreadMethod>;
using SkSVGStopColorValue = SkSVGWrapperValue<SkSVGStopColor , SkSVGValue::Type::kStopColor >;
+using SkSVGGradientUnitsValue= SkSVGWrapperValue<SkSVGGradientUnits,
+ SkSVGValue::Type::kGradientUnits>;
using SkSVGVisibilityValue = SkSVGWrapperValue<SkSVGVisibility , SkSVGValue::Type::kVisibility>;
using SkSVGDashArrayValue = SkSVGWrapperValue<SkSVGDashArray , SkSVGValue::Type::kDashArray >;
diff --git a/modules/svg/src/SkSVGAttributeParser.cpp b/modules/svg/src/SkSVGAttributeParser.cpp
index 18acdf4..8cfc6c3 100644
--- a/modules/svg/src/SkSVGAttributeParser.cpp
+++ b/modules/svg/src/SkSVGAttributeParser.cpp
@@ -597,6 +597,19 @@
return parsedValue && this->parseEOSToken();
}
+// https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementGradientUnitsAttribute
+bool SkSVGAttributeParser::parseGradientUnits(SkSVGGradientUnits* gradientUnits) {
+ bool parsedValue = false;
+ if (this->parseExpectedStringToken("userSpaceOnUse")) {
+ *gradientUnits = SkSVGGradientUnits(SkSVGGradientUnits::Type::kUserSpaceOnUse);
+ parsedValue = true;
+ } else if (this->parseExpectedStringToken("objectBoundingBox")) {
+ *gradientUnits = SkSVGGradientUnits(SkSVGGradientUnits::Type::kObjectBoundingBox);
+ parsedValue = true;
+ }
+ return parsedValue && this->parseEOSToken();
+}
+
// https://www.w3.org/TR/SVG11/shapes.html#PolygonElementPointsAttribute
bool SkSVGAttributeParser::parsePoints(SkSVGPointsType* points) {
SkTDArray<SkPoint> pts;
diff --git a/modules/svg/src/SkSVGDOM.cpp b/modules/svg/src/SkSVGDOM.cpp
index 8ab5ade..58f1ef0 100644
--- a/modules/svg/src/SkSVGDOM.cpp
+++ b/modules/svg/src/SkSVGDOM.cpp
@@ -200,6 +200,18 @@
return true;
}
+bool SetGradientUnitsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
+ const char* stringValue) {
+ SkSVGGradientUnits gradientUnits;
+ SkSVGAttributeParser parser(stringValue);
+ if (!parser.parseGradientUnits(&gradientUnits)) {
+ return false;
+ }
+
+ node->setAttribute(attr, SkSVGGradientUnitsValue(gradientUnits));
+ return true;
+}
+
bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
const char* stringValue) {
SkSVGPointsType points;
@@ -391,6 +403,7 @@
{ "fx" , { SkSVGAttribute::kFx , SetLengthAttribute }},
{ "fy" , { SkSVGAttribute::kFy , SetLengthAttribute }},
{ "gradientTransform", { SkSVGAttribute::kGradientTransform, SetTransformAttribute }},
+ { "gradientUnits" , { SkSVGAttribute::kGradientUnits , SetGradientUnitsAttribute}},
{ "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
{ "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
{ "opacity" , { SkSVGAttribute::kOpacity , SetNumberAttribute }},
diff --git a/modules/svg/src/SkSVGGradient.cpp b/modules/svg/src/SkSVGGradient.cpp
index 656920c..66d0d38 100644
--- a/modules/svg/src/SkSVGGradient.cpp
+++ b/modules/svg/src/SkSVGGradient.cpp
@@ -23,6 +23,10 @@
fSpreadMethod = spread;
}
+void SkSVGGradient::setGradientUnits(const SkSVGGradientUnits& gradientUnits) {
+ fGradientUnits = gradientUnits;
+}
+
void SkSVGGradient::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
switch (attr) {
case SkSVGAttribute::kGradientTransform:
@@ -40,6 +44,11 @@
this->setSpreadMethod(*spread);
}
break;
+ case SkSVGAttribute::kGradientUnits:
+ if (const auto* gradientUnits = v.as<SkSVGGradientUnitsValue>()) {
+ this->setGradientUnits(*gradientUnits);
+ }
+ break;
default:
this->INHERITED::onSetAttribute(attr, v);
}