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

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: get rid of AutoResources 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 {
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 struct Resources {
mtklein 2015/02/02 22:30:10 FWIW, I am a big fan of data passed by value until
f(malita) 2015/02/02 23:32:29 Ack.
34 Resources(const SkPaint& paint)
35 : fPaint(svg_color(paint.getColor())) {}
36
37 SkString fPaint;
mtklein 2015/02/02 22:30:10 fPaintColor?
f(malita) 2015/02/02 23:32:29 The thing is it's not necessarily a color: it can
38 };
39
40 }
41
42 class SkSVGDevice::AutoElement : ::SkNoncopyable {
20 public: 43 public:
21 AutoElement(const char name[], SkXMLWriter* writer) 44 AutoElement(const char name[], SkXMLWriter* writer)
22 : fWriter(writer) { 45 : fWriter(writer) {
23 fWriter->startElement(name); 46 fWriter->startElement(name);
24 } 47 }
25 48
49 AutoElement(const char name[], SkXMLWriter* writer, const SkDraw& draw, cons t SkPaint& paint)
50 : fWriter(writer) {
51
52 Resources res = this->addResources(paint);
53
54 fWriter->startElement(name);
55
56 this->addPaint(paint, res);
57 this->addTransform(*draw.fMatrix);
58 }
59
26 ~AutoElement() { 60 ~AutoElement() {
27 fWriter->endElement(); 61 fWriter->endElement();
28 } 62 }
29 63
64 void addAttribute(const char name[], const char val[]) {
65 fWriter->addAttribute(name, val);
66 }
67
68 void addAttribute(const char name[], const SkString& val) {
69 fWriter->addAttribute(name, val.c_str());
70 }
71
72 void addAttribute(const char name[], int32_t val) {
73 fWriter->addS32Attribute(name, val);
74 }
75
76 void addAttribute(const char name[], SkScalar val) {
77 fWriter->addScalarAttribute(name, val);
78 }
79
30 private: 80 private:
81 Resources addResources(const SkPaint& paint);
82 void addPaint(const SkPaint& paint, const Resources& resources);
83 void addTransform(const SkMatrix& transform, const char name[] = "transform" );
84
85 SkString addLinearGradientDef(const SkShader::GradientInfo& info, const SkSh ader* shader);
86
31 SkXMLWriter* fWriter; 87 SkXMLWriter* fWriter;
32 }; 88 };
33 89
90 void SkSVGDevice::AutoElement::addPaint(const SkPaint& paint, const Resources& r esources) {
91 SkPaint::Style style = paint.getStyle();
92 if (style == SkPaint::kFill_Style || style == SkPaint::kStrokeAndFill_Style) {
93 fWriter->addAttribute("fill", resources.fPaint.c_str());
mtklein 2015/02/02 22:30:10 Might be more readable here if you dogfood your ow
f(malita) 2015/02/02 23:32:30 Done.
94 } else {
95 fWriter->addAttribute("fill", "none");
96 }
97
98 if (style == SkPaint::kStroke_Style || style == SkPaint::kStrokeAndFill_Styl e) {
99 fWriter->addAttribute("stroke", resources.fPaint.c_str());
100 fWriter->addScalarAttribute("stroke-width", paint.getStrokeWidth());
101 } else {
102 fWriter->addAttribute("stroke", "none");
103 }
104
105 if (SK_AlphaOPAQUE != SkColorGetA(paint.getColor())) {
106 fWriter->addScalarAttribute("opacity", svg_opacity(paint.getColor()));
107 }
108 }
109
110 void SkSVGDevice::AutoElement::addTransform(const SkMatrix& t, const char name[] ) {
111 if (t.isIdentity()) {
112 return;
113 }
114
115 SkString tstr;
116 switch (t.getType()) {
117 case SkMatrix::kPerspective_Mask:
118 SkDebugf("Can't handle perspective matrices.");
119 break;
120 case SkMatrix::kTranslate_Mask:
121 tstr.printf("translate(%g %g)",
122 SkScalarToFloat(t.getTranslateX()),
123 SkScalarToFloat(t.getTranslateY()));
124 break;
125 case SkMatrix::kScale_Mask:
126 tstr.printf("scale(%g %g)",
127 SkScalarToFloat(t.getScaleX()),
128 SkScalarToFloat(t.getScaleY()));
129 break;
130 default:
131 tstr.printf("matrix(%g %g %g %g %g %g)",
132 SkScalarToFloat(t.getScaleX()), SkScalarToFloat(t.getSkewY( )),
133 SkScalarToFloat(t.getSkewX()), SkScalarToFloat(t.getScaleY( )),
134 SkScalarToFloat(t.getTranslateX()), SkScalarToFloat(t.getTr anslateY()));
135 break;
136 }
137
138 fWriter->addAttribute(name, tstr.c_str());
139 }
140
141 Resources SkSVGDevice::AutoElement::addResources(const SkPaint& paint) {
142 Resources resources(paint);
mtklein 2015/02/02 22:30:10 Given the number of times you need to "return reso
f(malita) 2015/02/02 23:32:29 Done.
143
144 const SkShader* shader = paint.getShader();
145 if (!SkToBool(shader)) {
146 // TODO: clip support
147 return resources;
148 }
149
150 SkShader::GradientInfo grInfo;
151 grInfo.fColorCount = 0;
152 if (SkShader::kLinear_GradientType != shader->asAGradient(&grInfo)) {
153 // TODO: non-linear gradient support
154 SkDebugf("unsupported shader type\n");
155 return resources;
156 }
157
158 {
159 AutoElement defs("defs", fWriter);
160
161 SkAutoSTArray<16, SkColor> grColors(grInfo.fColorCount);
162 SkAutoSTArray<16, SkScalar> grOffsets(grInfo.fColorCount);
163 grInfo.fColors = grColors.get();
164 grInfo.fColorOffsets = grOffsets.get();
165
166 // One more call to get the actual colors/offsets.
167 shader->asAGradient(&grInfo);
168 SkASSERT(grInfo.fColorCount <= grColors.count());
169 SkASSERT(grInfo.fColorCount <= grOffsets.count());
170
171 resources.fPaint.printf("url(#%s)", addLinearGradientDef(grInfo, shader) .c_str());
172 }
173
174 return resources;
175 }
176
177 SkString SkSVGDevice::AutoElement::addLinearGradientDef(const SkShader::Gradient Info& info,
178 const SkShader* shader) {
179 static uint32_t linear_gradient_counter = 0;
mtklein 2015/02/02 22:30:10 ಠ_ಠ Not incremented atomically. Not initialized
f(malita) 2015/02/02 23:32:30 What?! You're telling me this is not single-thread
180
181 SkString id("linear_gradient_");
182 id.appendU32(linear_gradient_counter++);
183
184 {
185 AutoElement gradient("linearGradient", fWriter);
186
187 gradient.addAttribute("id", id);
188 gradient.addAttribute("gradientUnits", "userSpaceOnUse");
189 gradient.addAttribute("x1", info.fPoint[0].x());
190 gradient.addAttribute("y1", info.fPoint[0].y());
191 gradient.addAttribute("x2", info.fPoint[1].x());
192 gradient.addAttribute("y2", info.fPoint[1].y());
193 gradient.addTransform(shader->getLocalMatrix(), "gradientTransform");
194
195 SkASSERT(info.fColorCount >= 2);
196 for (int i = 0; i < info.fColorCount; ++i) {
197 SkColor color = info.fColors[i];
198 SkString colorStr(svg_color(color));
199
200 {
201 AutoElement stop("stop", fWriter);
202 stop.addAttribute("offset", info.fColorOffsets[i]);
203 stop.addAttribute("stop-color", colorStr.c_str());
204
205 if (SK_AlphaOPAQUE != SkColorGetA(color)) {
206 stop.addAttribute("stop-opacity", svg_opacity(color));
207 }
208 }
209 }
210
211 return id;
212 }
34 } 213 }
35 214
36 SkBaseDevice* SkSVGDevice::Create(const SkISize& size, SkWStream* wstream) { 215 SkBaseDevice* SkSVGDevice::Create(const SkISize& size, SkWStream* wstream) {
37 if (!SkToBool(wstream)) { 216 if (!SkToBool(wstream)) {
38 return NULL; 217 return NULL;
39 } 218 }
40 219
41 return SkNEW_ARGS(SkSVGDevice, (size, wstream)); 220 return SkNEW_ARGS(SkSVGDevice, (size, wstream));
42 } 221 }
43 222
44 SkSVGDevice::SkSVGDevice(const SkISize& size, SkWStream* wstream) 223 SkSVGDevice::SkSVGDevice(const SkISize& size, SkWStream* wstream)
45 : fWriter(SkNEW_ARGS(SkXMLStreamWriter, (wstream))) { 224 : fWriter(SkNEW_ARGS(SkXMLStreamWriter, (wstream))) {
46 225
47 fLegacyBitmap.setInfo(SkImageInfo::MakeUnknown(size.width(), size.height())) ; 226 fLegacyBitmap.setInfo(SkImageInfo::MakeUnknown(size.width(), size.height())) ;
48 227
49 fWriter->writeHeader(); 228 fWriter->writeHeader();
50 fWriter->startElement("svg"); 229
51 fWriter->addAttribute("xmlns", "http://www.w3.org/2000/svg"); 230 // The root <svg> tag gets closed by the destructor.
52 fWriter->addAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); 231 fRootElement.reset(SkNEW_ARGS(AutoElement, ("svg", fWriter)));
53 fWriter->addS32Attribute("width", size.width()); 232
54 fWriter->addS32Attribute("height", size.height()); 233 fRootElement->addAttribute("xmlns", "http://www.w3.org/2000/svg");
234 fRootElement->addAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
235 fRootElement->addAttribute("width", size.width());
236 fRootElement->addAttribute("height", size.height());
55 } 237 }
56 238
57 SkSVGDevice::~SkSVGDevice() { 239 SkSVGDevice::~SkSVGDevice() {
58 fWriter->endElement();
59 fWriter->flush();
60 SkDELETE(fWriter);
61 } 240 }
62 241
63 SkImageInfo SkSVGDevice::imageInfo() const { 242 SkImageInfo SkSVGDevice::imageInfo() const {
64 return fLegacyBitmap.info(); 243 return fLegacyBitmap.info();
65 } 244 }
66 245
67 const SkBitmap& SkSVGDevice::onAccessBitmap() { 246 const SkBitmap& SkSVGDevice::onAccessBitmap() {
68 return fLegacyBitmap; 247 return fLegacyBitmap;
69 } 248 }
70 249
71 void SkSVGDevice::addPaint(const SkPaint& paint) { 250 void SkSVGDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
72 SkColor color = paint.getColor(); 251 AutoElement rect("rect", fWriter, draw, paint);
73 SkString colorStr; 252 rect.addAttribute("x", 0);
74 colorStr.appendf("rgb(%u,%u,%u)", SkColorGetR(color), SkColorGetG(color), Sk ColorGetB(color)); 253 rect.addAttribute("y", 0);
75 254 rect.addAttribute("width", this->width());
76 SkPaint::Style style = paint.getStyle(); 255 rect.addAttribute("height", this->height());
77 if (style == SkPaint::kFill_Style || style == SkPaint::kStrokeAndFill_Style) {
78 fWriter->addAttribute("fill", colorStr.c_str());
79 } else {
80 fWriter->addAttribute("fill", "none");
81 }
82
83 if (style == SkPaint::kStroke_Style || style == SkPaint::kStrokeAndFill_Styl e) {
84 fWriter->addAttribute("stroke", colorStr.c_str());
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 } 256 }
107 257
108 void SkSVGDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t cou nt, 258 void SkSVGDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t cou nt,
109 const SkPoint[], const SkPaint& paint) { 259 const SkPoint[], const SkPaint& paint) {
110 // todo 260 // todo
261 SkDebugf("unsupported operation: drawPoints()");
111 } 262 }
112 263
113 void SkSVGDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& p aint) { 264 void SkSVGDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& p aint) {
114 AutoElement elem("rect", fWriter); 265 AutoElement rect("rect", fWriter, draw, paint);
115 266 rect.addAttribute("x", r.fLeft);
116 fWriter->addScalarAttribute("x", r.fLeft); 267 rect.addAttribute("y", r.fTop);
117 fWriter->addScalarAttribute("y", r.fTop); 268 rect.addAttribute("width", r.width());
118 fWriter->addScalarAttribute("width", r.width()); 269 rect.addAttribute("height", r.height());
119 fWriter->addScalarAttribute("height", r.height());
120
121 this->addPaint(paint);
122 this->addTransform(*draw.fMatrix);
123 } 270 }
124 271
125 void SkSVGDevice::drawOval(const SkDraw&, const SkRect& oval, const SkPaint& pai nt) { 272 void SkSVGDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint & paint) {
126 // todo 273 AutoElement ellipse("ellipse", fWriter, draw, paint);
274 ellipse.addAttribute("cx", oval.centerX());
275 ellipse.addAttribute("cy", oval.centerY());
276 ellipse.addAttribute("rx", oval.width() / 2);
277 ellipse.addAttribute("ry", oval.height() / 2);
127 } 278 }
128 279
129 void SkSVGDevice::drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& pai nt) { 280 void SkSVGDevice::drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& pai nt) {
130 // todo 281 // todo
282 SkDebugf("unsupported operation: drawRRect()");
131 } 283 }
132 284
133 void SkSVGDevice::drawPath(const SkDraw& draw, const SkPath& path, const SkPaint & paint, 285 void SkSVGDevice::drawPath(const SkDraw& draw, const SkPath& path, const SkPaint & paint,
134 const SkMatrix* prePathMatrix, bool pathIsMutable) { 286 const SkMatrix* prePathMatrix, bool pathIsMutable) {
135 AutoElement elem("path", fWriter); 287 AutoElement elem("path", fWriter, draw, paint);
136 288
137 SkString pathStr; 289 SkString pathStr;
138 SkParsePath::ToSVGString(path, &pathStr); 290 SkParsePath::ToSVGString(path, &pathStr);
139 fWriter->addAttribute("d", pathStr.c_str()); 291 elem.addAttribute("d", pathStr.c_str());
140
141 this->addPaint(paint);
142 this->addTransform(*draw.fMatrix);
143 } 292 }
144 293
145 void SkSVGDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, 294 void SkSVGDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap,
146 const SkMatrix& matrix, const SkPaint& paint) { 295 const SkMatrix& matrix, const SkPaint& paint) {
147 // todo 296 // todo
297 SkDebugf("unsupported operation: drawBitmap()");
148 } 298 }
149 299
150 void SkSVGDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, 300 void SkSVGDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap,
151 int x, int y, const SkPaint& paint) { 301 int x, int y, const SkPaint& paint) {
152 // todo 302 // todo
303 SkDebugf("unsupported operation: drawSprite()");
153 } 304 }
154 305
155 void SkSVGDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, const SkRect* s rcOrNull, 306 void SkSVGDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, const SkRect* s rcOrNull,
156 const SkRect& dst, const SkPaint& paint, 307 const SkRect& dst, const SkPaint& paint,
157 SkCanvas::DrawBitmapRectFlags flags) { 308 SkCanvas::DrawBitmapRectFlags flags) {
158 // todo 309 // todo
310 SkDebugf("unsupported operation: drawBitmapRect()");
159 } 311 }
160 312
161 void SkSVGDevice::drawText(const SkDraw&, const void* text, size_t len, 313 void SkSVGDevice::drawText(const SkDraw&, const void* text, size_t len,
162 SkScalar x, SkScalar y, const SkPaint& paint) { 314 SkScalar x, SkScalar y, const SkPaint& paint) {
163 // todo 315 // todo
316 SkDebugf("unsupported operation: drawText()");
164 } 317 }
165 318
166 void SkSVGDevice::drawPosText(const SkDraw&, const void* text, size_t len,const SkScalar pos[], 319 void SkSVGDevice::drawPosText(const SkDraw&, const void* text, size_t len,const SkScalar pos[],
167 int scalarsPerPos, const SkPoint& offset, const Sk Paint& paint) { 320 int scalarsPerPos, const SkPoint& offset, const Sk Paint& paint) {
168 // todo 321 // todo
322 SkDebugf("unsupported operation: drawPosText()");
169 } 323 }
170 324
171 void SkSVGDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, co nst SkPath& path, 325 void SkSVGDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, co nst SkPath& path,
172 const SkMatrix* matrix, const SkPaint& paint) { 326 const SkMatrix* matrix, const SkPaint& paint) {
173 // todo 327 // todo
328 SkDebugf("unsupported operation: drawTextOnPath()");
174 } 329 }
175 330
176 void SkSVGDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCo unt, 331 void SkSVGDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCo unt,
177 const SkPoint verts[], const SkPoint texs[], 332 const SkPoint verts[], const SkPoint texs[],
178 const SkColor colors[], SkXfermode* xmode, 333 const SkColor colors[], SkXfermode* xmode,
179 const uint16_t indices[], int indexCount, 334 const uint16_t indices[], int indexCount,
180 const SkPaint& paint) { 335 const SkPaint& paint) {
181 // todo 336 // todo
337 SkDebugf("unsupported operation: drawVertices()");
182 } 338 }
183 339
184 void SkSVGDevice::drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, 340 void SkSVGDevice::drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
185 const SkPaint&) { 341 const SkPaint&) {
186 // todo 342 // todo
343 SkDebugf("unsupported operation: drawDevice()");
187 } 344 }
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