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

Side by Side Diff: experimental/svg/SkSVGDevice.cpp

Issue 892973002: [SkSVGDevice] Initial shader/gradient support (Closed) Base URL: https://chromium.googlesource.com/skia.git@master
Patch Set: Created 5 years, 10 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/SkSVGDevice.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 }
OLDNEW
« no previous file with comments | « experimental/svg/SkSVGDevice.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698