Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(318)

Side by Side Diff: experimental/svg/model/SkSVGDOM.cpp

Issue 2164193002: Initial SVG model (Closed) Base URL: https://chromium.googlesource.com/skia.git@master
Patch Set: warning fix Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « experimental/svg/model/SkSVGDOM.h ('k') | experimental/svg/model/SkSVGG.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkCanvas.h"
9 #include "SkDOM.h"
10 #include "SkParse.h"
11 #include "SkParsePath.h"
12 #include "SkSVGDOM.h"
13 #include "SkSVGG.h"
14 #include "SkSVGNode.h"
15 #include "SkSVGPath.h"
16 #include "SkSVGSVG.h"
17 #include "SkSVGValue.h"
18 #include "SkTSearch.h"
19
20 namespace {
21
22 SkColor ParseColor(const char* str) {
23 // FIXME: real parser
24 if (*str++ != '#') {
25 return SK_ColorBLACK;
26 }
27
28 uint32_t v;
29 const char* consumed = SkParse::FindHex(str, &v);
30
31 switch(consumed - str) {
32 case 6:
33 // matched '#xxxxxx'
34 break;
35 case 3:
36 // matched '#xxx;
37 v = ((v << 12) & 0x00f00000) |
38 ((v << 8) & 0x000ff000) |
39 ((v << 4) & 0x00000ff0) |
40 ((v << 0) & 0x0000000f);
41 break;
42 default:
43 // failed
44 v = 0;
45 break;
46 }
47
48 return v | 0xff000000;
49 }
50
51 const char* ParseScalarPair(const char* str, SkScalar v[2]) {
52 str = SkParse::FindScalar(str, v);
53 if (str) {
54 const char* second = SkParse::FindScalar(str, v + 1);
55 if (!second) {
56 v[1] = v[0];
57 } else {
58 str = second;
59 }
60 }
61
62 return str;
63 }
64
65 SkMatrix ParseTransform(const char* str) {
66 SkMatrix m = SkMatrix::I();
67
68 // FIXME: real parser
69 if (!strncmp(str, "matrix(", 7)) {
70 SkScalar values[6];
71 str = SkParse::FindScalars(str + 7, values, 6);
72 if (str) {
73 m.setAffine(values);
74 }
75 } else if (!strncmp(str, "scale(", 6)) {
76 SkScalar values[2];
77 str = ParseScalarPair(str + 6, values);
78 if (str) {
79 m.setScale(values[0], values[1]);
80 }
81 } else if (!strncmp(str, "translate(", 10)) {
82 SkScalar values[2];
83 str = ParseScalarPair(str + 10, values);
84 if (str) {
85 m.setTranslate(values[0], values[1]);
86 }
87 } else if (!strncmp(str, "rotate(", 7)) {
88 SkScalar value;
89 str = SkParse::FindScalar(str + 7, &value);
90 if (str) {
91 m.setRotate(value);
92 }
93 }
94
95 return m;
96 }
97
98 bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
99 const char* stringValue) {
100 node->setAttribute(attr, SkSVGColorValue(ParseColor(stringValue)));
101 return true;
102 }
103
104 bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
105 const char* stringValue) {
106 SkPath path;
107 if (!SkParsePath::FromSVGString(stringValue, &path)) {
108 return false;
109 }
110
111 node->setAttribute(attr, SkSVGPathValue(path));
112 return true;
113 }
114
115 bool SetTransformAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
116 const char* stringValue) {
117 node->setAttribute(attr, SkSVGTransformValue(ParseTransform(stringValue)));
118 return true;
119 }
120
121 template<typename T>
122 struct SortedDictionaryEntry {
123 const char* fKey;
124 const T fValue;
125 };
126
127 struct AttrParseInfo {
128 SkSVGAttribute fAttr;
129 bool (*fSetter)(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr, const cha r* stringValue);
130 };
131
132 SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
133 { "d", { SkSVGAttribute::d, SetPathDataAttribute }},
134 { "fill", { SkSVGAttribute::fill, SetPaintAttribute }},
135 { "stroke", { SkSVGAttribute::stroke, SetPaintAttribute }},
136 { "transform", { SkSVGAttribute::transform, SetTransformAttribute }},
137 };
138
139 SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
140 { "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
141 { "path", []() -> sk_sp<SkSVGNode> { return SkSVGPath::Make(); }},
142 { "svg" , []() -> sk_sp<SkSVGNode> { return SkSVGSVG::Make(); }},
143 };
144
145 struct ConstructionContext {
146 ConstructionContext() : fParent(nullptr) { }
147 ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode> & newParent)
148 : fParent(newParent.get()) { }
149
150 const SkSVGNode* fParent;
151 };
152
153 void parse_node_attributes(const SkDOM& xmlDom, const SkDOM::Node* xmlNode,
154 const sk_sp<SkSVGNode>& svgNode) {
155 const char* name, *value;
156 SkDOM::AttrIter attrIter(xmlDom, xmlNode);
157 while ((name = attrIter.next(&value))) {
158 const int attrIndex = SkStrSearch(&gAttributeParseInfo[0].fKey,
159 SkTo<int>(SK_ARRAY_COUNT(gAttributePar seInfo)),
160 name, sizeof(gAttributeParseInfo[0]));
161 if (attrIndex < 0) {
162 SkDebugf("unhandled attribute: %s\n", name);
163 continue;
164 }
165
166 SkASSERT(SkTo<size_t>(attrIndex) < SK_ARRAY_COUNT(gAttributeParseInfo));
167 const auto& attrInfo = gAttributeParseInfo[attrIndex].fValue;
168 if (!attrInfo.fSetter(svgNode, attrInfo.fAttr, value)) {
169 SkDebugf("could not parse attribute: '%s=\"%s\"'\n", name, value);
170 }
171 }
172 }
173
174 sk_sp<SkSVGNode> construct_svg_node(const SkDOM& dom, const ConstructionContext& ctx,
175 const SkDOM::Node* xmlNode) {
176 const char* elem = dom.getName(xmlNode);
177 const SkDOM::Type elemType = dom.getType(xmlNode);
178
179 if (elemType == SkDOM::kText_Type) {
180 SkASSERT(dom.countChildren(xmlNode) == 0);
181 // TODO: text handling
182 return nullptr;
183 }
184
185 SkASSERT(elemType == SkDOM::kElement_Type);
186
187 const int tagIndex = SkStrSearch(&gTagFactories[0].fKey,
188 SkTo<int>(SK_ARRAY_COUNT(gTagFactories)),
189 elem, sizeof(gTagFactories[0]));
190 if (tagIndex < 0) {
191 SkDebugf("unhandled element: <%s>\n", elem);
192 return nullptr;
193 }
194
195 SkASSERT(SkTo<size_t>(tagIndex) < SK_ARRAY_COUNT(gTagFactories));
196 sk_sp<SkSVGNode> node = gTagFactories[tagIndex].fValue();
197 parse_node_attributes(dom, xmlNode, node);
198
199 ConstructionContext localCtx(ctx, node);
200 for (auto* child = dom.getFirstChild(xmlNode, nullptr); child;
201 child = dom.getNextSibling(child)) {
202 sk_sp<SkSVGNode> childNode = construct_svg_node(dom, localCtx, child);
203 if (childNode) {
204 node->appendChild(std::move(childNode));
205 }
206 }
207
208 return node;
209 }
210
211 } // anonymous namespace
212
213 SkSVGDOM::SkSVGDOM(const SkSize& containerSize)
214 : fContainerSize(containerSize) {
215 }
216
217 sk_sp<SkSVGDOM> SkSVGDOM::MakeFromDOM(const SkDOM& xmlDom, const SkSize& contain erSize) {
218 sk_sp<SkSVGDOM> dom = sk_make_sp<SkSVGDOM>(containerSize);
219
220 ConstructionContext ctx;
221 dom->fRoot = construct_svg_node(xmlDom, ctx, xmlDom.getRootNode());
222
223 return dom;
224 }
225
226 sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream, const SkSize& cont ainerSize) {
227 SkDOM xmlDom;
228 if (!xmlDom.build(svgStream)) {
229 return nullptr;
230 }
231
232 return MakeFromDOM(xmlDom, containerSize);
233 }
234
235 void SkSVGDOM::render(SkCanvas* canvas) const {
236 if (fRoot) {
237 fRoot->render(canvas);
238 }
239 }
240
241 void SkSVGDOM::setContainerSize(const SkSize& containerSize) {
242 // TODO: inval
243 fContainerSize = containerSize;
244 }
OLDNEW
« no previous file with comments | « experimental/svg/model/SkSVGDOM.h ('k') | experimental/svg/model/SkSVGG.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698