aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2017-10-13 14:07:44 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-10-13 19:14:39 +0000
commitf543a60ef06a6b0ccb5a0a85ca5415021c81c9ee (patch)
treef2a3d3dd48e360e045e01385d86fa7833de20d3b
parent770db22a553e87d6f3e40db72c5871b1d8a9ec91 (diff)
[SVGDom] Add 'stroke-dasharray' support
https://www.w3.org/TR/SVG/painting.html#StrokeDasharrayProperty Change-Id: I9a63ebbd958d661c865ed405570b86cca68f63bf Reviewed-on: https://skia-review.googlesource.com/59700 Commit-Queue: Florin Malita <fmalita@chromium.org> Reviewed-by: Robert Phillips <robertphillips@google.com>
-rw-r--r--experimental/svg/model/SkSVGAttribute.cpp1
-rw-r--r--experimental/svg/model/SkSVGAttribute.h2
-rw-r--r--experimental/svg/model/SkSVGAttributeParser.cpp30
-rw-r--r--experimental/svg/model/SkSVGAttributeParser.h1
-rw-r--r--experimental/svg/model/SkSVGDOM.cpp13
-rw-r--r--experimental/svg/model/SkSVGNode.cpp9
-rw-r--r--experimental/svg/model/SkSVGNode.h1
-rw-r--r--experimental/svg/model/SkSVGRenderContext.cpp34
-rw-r--r--experimental/svg/model/SkSVGTypes.h31
-rw-r--r--experimental/svg/model/SkSVGValue.h2
10 files changed, 124 insertions, 0 deletions
diff --git a/experimental/svg/model/SkSVGAttribute.cpp b/experimental/svg/model/SkSVGAttribute.cpp
index 89b57cd1da..41527f7497 100644
--- a/experimental/svg/model/SkSVGAttribute.cpp
+++ b/experimental/svg/model/SkSVGAttribute.cpp
@@ -16,6 +16,7 @@ SkSVGPresentationAttributes SkSVGPresentationAttributes::MakeInitial() {
result.fClipRule.set(SkSVGFillRule(SkSVGFillRule::Type::kNonZero));
result.fStroke.set(SkSVGPaint(SkSVGPaint::Type::kNone));
+ result.fStrokeDashArray.set(SkSVGDashArray(SkSVGDashArray::Type::kNone));
result.fStrokeLineCap.set(SkSVGLineCap(SkSVGLineCap::Type::kButt));
result.fStrokeLineJoin.set(SkSVGLineJoin(SkSVGLineJoin::Type::kMiter));
result.fStrokeMiterLimit.set(SkSVGNumberType(4));
diff --git a/experimental/svg/model/SkSVGAttribute.h b/experimental/svg/model/SkSVGAttribute.h
index bd2cf7d196..1650c3b913 100644
--- a/experimental/svg/model/SkSVGAttribute.h
+++ b/experimental/svg/model/SkSVGAttribute.h
@@ -38,6 +38,7 @@ enum class SkSVGAttribute {
kStopColor,
kStopOpacity,
kStroke,
+ kStrokeDashArray,
kStrokeOpacity,
kStrokeLineCap,
kStrokeLineJoin,
@@ -68,6 +69,7 @@ struct SkSVGPresentationAttributes {
SkTLazy<SkSVGFillRule> fClipRule;
SkTLazy<SkSVGPaint> fStroke;
+ SkTLazy<SkSVGDashArray> fStrokeDashArray;
SkTLazy<SkSVGLineCap> fStrokeLineCap;
SkTLazy<SkSVGLineJoin> fStrokeLineJoin;
SkTLazy<SkSVGNumberType> fStrokeMiterLimit;
diff --git a/experimental/svg/model/SkSVGAttributeParser.cpp b/experimental/svg/model/SkSVGAttributeParser.cpp
index aee15b394e..40a3f1a4a9 100644
--- a/experimental/svg/model/SkSVGAttributeParser.cpp
+++ b/experimental/svg/model/SkSVGAttributeParser.cpp
@@ -617,3 +617,33 @@ bool SkSVGAttributeParser::parseVisibility(SkSVGVisibility* visibility) {
return parsedValue && this->parseEOSToken();
}
+
+// https://www.w3.org/TR/SVG/painting.html#StrokeDasharrayProperty
+bool SkSVGAttributeParser::parseDashArray(SkSVGDashArray* dashArray) {
+ bool parsedValue = false;
+ if (this->parseExpectedStringToken("none")) {
+ *dashArray = SkSVGDashArray(SkSVGDashArray::Type::kNone);
+ parsedValue = true;
+ } else if (this->parseExpectedStringToken("inherit")) {
+ *dashArray = SkSVGDashArray(SkSVGDashArray::Type::kInherit);
+ parsedValue = true;
+ } else {
+ SkTDArray<SkSVGLength> dashes;
+ for (;;) {
+ SkSVGLength dash;
+ // parseLength() also consumes trailing separators.
+ if (!this->parseLength(&dash)) {
+ break;
+ }
+
+ dashes.push(dash);
+ parsedValue = true;
+ }
+
+ if (parsedValue) {
+ *dashArray = SkSVGDashArray(std::move(dashes));
+ }
+ }
+
+ return parsedValue && this->parseEOSToken();
+}
diff --git a/experimental/svg/model/SkSVGAttributeParser.h b/experimental/svg/model/SkSVGAttributeParser.h
index b2ac98f128..7d329c7a2b 100644
--- a/experimental/svg/model/SkSVGAttributeParser.h
+++ b/experimental/svg/model/SkSVGAttributeParser.h
@@ -28,6 +28,7 @@ public:
bool parseIRI(SkSVGStringType*);
bool parseSpreadMethod(SkSVGSpreadMethod*);
bool parseVisibility(SkSVGVisibility*);
+ bool parseDashArray(SkSVGDashArray*);
private:
// Stack-only
diff --git a/experimental/svg/model/SkSVGDOM.cpp b/experimental/svg/model/SkSVGDOM.cpp
index 28784c2875..b25a4d01e3 100644
--- a/experimental/svg/model/SkSVGDOM.cpp
+++ b/experimental/svg/model/SkSVGDOM.cpp
@@ -214,6 +214,18 @@ bool SetVisibilityAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
return true;
}
+bool SetDashArrayAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
+ const char* stringValue) {
+ SkSVGDashArray dashArray;
+ SkSVGAttributeParser parser(stringValue);
+ if (!parser.parseDashArray(&dashArray)) {
+ return false;
+ }
+
+ node->setAttribute(attr, SkSVGDashArrayValue(dashArray));
+ return true;
+}
+
SkString TrimmedString(const char* first, const char* last) {
SkASSERT(first);
SkASSERT(last);
@@ -316,6 +328,7 @@ SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
{ "stop-color" , { SkSVGAttribute::kStopColor , SetColorAttribute }},
{ "stop-opacity" , { SkSVGAttribute::kStopOpacity , SetNumberAttribute }},
{ "stroke" , { SkSVGAttribute::kStroke , SetPaintAttribute }},
+ { "stroke-dasharray" , { SkSVGAttribute::kStrokeDashArray , SetDashArrayAttribute }},
{ "stroke-linecap" , { SkSVGAttribute::kStrokeLineCap , SetLineCapAttribute }},
{ "stroke-linejoin" , { SkSVGAttribute::kStrokeLineJoin , SetLineJoinAttribute }},
{ "stroke-miterlimit", { SkSVGAttribute::kStrokeMiterLimit , SetNumberAttribute }},
diff --git a/experimental/svg/model/SkSVGNode.cpp b/experimental/svg/model/SkSVGNode.cpp
index ddde838f8e..07dc59c645 100644
--- a/experimental/svg/model/SkSVGNode.cpp
+++ b/experimental/svg/model/SkSVGNode.cpp
@@ -90,6 +90,10 @@ void SkSVGNode::setStroke(const SkSVGPaint& svgPaint) {
fPresentationAttributes.fStroke.set(svgPaint);
}
+void SkSVGNode::setStrokeDashArray(const SkSVGDashArray& dashArray) {
+ fPresentationAttributes.fStrokeDashArray.set(dashArray);
+}
+
void SkSVGNode::setStrokeOpacity(const SkSVGNumberType& opacity) {
fPresentationAttributes.fStrokeOpacity.set(
SkSVGNumberType(SkTPin<SkScalar>(opacity.value(), 0, 1)));
@@ -140,6 +144,11 @@ void SkSVGNode::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
this->setStroke(*paint);
}
break;
+ case SkSVGAttribute::kStrokeDashArray:
+ if (const SkSVGDashArrayValue* dashArray = v.as<SkSVGDashArrayValue>()) {
+ this->setStrokeDashArray(*dashArray);
+ }
+ break;
case SkSVGAttribute::kStrokeOpacity:
if (const SkSVGNumberValue* opacity = v.as<SkSVGNumberValue>()) {
this->setStrokeOpacity(*opacity);
diff --git a/experimental/svg/model/SkSVGNode.h b/experimental/svg/model/SkSVGNode.h
index 02c2caa86e..c8de2d75f2 100644
--- a/experimental/svg/model/SkSVGNode.h
+++ b/experimental/svg/model/SkSVGNode.h
@@ -58,6 +58,7 @@ public:
void setFillRule(const SkSVGFillRule&);
void setOpacity(const SkSVGNumberType&);
void setStroke(const SkSVGPaint&);
+ void setStrokeDashArray(const SkSVGDashArray&);
void setStrokeOpacity(const SkSVGNumberType&);
void setStrokeWidth(const SkSVGLength&);
void setVisibility(const SkSVGVisibility&);
diff --git a/experimental/svg/model/SkSVGRenderContext.cpp b/experimental/svg/model/SkSVGRenderContext.cpp
index 8ee5ffcbe6..61551c4858 100644
--- a/experimental/svg/model/SkSVGRenderContext.cpp
+++ b/experimental/svg/model/SkSVGRenderContext.cpp
@@ -6,6 +6,7 @@
*/
#include "SkCanvas.h"
+#include "SkDashPathEffect.h"
#include "SkPath.h"
#include "SkSVGAttribute.h"
#include "SkSVGNode.h"
@@ -154,6 +155,38 @@ void commitToPaint<SkSVGAttribute::kFillOpacity>(const SkSVGPresentationAttribut
}
template <>
+void commitToPaint<SkSVGAttribute::kStrokeDashArray>(const SkSVGPresentationAttributes& attrs,
+ const SkSVGRenderContext& ctx,
+ SkSVGPresentationContext* pctx) {
+ const auto& dashArray = attrs.fStrokeDashArray.get();
+ if (dashArray->type() != SkSVGDashArray::Type::kDashArray) {
+ return;
+ }
+
+ const auto count = dashArray->dashArray().count();
+ SkSTArray<128, SkScalar, true> intervals(count);
+ for (const auto& dash : dashArray->dashArray()) {
+ intervals.push_back(ctx.lengthContext().resolve(dash,
+ SkSVGLengthContext::LengthType::kOther));
+ }
+
+ if (count & 1) {
+ // If an odd number of values is provided, then the list of values
+ // is repeated to yield an even number of values.
+ intervals.push_back_n(count);
+ memcpy(intervals.begin() + count, intervals.begin(), count);
+ }
+
+ SkASSERT((intervals.count() & 1) == 0);
+
+ // TODO: phase support
+ const SkScalar phase = 0;
+ pctx->fStrokePaint.setPathEffect(SkDashPathEffect::Make(intervals.begin(),
+ intervals.count(),
+ phase));
+}
+
+template <>
void commitToPaint<SkSVGAttribute::kStrokeLineCap>(const SkSVGPresentationAttributes& attrs,
const SkSVGRenderContext&,
SkSVGPresentationContext* pctx) {
@@ -297,6 +330,7 @@ void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttr
ApplyLazyInheritedAttribute(FillRule);
ApplyLazyInheritedAttribute(ClipRule);
ApplyLazyInheritedAttribute(Stroke);
+ ApplyLazyInheritedAttribute(StrokeDashArray);
ApplyLazyInheritedAttribute(StrokeLineCap);
ApplyLazyInheritedAttribute(StrokeLineJoin);
ApplyLazyInheritedAttribute(StrokeMiterLimit);
diff --git a/experimental/svg/model/SkSVGTypes.h b/experimental/svg/model/SkSVGTypes.h
index 4a300b6e3c..0878068982 100644
--- a/experimental/svg/model/SkSVGTypes.h
+++ b/experimental/svg/model/SkSVGTypes.h
@@ -272,4 +272,35 @@ private:
Type fType;
};
+class SkSVGDashArray {
+public:
+ enum class Type {
+ kNone,
+ kDashArray,
+ kInherit,
+ };
+
+ SkSVGDashArray() : fType(Type::kNone) {}
+ explicit SkSVGDashArray(Type t) : fType(t) {}
+ explicit SkSVGDashArray(SkTDArray<SkSVGLength>&& dashArray)
+ : fType(Type::kDashArray)
+ , fDashArray(std::move(dashArray)) {}
+
+ SkSVGDashArray(const SkSVGDashArray&) = default;
+ SkSVGDashArray& operator=(const SkSVGDashArray&) = default;
+
+ bool operator==(const SkSVGDashArray& other) const {
+ return fType == other.fType && fDashArray == other.fDashArray;
+ }
+ bool operator!=(const SkSVGDashArray& other) const { return !(*this == other); }
+
+ Type type() const { return fType; }
+
+ const SkTDArray<SkSVGLength>& dashArray() const { return fDashArray; }
+
+private:
+ Type fType;
+ SkTDArray<SkSVGLength> fDashArray;
+};
+
#endif // SkSVGTypes_DEFINED
diff --git a/experimental/svg/model/SkSVGValue.h b/experimental/svg/model/SkSVGValue.h
index c6390c0468..d994f64890 100644
--- a/experimental/svg/model/SkSVGValue.h
+++ b/experimental/svg/model/SkSVGValue.h
@@ -19,6 +19,7 @@ public:
enum class Type {
kClip,
kColor,
+ kDashArray,
kFillRule,
kLength,
kLineCap,
@@ -88,5 +89,6 @@ using SkSVGStringValue = SkSVGWrapperValue<SkSVGStringType , SkSVGValue:
using SkSVGSpreadMethodValue = SkSVGWrapperValue<SkSVGSpreadMethod ,
SkSVGValue::Type::kSpreadMethod>;
using SkSVGVisibilityValue = SkSVGWrapperValue<SkSVGVisibility , SkSVGValue::Type::kVisibility>;
+using SkSVGDashArrayValue = SkSVGWrapperValue<SkSVGDashArray , SkSVGValue::Type::kDashArray >;
#endif // SkSVGValue_DEFINED