OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkSVGDevice.h" | 8 #include "SkSVGDevice.h" |
9 | 9 |
10 #include "SkBitmap.h" | 10 #include "SkBitmap.h" |
11 #include "SkDraw.h" | 11 #include "SkDraw.h" |
12 #include "SkPaint.h" | 12 #include "SkPaint.h" |
13 #include "SkParsePath.h" | 13 #include "SkParsePath.h" |
14 #include "SkShader.h" | |
14 #include "SkStream.h" | 15 #include "SkStream.h" |
15 #include "SkXMLWriter.h" | 16 #include "SkXMLWriter.h" |
16 | 17 |
17 namespace { | 18 namespace { |
mtklein
2015/02/02 16:52:48
You can probably drop this namespace for now, give
f(malita)
2015/02/02 18:05:47
Done.
| |
18 | 19 |
19 class AutoElement { | 20 static SkString svg_color(SkColor color) { |
21 SkString colorStr; | |
22 colorStr.printf("rgb(%u,%u,%u)", | |
23 SkColorGetR(color), | |
24 SkColorGetG(color), | |
25 SkColorGetB(color)); | |
26 return colorStr; | |
27 } | |
28 | |
29 static SkScalar svg_opacity(SkColor color) { | |
30 return SkIntToScalar(SkColorGetA(color)) / SK_AlphaOPAQUE; | |
31 } | |
32 | |
33 } | |
34 | |
35 class SkSVGDevice::AutoResources { | |
mtklein
2015/02/02 16:52:48
: SkNoncopyable for both these?
f(malita)
2015/02/02 18:05:47
Done.
| |
20 public: | 36 public: |
21 AutoElement(const char name[], SkXMLWriter* writer) | 37 AutoResources(const SkPaint& paint, SkXMLWriter* writer); |
22 : fWriter(writer) { | 38 |
mtklein
2015/02/02 16:52:49
Maybe dumb question... if this guy doesn't have a
f(malita)
2015/02/02 18:05:47
Yeah there is no auto dtor logic for this class, b
| |
39 const SkString& color() const { return fColor; } | |
40 | |
41 private: | |
42 SkString addLinearGradientDef(const SkShader::GradientInfo&, const SkShader* ); | |
43 | |
44 SkXMLWriter* fWriter; | |
45 SkString fColor; | |
46 }; | |
47 | |
48 class SkSVGDevice::AutoElement { | |
49 public: | |
50 AutoElement(const char name[], SkXMLWriter* writer, bool autoClose = true) | |
51 : fWriter(writer) | |
52 , fAutoClose(autoClose) { | |
23 fWriter->startElement(name); | 53 fWriter->startElement(name); |
24 } | 54 } |
25 | 55 |
26 ~AutoElement() { | 56 ~AutoElement() { |
27 fWriter->endElement(); | 57 if (fAutoClose) { |
58 fWriter->endElement(); | |
59 } | |
60 } | |
61 | |
62 void addAttribute(const char name[], const char val[]) { | |
63 fWriter->addAttribute(name, val); | |
64 } | |
65 | |
66 void addAttribute(const char name[], const SkString& val) { | |
67 fWriter->addAttribute(name, val.c_str()); | |
68 } | |
69 | |
70 void addAttribute(const char name[], int32_t val) { | |
71 fWriter->addS32Attribute(name, val); | |
72 } | |
73 | |
74 void addAttribute(const char name[], SkScalar val) { | |
75 fWriter->addScalarAttribute(name, val); | |
76 } | |
77 | |
78 void addPaint(const SkPaint& paint, const AutoResources& resources) { | |
79 SkPaint::Style style = paint.getStyle(); | |
80 if (style == SkPaint::kFill_Style || style == SkPaint::kStrokeAndFill_St yle) { | |
81 fWriter->addAttribute("fill", resources.color().c_str()); | |
82 } else { | |
83 fWriter->addAttribute("fill", "none"); | |
84 } | |
85 | |
86 if (style == SkPaint::kStroke_Style || style == SkPaint::kStrokeAndFill_ Style) { | |
87 fWriter->addAttribute("stroke", resources.color().c_str()); | |
88 fWriter->addScalarAttribute("stroke-width", paint.getStrokeWidth()); | |
89 } else { | |
90 fWriter->addAttribute("stroke", "none"); | |
91 } | |
92 | |
93 if (SK_AlphaOPAQUE != SkColorGetA(paint.getColor())) { | |
94 fWriter->addScalarAttribute("opacity", svg_opacity(paint.getColor()) ); | |
95 } | |
96 } | |
97 | |
98 void addTransform(const SkMatrix &t, const char* name = NULL) { | |
mtklein
2015/02/02 16:52:48
SkMatrix& ?
f(malita)
2015/02/02 18:05:47
Done.
| |
99 if (t.isIdentity()) { | |
100 return; | |
101 } | |
102 | |
103 SkString tstr; | |
104 switch (t.getType()) { | |
105 case SkMatrix::kTranslate_Mask: | |
106 tstr.appendf("translate(%g %g)", | |
107 SkScalarToFloat(t.getTranslateX()), | |
108 SkScalarToFloat(t.getTranslateY())); | |
109 break; | |
110 case SkMatrix::kScale_Mask: | |
111 tstr.appendf("scale(%g %g)", | |
112 SkScalarToFloat(t.getScaleX()), | |
113 SkScalarToFloat(t.getScaleY())); | |
114 break; | |
115 default: | |
mtklein
2015/02/02 16:52:48
case SkMatrix::kAffineMask:
<this code>
defau
f(malita)
2015/02/02 18:05:47
kAffineMask is only set when rotating/skewing so i
| |
116 tstr.appendf("matrix(%g %g %g %g %g %g)", | |
117 SkScalarToFloat(t.getScaleX()), SkScalarToFloat(t.getSk ewY()), | |
118 SkScalarToFloat(t.getSkewX()), SkScalarToFloat(t.getSca leY()), | |
119 SkScalarToFloat(t.getTranslateX()), SkScalarToFloat(t.g etTranslateY())); | |
120 break; | |
121 } | |
122 | |
123 fWriter->addAttribute(SkToBool(name) ? name : "transform", tstr.c_str()) ; | |
mtklein
2015/02/02 16:52:48
Can we not just default name to "transform"?
f(malita)
2015/02/02 18:05:47
Done.
| |
28 } | 124 } |
29 | 125 |
30 private: | 126 private: |
31 SkXMLWriter* fWriter; | 127 SkXMLWriter* fWriter; |
128 bool fAutoClose; | |
32 }; | 129 }; |
33 | 130 |
131 SkSVGDevice::AutoResources::AutoResources(const SkPaint& paint, SkXMLWriter* wri ter) | |
132 : fWriter(writer) | |
133 , fColor(svg_color(paint.getColor())) { | |
134 | |
135 const SkShader* shader = paint.getShader(); | |
136 if (!SkToBool(shader)) { | |
137 // TODO: clip support | |
138 return; | |
139 } | |
140 | |
141 SkShader::GradientInfo grInfo; | |
142 if (SkShader::kLinear_GradientType != shader->asAGradient(&grInfo)) { | |
143 // TODO: non-linear gradient support | |
144 SkDebugf("unsupported shader type\n"); | |
145 return; | |
146 } | |
147 | |
148 AutoElement defs("defs", fWriter); | |
mtklein
2015/02/02 16:52:48
It might help these standalone AutoElements to jum
f(malita)
2015/02/02 18:05:47
Done.
| |
149 | |
150 SkAutoSTArray<16, SkColor> grColors(grInfo.fColorCount); | |
151 SkAutoSTArray<16, SkScalar> grOffsets(grInfo.fColorCount); | |
152 grInfo.fColors = grColors.get(); | |
153 grInfo.fColorOffsets = grOffsets.get(); | |
154 | |
155 SkAssertResult(SkShader::kLinear_GradientType == shader->asAGradient(&grInfo )); | |
156 SkASSERT(grInfo.fColorCount <= grColors.count()); | |
157 SkASSERT(grInfo.fColorCount <= grOffsets.count()); | |
158 | |
159 fColor.printf("url(#%s)", addLinearGradientDef(grInfo, shader).c_str()); | |
160 } | |
161 | |
162 SkString SkSVGDevice::AutoResources::addLinearGradientDef(const SkShader::Gradie ntInfo& info, | |
163 const SkShader* shader ) { | |
164 static uint32_t linear_gradient_counter = 0; | |
165 | |
166 SkString id("linear_gradient_"); | |
167 id.appendU32(linear_gradient_counter++); | |
168 | |
169 AutoElement gradient("linearGradient", fWriter); | |
170 gradient.addAttribute("id", id); | |
171 gradient.addAttribute("gradientUnits", "userSpaceOnUse"); | |
172 gradient.addAttribute("x1", info.fPoint[0].x()); | |
173 gradient.addAttribute("y1", info.fPoint[0].y()); | |
174 gradient.addAttribute("x2", info.fPoint[1].x()); | |
175 gradient.addAttribute("y2", info.fPoint[1].y()); | |
176 gradient.addTransform(shader->getLocalMatrix(), "gradientTransform"); | |
177 | |
178 SkASSERT(info.fColorCount >= 2); | |
179 for (int i = 0; i < info.fColorCount; ++i) { | |
180 SkColor color = info.fColors[i]; | |
181 SkString colorStr(svg_color(color)); | |
182 | |
183 AutoElement stop("stop", fWriter); | |
184 stop.addAttribute("offset", info.fColorOffsets[i]); | |
185 stop.addAttribute("stop-color", colorStr.c_str()); | |
186 | |
187 if (SK_AlphaOPAQUE != SkColorGetA(color)) { | |
188 stop.addAttribute("stop-opacity", svg_opacity(color)); | |
189 } | |
190 } | |
191 | |
192 return id; | |
34 } | 193 } |
35 | 194 |
36 SkBaseDevice* SkSVGDevice::Create(const SkISize& size, SkWStream* wstream) { | 195 SkBaseDevice* SkSVGDevice::Create(const SkISize& size, SkWStream* wstream) { |
37 if (!SkToBool(wstream)) { | 196 if (!SkToBool(wstream)) { |
38 return NULL; | 197 return NULL; |
39 } | 198 } |
40 | 199 |
41 return SkNEW_ARGS(SkSVGDevice, (size, wstream)); | 200 return SkNEW_ARGS(SkSVGDevice, (size, wstream)); |
42 } | 201 } |
43 | 202 |
44 SkSVGDevice::SkSVGDevice(const SkISize& size, SkWStream* wstream) | 203 SkSVGDevice::SkSVGDevice(const SkISize& size, SkWStream* wstream) |
45 : fWriter(SkNEW_ARGS(SkXMLStreamWriter, (wstream))) { | 204 : fWriter(SkNEW_ARGS(SkXMLStreamWriter, (wstream))) |
205 , fElementStack(0) { | |
46 | 206 |
47 fLegacyBitmap.setInfo(SkImageInfo::MakeUnknown(size.width(), size.height())) ; | 207 fLegacyBitmap.setInfo(SkImageInfo::MakeUnknown(size.width(), size.height())) ; |
48 | 208 |
49 fWriter->writeHeader(); | 209 fWriter->writeHeader(); |
50 fWriter->startElement("svg"); | 210 |
51 fWriter->addAttribute("xmlns", "http://www.w3.org/2000/svg"); | 211 |
52 fWriter->addAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); | 212 AutoElement elem("svg", fWriter, false); |
mtklein
2015/02/02 16:52:49
Probably worth a note to point out how this tag ge
f(malita)
2015/02/02 18:05:47
Done.
| |
53 fWriter->addS32Attribute("width", size.width()); | 213 elem.addAttribute("xmlns", "http://www.w3.org/2000/svg"); |
54 fWriter->addS32Attribute("height", size.height()); | 214 elem.addAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); |
215 elem.addAttribute("width", size.width()); | |
216 elem.addAttribute("height", size.height()); | |
217 | |
218 this->pushElement(elem); | |
mtklein
2015/02/02 16:52:48
Seems like we really don't need an explicit stack
f(malita)
2015/02/02 18:05:47
That was my first thought also, but gave up initia
| |
55 } | 219 } |
56 | 220 |
57 SkSVGDevice::~SkSVGDevice() { | 221 SkSVGDevice::~SkSVGDevice() { |
58 fWriter->endElement(); | 222 while (fElementStack > 0) { |
223 popElement(); | |
mtklein
2015/02/02 16:52:48
this->
f(malita)
2015/02/02 18:05:47
removed
| |
224 } | |
225 | |
59 fWriter->flush(); | 226 fWriter->flush(); |
60 SkDELETE(fWriter); | 227 SkDELETE(fWriter); |
61 } | 228 } |
62 | 229 |
230 void SkSVGDevice::pushElement(const AutoElement&) { | |
mtklein
2015/02/02 16:52:48
Might want to assert the AutoElement isn't auto-cl
f(malita)
2015/02/02 18:05:47
removed
| |
231 fElementStack++; | |
232 } | |
233 | |
234 void SkSVGDevice::popElement() { | |
235 SkASSERT(fElementStack > 0); | |
236 | |
237 fWriter->endElement(); | |
238 fElementStack--; | |
239 } | |
240 | |
63 SkImageInfo SkSVGDevice::imageInfo() const { | 241 SkImageInfo SkSVGDevice::imageInfo() const { |
64 return fLegacyBitmap.info(); | 242 return fLegacyBitmap.info(); |
65 } | 243 } |
66 | 244 |
67 const SkBitmap& SkSVGDevice::onAccessBitmap() { | 245 const SkBitmap& SkSVGDevice::onAccessBitmap() { |
68 return fLegacyBitmap; | 246 return fLegacyBitmap; |
69 } | 247 } |
70 | 248 |
71 void SkSVGDevice::addPaint(const SkPaint& paint) { | 249 void SkSVGDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { |
72 SkColor color = paint.getColor(); | 250 AutoResources resources(paint, fWriter); |
73 SkString colorStr; | 251 AutoElement rect("rect", fWriter); |
74 colorStr.appendf("rgb(%u,%u,%u)", SkColorGetR(color), SkColorGetG(color), Sk ColorGetB(color)); | |
75 | 252 |
76 SkPaint::Style style = paint.getStyle(); | 253 rect.addAttribute("x", 0); |
77 if (style == SkPaint::kFill_Style || style == SkPaint::kStrokeAndFill_Style) { | 254 rect.addAttribute("y", 0); |
78 fWriter->addAttribute("fill", colorStr.c_str()); | 255 rect.addAttribute("width", this->width()); |
79 } else { | 256 rect.addAttribute("height", this->height()); |
80 fWriter->addAttribute("fill", "none"); | |
81 } | |
82 | 257 |
83 if (style == SkPaint::kStroke_Style || style == SkPaint::kStrokeAndFill_Styl e) { | 258 rect.addPaint(paint, resources); |
84 fWriter->addAttribute("stroke", colorStr.c_str()); | 259 rect.addTransform(*draw.fMatrix); |
85 fWriter->addScalarAttribute("stroke-width", paint.getStrokeWidth()); | |
86 } else { | |
87 fWriter->addAttribute("stroke", "none"); | |
88 } | |
89 } | |
90 | |
91 void SkSVGDevice::addTransform(const SkMatrix &t) { | |
92 if (t.isIdentity()) { | |
93 return; | |
94 } | |
95 | |
96 SkString tstr; | |
97 tstr.appendf("matrix(%g %g %g %g %g %g)", | |
98 SkScalarToFloat(t.getScaleX()), SkScalarToFloat(t.getSkewY()), | |
99 SkScalarToFloat(t.getSkewX()), SkScalarToFloat(t.getScaleY()), | |
100 SkScalarToFloat(t.getTranslateX()), SkScalarToFloat(t.getTransl ateY())); | |
101 fWriter->addAttribute("transform", tstr.c_str()); | |
102 } | |
103 | |
104 void SkSVGDevice::drawPaint(const SkDraw&, const SkPaint& paint) { | |
105 // todo | |
106 } | 260 } |
107 | 261 |
108 void SkSVGDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t cou nt, | 262 void SkSVGDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t cou nt, |
109 const SkPoint[], const SkPaint& paint) { | 263 const SkPoint[], const SkPaint& paint) { |
110 // todo | 264 // todo |
265 SkDebugf("unsupported operation: drawPoints()"); | |
111 } | 266 } |
112 | 267 |
113 void SkSVGDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& p aint) { | 268 void SkSVGDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& p aint) { |
114 AutoElement elem("rect", fWriter); | 269 AutoResources resources(paint, fWriter); |
270 AutoElement rect("rect", fWriter); | |
115 | 271 |
116 fWriter->addScalarAttribute("x", r.fLeft); | 272 rect.addAttribute("x", r.fLeft); |
117 fWriter->addScalarAttribute("y", r.fTop); | 273 rect.addAttribute("y", r.fTop); |
118 fWriter->addScalarAttribute("width", r.width()); | 274 rect.addAttribute("width", r.width()); |
119 fWriter->addScalarAttribute("height", r.height()); | 275 rect.addAttribute("height", r.height()); |
120 | 276 |
121 this->addPaint(paint); | 277 rect.addPaint(paint, resources); |
122 this->addTransform(*draw.fMatrix); | 278 rect.addTransform(*draw.fMatrix); |
123 } | 279 } |
124 | 280 |
125 void SkSVGDevice::drawOval(const SkDraw&, const SkRect& oval, const SkPaint& pai nt) { | 281 void SkSVGDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint & paint) { |
126 // todo | 282 AutoResources resources(paint, fWriter); |
283 AutoElement ellipse("ellipse", fWriter); | |
284 | |
285 ellipse.addAttribute("cx", oval.centerX()); | |
286 ellipse.addAttribute("cy", oval.centerY()); | |
287 ellipse.addAttribute("rx", oval.width() / 2); | |
288 ellipse.addAttribute("ry", oval.height() / 2); | |
289 | |
290 ellipse.addPaint(paint, resources); | |
291 ellipse.addTransform(*draw.fMatrix); | |
127 } | 292 } |
128 | 293 |
129 void SkSVGDevice::drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& pai nt) { | 294 void SkSVGDevice::drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& pai nt) { |
130 // todo | 295 // todo |
296 SkDebugf("unsupported operation: drawRRect()"); | |
131 } | 297 } |
132 | 298 |
133 void SkSVGDevice::drawPath(const SkDraw& draw, const SkPath& path, const SkPaint & paint, | 299 void SkSVGDevice::drawPath(const SkDraw& draw, const SkPath& path, const SkPaint & paint, |
134 const SkMatrix* prePathMatrix, bool pathIsMutable) { | 300 const SkMatrix* prePathMatrix, bool pathIsMutable) { |
301 AutoResources resources(paint, fWriter); | |
135 AutoElement elem("path", fWriter); | 302 AutoElement elem("path", fWriter); |
136 | 303 |
137 SkString pathStr; | 304 SkString pathStr; |
138 SkParsePath::ToSVGString(path, &pathStr); | 305 SkParsePath::ToSVGString(path, &pathStr); |
139 fWriter->addAttribute("d", pathStr.c_str()); | 306 elem.addAttribute("d", pathStr.c_str()); |
140 | 307 |
141 this->addPaint(paint); | 308 elem.addPaint(paint, resources); |
142 this->addTransform(*draw.fMatrix); | 309 elem.addTransform(*draw.fMatrix); |
143 } | 310 } |
144 | 311 |
145 void SkSVGDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, | 312 void SkSVGDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, |
146 const SkMatrix& matrix, const SkPaint& paint) { | 313 const SkMatrix& matrix, const SkPaint& paint) { |
147 // todo | 314 // todo |
315 SkDebugf("unsupported operation: drawBitmap()"); | |
148 } | 316 } |
149 | 317 |
150 void SkSVGDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, | 318 void SkSVGDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, |
151 int x, int y, const SkPaint& paint) { | 319 int x, int y, const SkPaint& paint) { |
152 // todo | 320 // todo |
321 SkDebugf("unsupported operation: drawSprite()"); | |
153 } | 322 } |
154 | 323 |
155 void SkSVGDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, const SkRect* s rcOrNull, | 324 void SkSVGDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, const SkRect* s rcOrNull, |
156 const SkRect& dst, const SkPaint& paint, | 325 const SkRect& dst, const SkPaint& paint, |
157 SkCanvas::DrawBitmapRectFlags flags) { | 326 SkCanvas::DrawBitmapRectFlags flags) { |
158 // todo | 327 // todo |
328 SkDebugf("unsupported operation: drawBitmapRect()"); | |
159 } | 329 } |
160 | 330 |
161 void SkSVGDevice::drawText(const SkDraw&, const void* text, size_t len, | 331 void SkSVGDevice::drawText(const SkDraw&, const void* text, size_t len, |
162 SkScalar x, SkScalar y, const SkPaint& paint) { | 332 SkScalar x, SkScalar y, const SkPaint& paint) { |
163 // todo | 333 // todo |
334 SkDebugf("unsupported operation: drawText()"); | |
164 } | 335 } |
165 | 336 |
166 void SkSVGDevice::drawPosText(const SkDraw&, const void* text, size_t len,const SkScalar pos[], | 337 void SkSVGDevice::drawPosText(const SkDraw&, const void* text, size_t len,const SkScalar pos[], |
167 int scalarsPerPos, const SkPoint& offset, const Sk Paint& paint) { | 338 int scalarsPerPos, const SkPoint& offset, const Sk Paint& paint) { |
168 // todo | 339 // todo |
340 SkDebugf("unsupported operation: drawPosText()"); | |
169 } | 341 } |
170 | 342 |
171 void SkSVGDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, co nst SkPath& path, | 343 void SkSVGDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, co nst SkPath& path, |
172 const SkMatrix* matrix, const SkPaint& paint) { | 344 const SkMatrix* matrix, const SkPaint& paint) { |
173 // todo | 345 // todo |
346 SkDebugf("unsupported operation: drawTextOnPath()"); | |
174 } | 347 } |
175 | 348 |
176 void SkSVGDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCo unt, | 349 void SkSVGDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCo unt, |
177 const SkPoint verts[], const SkPoint texs[], | 350 const SkPoint verts[], const SkPoint texs[], |
178 const SkColor colors[], SkXfermode* xmode, | 351 const SkColor colors[], SkXfermode* xmode, |
179 const uint16_t indices[], int indexCount, | 352 const uint16_t indices[], int indexCount, |
180 const SkPaint& paint) { | 353 const SkPaint& paint) { |
181 // todo | 354 // todo |
355 SkDebugf("unsupported operation: drawVertices()"); | |
182 } | 356 } |
183 | 357 |
184 void SkSVGDevice::drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, | 358 void SkSVGDevice::drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, |
185 const SkPaint&) { | 359 const SkPaint&) { |
186 // todo | 360 // todo |
361 SkDebugf("unsupported operation: drawDevice()"); | |
187 } | 362 } |
OLD | NEW |