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

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