aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/svg
diff options
context:
space:
mode:
authorGravatar fmalita <fmalita@chromium.org>2016-09-13 12:56:11 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-09-13 12:56:11 -0700
commitcecd617a4297ffdcec632ca7e2ed1e6b61665e04 (patch)
tree48e32288114528e7085bf6aa0190653e7ad0bf99 /experimental/svg
parent649985a530c39afcda23d1f188fa2fc92df3ac56 (diff)
[SVGDom] Linear gradient 'spreadMethod' support
R=stephana@google.com,robertphillips@google.com GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2337203002 Review-Url: https://codereview.chromium.org/2337203002
Diffstat (limited to 'experimental/svg')
-rw-r--r--experimental/svg/model/SkSVGAttribute.h1
-rw-r--r--experimental/svg/model/SkSVGAttributeParser.cpp23
-rw-r--r--experimental/svg/model/SkSVGAttributeParser.h1
-rw-r--r--experimental/svg/model/SkSVGDOM.cpp73
-rw-r--r--experimental/svg/model/SkSVGLinearGradient.cpp20
-rw-r--r--experimental/svg/model/SkSVGLinearGradient.h4
-rw-r--r--experimental/svg/model/SkSVGTypes.h24
-rw-r--r--experimental/svg/model/SkSVGValue.h25
8 files changed, 127 insertions, 44 deletions
diff --git a/experimental/svg/model/SkSVGAttribute.h b/experimental/svg/model/SkSVGAttribute.h
index ce06b1e8a6..13a6041b4b 100644
--- a/experimental/svg/model/SkSVGAttribute.h
+++ b/experimental/svg/model/SkSVGAttribute.h
@@ -27,6 +27,7 @@ enum class SkSVGAttribute {
kR, // <circle>: radius
kRx, // <ellipse>,<rect>: horizontal (corner) radius
kRy, // <ellipse>,<rect>: vertical (corner) radius
+ kSpreadMethod,
kStopColor,
kStopOpacity,
kStroke,
diff --git a/experimental/svg/model/SkSVGAttributeParser.cpp b/experimental/svg/model/SkSVGAttributeParser.cpp
index 9d2d6b8136..04b050828a 100644
--- a/experimental/svg/model/SkSVGAttributeParser.cpp
+++ b/experimental/svg/model/SkSVGAttributeParser.cpp
@@ -491,6 +491,29 @@ bool SkSVGAttributeParser::parseLineJoin(SkSVGLineJoin* join) {
return parsedValue && this->parseEOSToken();
}
+// https://www.w3.org/TR/SVG/pservers.html#LinearGradientElementSpreadMethodAttribute
+bool SkSVGAttributeParser::parseSpreadMethod(SkSVGSpreadMethod* spread) {
+ static const struct {
+ SkSVGSpreadMethod::Type fType;
+ const char* fName;
+ } gSpreadInfo[] = {
+ { SkSVGSpreadMethod::Type::kPad , "pad" },
+ { SkSVGSpreadMethod::Type::kReflect, "reflect" },
+ { SkSVGSpreadMethod::Type::kRepeat , "repeat" },
+ };
+
+ bool parsedValue = false;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gSpreadInfo); ++i) {
+ if (this->parseExpectedStringToken(gSpreadInfo[i].fName)) {
+ *spread = SkSVGSpreadMethod(gSpreadInfo[i].fType);
+ parsedValue = true;
+ break;
+ }
+ }
+
+ return parsedValue && this->parseEOSToken();
+}
+
// https://www.w3.org/TR/SVG/shapes.html#PolygonElementPointsAttribute
bool SkSVGAttributeParser::parsePoints(SkSVGPointsType* points) {
SkTDArray<SkPoint> pts;
diff --git a/experimental/svg/model/SkSVGAttributeParser.h b/experimental/svg/model/SkSVGAttributeParser.h
index c1700a8e77..9d6939b2e2 100644
--- a/experimental/svg/model/SkSVGAttributeParser.h
+++ b/experimental/svg/model/SkSVGAttributeParser.h
@@ -24,6 +24,7 @@ public:
bool parseLineJoin(SkSVGLineJoin*);
bool parsePoints(SkSVGPointsType*);
bool parseIRI(SkSVGStringType*);
+ bool parseSpreadMethod(SkSVGSpreadMethod*);
private:
// Stack-only
diff --git a/experimental/svg/model/SkSVGDOM.cpp b/experimental/svg/model/SkSVGDOM.cpp
index d6e4f4c9bd..26944737f1 100644
--- a/experimental/svg/model/SkSVGDOM.cpp
+++ b/experimental/svg/model/SkSVGDOM.cpp
@@ -149,6 +149,18 @@ bool SetLineJoinAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
return true;
}
+bool SetSpreadMethodAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
+ const char* stringValue) {
+ SkSVGSpreadMethod spread;
+ SkSVGAttributeParser parser(stringValue);
+ if (!parser.parseSpreadMethod(&spread)) {
+ return false;
+ }
+
+ node->setAttribute(attr, SkSVGSpreadMethodValue(spread));
+ return true;
+}
+
bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
const char* stringValue) {
SkSVGPointsType points;
@@ -239,36 +251,37 @@ struct AttrParseInfo {
};
SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
- { "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
- { "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
- { "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
- { "fill" , { SkSVGAttribute::kFill , SetPaintAttribute }},
- { "fill-opacity" , { SkSVGAttribute::kFillOpacity , SetNumberAttribute }},
- { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
- { "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
- { "opacity" , { SkSVGAttribute::kOpacity , SetNumberAttribute }},
- { "points" , { SkSVGAttribute::kPoints , SetPointsAttribute }},
- { "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
- { "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
- { "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
- { "stop-color" , { SkSVGAttribute::kStopColor , SetColorAttribute }},
- { "stop-opacity" , { SkSVGAttribute::kStopOpacity , SetNumberAttribute }},
- { "stroke" , { SkSVGAttribute::kStroke , SetPaintAttribute }},
- { "stroke-linecap" , { SkSVGAttribute::kStrokeLineCap , SetLineCapAttribute }},
- { "stroke-linejoin", { SkSVGAttribute::kStrokeLineJoin, SetLineJoinAttribute }},
- { "stroke-opacity" , { SkSVGAttribute::kStrokeOpacity , SetNumberAttribute }},
- { "stroke-width" , { SkSVGAttribute::kStrokeWidth , SetLengthAttribute }},
- { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
- { "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
- { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
- { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
- { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
- { "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }},
- { "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }},
- { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }},
- { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
- { "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }},
- { "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }},
+ { "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
+ { "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
+ { "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
+ { "fill" , { SkSVGAttribute::kFill , SetPaintAttribute }},
+ { "fill-opacity" , { SkSVGAttribute::kFillOpacity , SetNumberAttribute }},
+ { "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
+ { "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
+ { "opacity" , { SkSVGAttribute::kOpacity , SetNumberAttribute }},
+ { "points" , { SkSVGAttribute::kPoints , SetPointsAttribute }},
+ { "r" , { SkSVGAttribute::kR , SetLengthAttribute }},
+ { "rx" , { SkSVGAttribute::kRx , SetLengthAttribute }},
+ { "ry" , { SkSVGAttribute::kRy , SetLengthAttribute }},
+ { "spreadMethod" , { SkSVGAttribute::kSpreadMethod , SetSpreadMethodAttribute }},
+ { "stop-color" , { SkSVGAttribute::kStopColor , SetColorAttribute }},
+ { "stop-opacity" , { SkSVGAttribute::kStopOpacity , SetNumberAttribute }},
+ { "stroke" , { SkSVGAttribute::kStroke , SetPaintAttribute }},
+ { "stroke-linecap" , { SkSVGAttribute::kStrokeLineCap , SetLineCapAttribute }},
+ { "stroke-linejoin", { SkSVGAttribute::kStrokeLineJoin, SetLineJoinAttribute }},
+ { "stroke-opacity" , { SkSVGAttribute::kStrokeOpacity , SetNumberAttribute }},
+ { "stroke-width" , { SkSVGAttribute::kStrokeWidth , SetLengthAttribute }},
+ { "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
+ { "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
+ { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
+ { "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
+ { "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
+ { "x1" , { SkSVGAttribute::kX1 , SetLengthAttribute }},
+ { "x2" , { SkSVGAttribute::kX2 , SetLengthAttribute }},
+ { "xlink:href" , { SkSVGAttribute::kHref , SetIRIAttribute }},
+ { "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
+ { "y1" , { SkSVGAttribute::kY1 , SetLengthAttribute }},
+ { "y2" , { SkSVGAttribute::kY2 , SetLengthAttribute }},
};
SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
diff --git a/experimental/svg/model/SkSVGLinearGradient.cpp b/experimental/svg/model/SkSVGLinearGradient.cpp
index 20c27f540c..289c5e3276 100644
--- a/experimental/svg/model/SkSVGLinearGradient.cpp
+++ b/experimental/svg/model/SkSVGLinearGradient.cpp
@@ -17,6 +17,10 @@ void SkSVGLinearGradient::setHref(const SkSVGStringType& href) {
fHref = std::move(href);
}
+void SkSVGLinearGradient::setSpreadMethod(const SkSVGSpreadMethod& spread) {
+ fSpreadMethod = spread;
+}
+
void SkSVGLinearGradient::setX1(const SkSVGLength& x1) {
fX1 = x1;
}
@@ -40,6 +44,11 @@ void SkSVGLinearGradient::onSetAttribute(SkSVGAttribute attr, const SkSVGValue&
this->setHref(*href);
}
break;
+ case SkSVGAttribute::kSpreadMethod:
+ if (const auto* spread = v.as<SkSVGSpreadMethodValue>()) {
+ this->setSpreadMethod(*spread);
+ }
+ break;
case SkSVGAttribute::kX1:
if (const auto* x1 = v.as<SkSVGLengthValue>()) {
this->setX1(*x1);
@@ -110,10 +119,17 @@ bool SkSVGLinearGradient::onAsPaint(const SkSVGRenderContext& ctx, SkPaint* pain
// * stop (lazy?) sorting
// * href loop detection
// * href attribute inheritance (not just color stops)
- // * spreadMethods support
// * objectBoundingBox units support
+ static_assert(static_cast<SkShader::TileMode>(SkSVGSpreadMethod::Type::kPad) ==
+ SkShader::kClamp_TileMode, "SkSVGSpreadMethod::Type is out of sync");
+ static_assert(static_cast<SkShader::TileMode>(SkSVGSpreadMethod::Type::kRepeat) ==
+ SkShader::kRepeat_TileMode, "SkSVGSpreadMethod::Type is out of sync");
+ static_assert(static_cast<SkShader::TileMode>(SkSVGSpreadMethod::Type::kReflect) ==
+ SkShader::kMirror_TileMode, "SkSVGSpreadMethod::Type is out of sync");
+ const auto tileMode = static_cast<SkShader::TileMode>(fSpreadMethod.type());
+
paint->setShader(SkGradientShader::MakeLinear(pts, colors.begin(), pos.begin(), colors.count(),
- SkShader::kClamp_TileMode));
+ tileMode));
return true;
}
diff --git a/experimental/svg/model/SkSVGLinearGradient.h b/experimental/svg/model/SkSVGLinearGradient.h
index 1a2e332baf..e12b5245e8 100644
--- a/experimental/svg/model/SkSVGLinearGradient.h
+++ b/experimental/svg/model/SkSVGLinearGradient.h
@@ -19,6 +19,7 @@ public:
}
void setHref(const SkSVGStringType&);
+ void setSpreadMethod(const SkSVGSpreadMethod&);
void setX1(const SkSVGLength&);
void setY1(const SkSVGLength&);
void setX2(const SkSVGLength&);
@@ -41,7 +42,8 @@ private:
SkSVGLength fX2 = SkSVGLength(100, SkSVGLength::Unit::kPercentage);
SkSVGLength fY2 = SkSVGLength(0 , SkSVGLength::Unit::kPercentage);
- SkSVGStringType fHref;
+ SkSVGStringType fHref;
+ SkSVGSpreadMethod fSpreadMethod = SkSVGSpreadMethod(SkSVGSpreadMethod::Type::kPad);
typedef SkSVGHiddenContainer INHERITED;
};
diff --git a/experimental/svg/model/SkSVGTypes.h b/experimental/svg/model/SkSVGTypes.h
index b2343a15e4..b07f9a2c8c 100644
--- a/experimental/svg/model/SkSVGTypes.h
+++ b/experimental/svg/model/SkSVGTypes.h
@@ -167,4 +167,28 @@ private:
Type fType;
};
+class SkSVGSpreadMethod {
+public:
+ // These values must match Skia's SkShader::TileMode enum.
+ enum class Type {
+ kPad, // kClamp_TileMode
+ kRepeat, // kRepeat_TileMode
+ kReflect, // kMirror_TileMode
+ };
+
+ constexpr SkSVGSpreadMethod() : fType(Type::kPad) {}
+ constexpr explicit SkSVGSpreadMethod(Type t) : fType(t) {}
+
+ SkSVGSpreadMethod(const SkSVGSpreadMethod&) = default;
+ SkSVGSpreadMethod& operator=(const SkSVGSpreadMethod&) = default;
+
+ bool operator==(const SkSVGSpreadMethod& other) const { return fType == other.fType; }
+ bool operator!=(const SkSVGSpreadMethod& other) const { return !(*this == other); }
+
+ Type type() const { return fType; }
+
+private:
+ Type fType;
+};
+
#endif // SkSVGTypes_DEFINED
diff --git a/experimental/svg/model/SkSVGValue.h b/experimental/svg/model/SkSVGValue.h
index e4673e9150..0160af0371 100644
--- a/experimental/svg/model/SkSVGValue.h
+++ b/experimental/svg/model/SkSVGValue.h
@@ -25,6 +25,7 @@ public:
kPaint,
kPath,
kPoints,
+ kSpreadMethod,
kString,
kTransform,
kViewBox,
@@ -68,16 +69,18 @@ private:
typedef SkSVGValue INHERITED;
};
-using SkSVGColorValue = SkSVGWrapperValue<SkSVGColorType , SkSVGValue::Type::kColor >;
-using SkSVGLengthValue = SkSVGWrapperValue<SkSVGLength , SkSVGValue::Type::kLength >;
-using SkSVGPathValue = SkSVGWrapperValue<SkPath , SkSVGValue::Type::kPath >;
-using SkSVGTransformValue = SkSVGWrapperValue<SkSVGTransformType, SkSVGValue::Type::kTransform>;
-using SkSVGViewBoxValue = SkSVGWrapperValue<SkSVGViewBoxType , SkSVGValue::Type::kViewBox >;
-using SkSVGPaintValue = SkSVGWrapperValue<SkSVGPaint , SkSVGValue::Type::kPaint >;
-using SkSVGLineCapValue = SkSVGWrapperValue<SkSVGLineCap , SkSVGValue::Type::kLineCap >;
-using SkSVGLineJoinValue = SkSVGWrapperValue<SkSVGLineJoin , SkSVGValue::Type::kLineJoin >;
-using SkSVGNumberValue = SkSVGWrapperValue<SkSVGNumberType , SkSVGValue::Type::kNumber >;
-using SkSVGPointsValue = SkSVGWrapperValue<SkSVGPointsType , SkSVGValue::Type::kPoints >;
-using SkSVGStringValue = SkSVGWrapperValue<SkSVGStringType , SkSVGValue::Type::kString >;
+using SkSVGColorValue = SkSVGWrapperValue<SkSVGColorType , SkSVGValue::Type::kColor >;
+using SkSVGLengthValue = SkSVGWrapperValue<SkSVGLength , SkSVGValue::Type::kLength >;
+using SkSVGPathValue = SkSVGWrapperValue<SkPath , SkSVGValue::Type::kPath >;
+using SkSVGTransformValue = SkSVGWrapperValue<SkSVGTransformType, SkSVGValue::Type::kTransform>;
+using SkSVGViewBoxValue = SkSVGWrapperValue<SkSVGViewBoxType , SkSVGValue::Type::kViewBox >;
+using SkSVGPaintValue = SkSVGWrapperValue<SkSVGPaint , SkSVGValue::Type::kPaint >;
+using SkSVGLineCapValue = SkSVGWrapperValue<SkSVGLineCap , SkSVGValue::Type::kLineCap >;
+using SkSVGLineJoinValue = SkSVGWrapperValue<SkSVGLineJoin , SkSVGValue::Type::kLineJoin >;
+using SkSVGNumberValue = SkSVGWrapperValue<SkSVGNumberType , SkSVGValue::Type::kNumber >;
+using SkSVGPointsValue = SkSVGWrapperValue<SkSVGPointsType , SkSVGValue::Type::kPoints >;
+using SkSVGStringValue = SkSVGWrapperValue<SkSVGStringType , SkSVGValue::Type::kString >;
+using SkSVGSpreadMethodValue = SkSVGWrapperValue<SkSVGSpreadMethod ,
+ SkSVGValue::Type::kSpreadMethod>;
#endif // SkSVGValue_DEFINED