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" |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 "round", // kRound_Join | 50 "round", // kRound_Join |
51 "bevel" // kBevel_Join | 51 "bevel" // kBevel_Join |
52 }; | 52 }; |
53 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(join_map) == SkPaint::kJoinCount, missing_join_
map_entry); | 53 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(join_map) == SkPaint::kJoinCount, missing_join_
map_entry); |
54 | 54 |
55 static const char* svg_join(SkPaint::Join join) { | 55 static const char* svg_join(SkPaint::Join join) { |
56 SkASSERT(join < SK_ARRAY_COUNT(join_map)); | 56 SkASSERT(join < SK_ARRAY_COUNT(join_map)); |
57 return join_map[join]; | 57 return join_map[join]; |
58 } | 58 } |
59 | 59 |
| 60 // Keep in sync with SkPaint::Align |
| 61 static const char* text_align_map[] = { |
| 62 NULL, // kLeft_Align (default) |
| 63 "middle", // kCenter_Align |
| 64 "end" // kRight_Align |
| 65 }; |
| 66 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(text_align_map) == SkPaint::kAlignCount, |
| 67 missing_text_align_map_entry); |
| 68 static const char* svg_text_align(SkPaint::Align align) { |
| 69 SkASSERT(align < SK_ARRAY_COUNT(text_align_map)); |
| 70 return text_align_map[align]; |
| 71 } |
| 72 |
| 73 static SkString svg_transform(const SkMatrix& t) { |
| 74 SkASSERT(!t.isIdentity()); |
| 75 |
| 76 SkString tstr; |
| 77 switch (t.getType()) { |
| 78 case SkMatrix::kPerspective_Mask: |
| 79 SkDebugf("Can't handle perspective matrices."); |
| 80 break; |
| 81 case SkMatrix::kTranslate_Mask: |
| 82 tstr.printf("translate(%g %g)", t.getTranslateX(), t.getTranslateY()); |
| 83 break; |
| 84 case SkMatrix::kScale_Mask: |
| 85 tstr.printf("scale(%g %g)", t.getScaleX(), t.getScaleY()); |
| 86 break; |
| 87 default: |
| 88 // http://www.w3.org/TR/SVG/coords.html#TransformMatrixDefined |
| 89 // | a c e | |
| 90 // | b d f | |
| 91 // | 0 0 1 | |
| 92 tstr.printf("matrix(%g %g %g %g %g %g)", |
| 93 t.getScaleX(), t.getSkewY(), |
| 94 t.getSkewX(), t.getScaleY(), |
| 95 t.getTranslateX(), t.getTranslateY()); |
| 96 break; |
| 97 } |
| 98 |
| 99 return tstr; |
| 100 } |
| 101 |
60 static void append_escaped_unichar(SkUnichar c, SkString* text) { | 102 static void append_escaped_unichar(SkUnichar c, SkString* text) { |
61 switch(c) { | 103 switch(c) { |
62 case '&': | 104 case '&': |
63 text->append("&"); | 105 text->append("&"); |
64 break; | 106 break; |
65 case '"': | 107 case '"': |
66 text->append("""); | 108 text->append("""); |
67 break; | 109 break; |
68 case '\'': | 110 case '\'': |
69 text->append("'"); | 111 text->append("'"); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
129 SkString fPaintServer; | 171 SkString fPaintServer; |
130 SkString fClip; | 172 SkString fClip; |
131 }; | 173 }; |
132 | 174 |
133 } | 175 } |
134 | 176 |
135 // For now all this does is serve unique serial IDs, but it will eventually evol
ve to track | 177 // For now all this does is serve unique serial IDs, but it will eventually evol
ve to track |
136 // and deduplicate resources. | 178 // and deduplicate resources. |
137 class SkSVGDevice::ResourceBucket : ::SkNoncopyable { | 179 class SkSVGDevice::ResourceBucket : ::SkNoncopyable { |
138 public: | 180 public: |
139 ResourceBucket() : fGradientCount(0), fClipCount(0) {} | 181 ResourceBucket() : fGradientCount(0), fClipCount(0), fPathCount(0) {} |
140 | 182 |
141 SkString addLinearGradient() { | 183 SkString addLinearGradient() { |
142 return SkStringPrintf("gradient_%d", fGradientCount++); | 184 return SkStringPrintf("gradient_%d", fGradientCount++); |
143 } | 185 } |
144 | 186 |
145 SkString addClip() { | 187 SkString addClip() { |
146 return SkStringPrintf("clip_%d", fClipCount++); | 188 return SkStringPrintf("clip_%d", fClipCount++); |
147 } | 189 } |
148 | 190 |
| 191 SkString addPath() { |
| 192 return SkStringPrintf("path_%d", fPathCount++); |
| 193 } |
| 194 |
149 private: | 195 private: |
150 uint32_t fGradientCount; | 196 uint32_t fGradientCount; |
151 uint32_t fClipCount; | 197 uint32_t fClipCount; |
| 198 uint32_t fPathCount; |
152 }; | 199 }; |
153 | 200 |
154 class SkSVGDevice::AutoElement : ::SkNoncopyable { | 201 class SkSVGDevice::AutoElement : ::SkNoncopyable { |
155 public: | 202 public: |
156 AutoElement(const char name[], SkXMLWriter* writer) | 203 AutoElement(const char name[], SkXMLWriter* writer) |
157 : fWriter(writer) | 204 : fWriter(writer) |
158 , fResourceBucket(NULL) { | 205 , fResourceBucket(NULL) { |
159 fWriter->startElement(name); | 206 fWriter->startElement(name); |
160 } | 207 } |
161 | 208 |
162 AutoElement(const char name[], SkXMLWriter* writer, ResourceBucket* bucket, | 209 AutoElement(const char name[], SkXMLWriter* writer, ResourceBucket* bucket, |
163 const SkDraw& draw, const SkPaint& paint) | 210 const SkDraw& draw, const SkPaint& paint) |
164 : fWriter(writer) | 211 : fWriter(writer) |
165 , fResourceBucket(bucket) { | 212 , fResourceBucket(bucket) { |
166 | 213 |
167 Resources res = this->addResources(draw, paint); | 214 Resources res = this->addResources(draw, paint); |
168 | 215 |
169 fWriter->startElement(name); | 216 fWriter->startElement(name); |
170 | 217 |
171 this->addPaint(paint, res); | 218 this->addPaint(paint, res); |
172 this->addTransform(*draw.fMatrix); | 219 |
| 220 if (!draw.fMatrix->isIdentity()) { |
| 221 this->addAttribute("transform", svg_transform(*draw.fMatrix)); |
| 222 } |
173 } | 223 } |
174 | 224 |
175 ~AutoElement() { | 225 ~AutoElement() { |
176 fWriter->endElement(); | 226 fWriter->endElement(); |
177 } | 227 } |
178 | 228 |
179 void addAttribute(const char name[], const char val[]) { | 229 void addAttribute(const char name[], const char val[]) { |
180 fWriter->addAttribute(name, val); | 230 fWriter->addAttribute(name, val); |
181 } | 231 } |
182 | 232 |
183 void addAttribute(const char name[], const SkString& val) { | 233 void addAttribute(const char name[], const SkString& val) { |
184 fWriter->addAttribute(name, val.c_str()); | 234 fWriter->addAttribute(name, val.c_str()); |
185 } | 235 } |
186 | 236 |
187 void addAttribute(const char name[], int32_t val) { | 237 void addAttribute(const char name[], int32_t val) { |
188 fWriter->addS32Attribute(name, val); | 238 fWriter->addS32Attribute(name, val); |
189 } | 239 } |
190 | 240 |
191 void addAttribute(const char name[], SkScalar val) { | 241 void addAttribute(const char name[], SkScalar val) { |
192 fWriter->addScalarAttribute(name, val); | 242 fWriter->addScalarAttribute(name, val); |
193 } | 243 } |
194 | 244 |
195 void addText(const SkString& text) { | 245 void addText(const SkString& text) { |
196 fWriter->addText(text.c_str()); | 246 fWriter->addText(text.c_str()); |
197 } | 247 } |
198 | 248 |
199 void addRectAttributes(const SkRect&); | 249 void addRectAttributes(const SkRect&); |
200 void addFontAttributes(const SkPaint&); | 250 void addPathAttributes(const SkPath&); |
| 251 void addTextAttributes(const SkPaint&); |
201 | 252 |
202 private: | 253 private: |
203 Resources addResources(const SkDraw& draw, const SkPaint& paint); | 254 Resources addResources(const SkDraw& draw, const SkPaint& paint); |
204 void addClipResources(const SkDraw& draw, Resources* resources); | 255 void addClipResources(const SkDraw& draw, Resources* resources); |
205 void addShaderResources(const SkPaint& paint, Resources* resources); | 256 void addShaderResources(const SkPaint& paint, Resources* resources); |
206 | 257 |
207 void addPaint(const SkPaint& paint, const Resources& resources); | 258 void addPaint(const SkPaint& paint, const Resources& resources); |
208 void addTransform(const SkMatrix& transform, const char name[] = "transform"
); | |
209 | 259 |
210 SkString addLinearGradientDef(const SkShader::GradientInfo& info, const SkSh
ader* shader); | 260 SkString addLinearGradientDef(const SkShader::GradientInfo& info, const SkSh
ader* shader); |
211 | 261 |
212 SkXMLWriter* fWriter; | 262 SkXMLWriter* fWriter; |
213 ResourceBucket* fResourceBucket; | 263 ResourceBucket* fResourceBucket; |
214 }; | 264 }; |
215 | 265 |
216 void SkSVGDevice::AutoElement::addPaint(const SkPaint& paint, const Resources& r
esources) { | 266 void SkSVGDevice::AutoElement::addPaint(const SkPaint& paint, const Resources& r
esources) { |
217 SkPaint::Style style = paint.getStyle(); | 267 SkPaint::Style style = paint.getStyle(); |
218 if (style == SkPaint::kFill_Style || style == SkPaint::kStrokeAndFill_Style)
{ | 268 if (style == SkPaint::kFill_Style || style == SkPaint::kStrokeAndFill_Style)
{ |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
255 } else { | 305 } else { |
256 SkASSERT(style == SkPaint::kFill_Style); | 306 SkASSERT(style == SkPaint::kFill_Style); |
257 this->addAttribute("stroke", "none"); | 307 this->addAttribute("stroke", "none"); |
258 } | 308 } |
259 | 309 |
260 if (!resources.fClip.isEmpty()) { | 310 if (!resources.fClip.isEmpty()) { |
261 this->addAttribute("clip-path", resources.fClip); | 311 this->addAttribute("clip-path", resources.fClip); |
262 } | 312 } |
263 } | 313 } |
264 | 314 |
265 void SkSVGDevice::AutoElement::addTransform(const SkMatrix& t, const char name[]
) { | |
266 if (t.isIdentity()) { | |
267 return; | |
268 } | |
269 | |
270 SkString tstr; | |
271 switch (t.getType()) { | |
272 case SkMatrix::kPerspective_Mask: | |
273 SkDebugf("Can't handle perspective matrices."); | |
274 break; | |
275 case SkMatrix::kTranslate_Mask: | |
276 tstr.printf("translate(%g %g)", | |
277 SkScalarToFloat(t.getTranslateX()), | |
278 SkScalarToFloat(t.getTranslateY())); | |
279 break; | |
280 case SkMatrix::kScale_Mask: | |
281 tstr.printf("scale(%g %g)", | |
282 SkScalarToFloat(t.getScaleX()), | |
283 SkScalarToFloat(t.getScaleY())); | |
284 break; | |
285 default: | |
286 tstr.printf("matrix(%g %g %g %g %g %g)", | |
287 SkScalarToFloat(t.getScaleX()), SkScalarToFloat(t.getSkewY(
)), | |
288 SkScalarToFloat(t.getSkewX()), SkScalarToFloat(t.getScaleY(
)), | |
289 SkScalarToFloat(t.getTranslateX()), SkScalarToFloat(t.getTr
anslateY())); | |
290 break; | |
291 } | |
292 | |
293 fWriter->addAttribute(name, tstr.c_str()); | |
294 } | |
295 | |
296 Resources SkSVGDevice::AutoElement::addResources(const SkDraw& draw, const SkPai
nt& paint) { | 315 Resources SkSVGDevice::AutoElement::addResources(const SkDraw& draw, const SkPai
nt& paint) { |
297 Resources resources(paint); | 316 Resources resources(paint); |
298 | 317 |
299 // FIXME: this is a weak heuristic and we end up with LOTS of redundant clip
s. | 318 // FIXME: this is a weak heuristic and we end up with LOTS of redundant clip
s. |
300 bool hasClip = !draw.fClipStack->isWideOpen(); | 319 bool hasClip = !draw.fClipStack->isWideOpen(); |
301 bool hasShader = SkToBool(paint.getShader()); | 320 bool hasShader = SkToBool(paint.getShader()); |
302 | 321 |
303 if (hasClip || hasShader) { | 322 if (hasClip || hasShader) { |
304 AutoElement defs("defs", fWriter); | 323 AutoElement defs("defs", fWriter); |
305 | 324 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 AutoElement clipPathElement("clipPath", fWriter); | 374 AutoElement clipPathElement("clipPath", fWriter); |
356 clipPathElement.addAttribute("id", clipID); | 375 clipPathElement.addAttribute("id", clipID); |
357 | 376 |
358 SkRect clipRect = SkRect::MakeEmpty(); | 377 SkRect clipRect = SkRect::MakeEmpty(); |
359 if (clipPath.isEmpty() || clipPath.isRect(&clipRect)) { | 378 if (clipPath.isEmpty() || clipPath.isRect(&clipRect)) { |
360 AutoElement rectElement("rect", fWriter); | 379 AutoElement rectElement("rect", fWriter); |
361 rectElement.addRectAttributes(clipRect); | 380 rectElement.addRectAttributes(clipRect); |
362 rectElement.addAttribute("clip-rule", clipRule); | 381 rectElement.addAttribute("clip-rule", clipRule); |
363 } else { | 382 } else { |
364 AutoElement pathElement("path", fWriter); | 383 AutoElement pathElement("path", fWriter); |
365 SkString pathStr; | 384 pathElement.addPathAttributes(clipPath); |
366 SkParsePath::ToSVGString(clipPath, &pathStr); | |
367 pathElement.addAttribute("d", pathStr.c_str()); | |
368 pathElement.addAttribute("clip-rule", clipRule); | 385 pathElement.addAttribute("clip-rule", clipRule); |
369 } | 386 } |
370 } | 387 } |
371 | 388 |
372 resources->fClip.printf("url(#%s)", clipID.c_str()); | 389 resources->fClip.printf("url(#%s)", clipID.c_str()); |
373 } | 390 } |
374 | 391 |
375 SkString SkSVGDevice::AutoElement::addLinearGradientDef(const SkShader::Gradient
Info& info, | 392 SkString SkSVGDevice::AutoElement::addLinearGradientDef(const SkShader::Gradient
Info& info, |
376 const SkShader* shader)
{ | 393 const SkShader* shader)
{ |
377 SkASSERT(fResourceBucket); | 394 SkASSERT(fResourceBucket); |
378 SkString id = fResourceBucket->addLinearGradient(); | 395 SkString id = fResourceBucket->addLinearGradient(); |
379 | 396 |
380 { | 397 { |
381 AutoElement gradient("linearGradient", fWriter); | 398 AutoElement gradient("linearGradient", fWriter); |
382 | 399 |
383 gradient.addAttribute("id", id); | 400 gradient.addAttribute("id", id); |
384 gradient.addAttribute("gradientUnits", "userSpaceOnUse"); | 401 gradient.addAttribute("gradientUnits", "userSpaceOnUse"); |
385 gradient.addAttribute("x1", info.fPoint[0].x()); | 402 gradient.addAttribute("x1", info.fPoint[0].x()); |
386 gradient.addAttribute("y1", info.fPoint[0].y()); | 403 gradient.addAttribute("y1", info.fPoint[0].y()); |
387 gradient.addAttribute("x2", info.fPoint[1].x()); | 404 gradient.addAttribute("x2", info.fPoint[1].x()); |
388 gradient.addAttribute("y2", info.fPoint[1].y()); | 405 gradient.addAttribute("y2", info.fPoint[1].y()); |
389 gradient.addTransform(shader->getLocalMatrix(), "gradientTransform"); | 406 |
| 407 if (!shader->getLocalMatrix().isIdentity()) { |
| 408 this->addAttribute("gradientTransform", svg_transform(shader->getLoc
alMatrix())); |
| 409 } |
390 | 410 |
391 SkASSERT(info.fColorCount >= 2); | 411 SkASSERT(info.fColorCount >= 2); |
392 for (int i = 0; i < info.fColorCount; ++i) { | 412 for (int i = 0; i < info.fColorCount; ++i) { |
393 SkColor color = info.fColors[i]; | 413 SkColor color = info.fColors[i]; |
394 SkString colorStr(svg_color(color)); | 414 SkString colorStr(svg_color(color)); |
395 | 415 |
396 { | 416 { |
397 AutoElement stop("stop", fWriter); | 417 AutoElement stop("stop", fWriter); |
398 stop.addAttribute("offset", info.fColorOffsets[i]); | 418 stop.addAttribute("offset", info.fColorOffsets[i]); |
399 stop.addAttribute("stop-color", colorStr.c_str()); | 419 stop.addAttribute("stop-color", colorStr.c_str()); |
(...skipping 14 matching lines...) Expand all Loading... |
414 this->addAttribute("x", rect.x()); | 434 this->addAttribute("x", rect.x()); |
415 } | 435 } |
416 if (rect.y() != 0) { | 436 if (rect.y() != 0) { |
417 this->addAttribute("y", rect.y()); | 437 this->addAttribute("y", rect.y()); |
418 } | 438 } |
419 | 439 |
420 this->addAttribute("width", rect.width()); | 440 this->addAttribute("width", rect.width()); |
421 this->addAttribute("height", rect.height()); | 441 this->addAttribute("height", rect.height()); |
422 } | 442 } |
423 | 443 |
424 void SkSVGDevice::AutoElement::addFontAttributes(const SkPaint& paint) { | 444 void SkSVGDevice::AutoElement::addPathAttributes(const SkPath& path) { |
| 445 SkString pathData; |
| 446 SkParsePath::ToSVGString(path, &pathData); |
| 447 this->addAttribute("d", pathData); |
| 448 } |
| 449 |
| 450 void SkSVGDevice::AutoElement::addTextAttributes(const SkPaint& paint) { |
425 this->addAttribute("font-size", paint.getTextSize()); | 451 this->addAttribute("font-size", paint.getTextSize()); |
426 | 452 |
427 SkTypeface::Style style = paint.getTypeface()->style(); | 453 SkTypeface::Style style = paint.getTypeface()->style(); |
428 if (style & SkTypeface::kItalic) { | 454 if (style & SkTypeface::kItalic) { |
429 this->addAttribute("font-style", "italic"); | 455 this->addAttribute("font-style", "italic"); |
430 } | 456 } |
431 if (style & SkTypeface::kBold) { | 457 if (style & SkTypeface::kBold) { |
432 this->addAttribute("font-weight", "bold"); | 458 this->addAttribute("font-weight", "bold"); |
433 } | 459 } |
434 | 460 |
435 SkAutoTUnref<const SkTypeface> tface(paint.getTypeface() ? | 461 SkAutoTUnref<const SkTypeface> tface(paint.getTypeface() ? |
436 SkRef(paint.getTypeface()) : SkTypeface::RefDefault(style)); | 462 SkRef(paint.getTypeface()) : SkTypeface::RefDefault(style)); |
437 SkString familyName; | 463 SkString familyName; |
438 tface->getFamilyName(&familyName); | 464 tface->getFamilyName(&familyName); |
439 if (!familyName.isEmpty()) { | 465 if (!familyName.isEmpty()) { |
440 this->addAttribute("font-family", familyName); | 466 this->addAttribute("font-family", familyName); |
441 } | 467 } |
| 468 |
| 469 if (const char* textAlign = svg_text_align(paint.getTextAlign())) { |
| 470 this->addAttribute("text-anchor", textAlign); |
| 471 } |
442 } | 472 } |
443 | 473 |
444 SkBaseDevice* SkSVGDevice::Create(const SkISize& size, SkWStream* wstream) { | 474 SkBaseDevice* SkSVGDevice::Create(const SkISize& size, SkWStream* wstream) { |
445 if (!SkToBool(wstream)) { | 475 if (!SkToBool(wstream)) { |
446 return NULL; | 476 return NULL; |
447 } | 477 } |
448 | 478 |
449 return SkNEW_ARGS(SkSVGDevice, (size, wstream)); | 479 return SkNEW_ARGS(SkSVGDevice, (size, wstream)); |
450 } | 480 } |
451 | 481 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
503 } | 533 } |
504 | 534 |
505 void SkSVGDevice::drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& pai
nt) { | 535 void SkSVGDevice::drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& pai
nt) { |
506 // todo | 536 // todo |
507 SkDebugf("unsupported operation: drawRRect()\n"); | 537 SkDebugf("unsupported operation: drawRRect()\n"); |
508 } | 538 } |
509 | 539 |
510 void SkSVGDevice::drawPath(const SkDraw& draw, const SkPath& path, const SkPaint
& paint, | 540 void SkSVGDevice::drawPath(const SkDraw& draw, const SkPath& path, const SkPaint
& paint, |
511 const SkMatrix* prePathMatrix, bool pathIsMutable) { | 541 const SkMatrix* prePathMatrix, bool pathIsMutable) { |
512 AutoElement elem("path", fWriter, fResourceBucket, draw, paint); | 542 AutoElement elem("path", fWriter, fResourceBucket, draw, paint); |
513 | 543 elem.addPathAttributes(path); |
514 SkString pathStr; | |
515 SkParsePath::ToSVGString(path, &pathStr); | |
516 elem.addAttribute("d", pathStr.c_str()); | |
517 } | 544 } |
518 | 545 |
519 void SkSVGDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, | 546 void SkSVGDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, |
520 const SkMatrix& matrix, const SkPaint& paint) { | 547 const SkMatrix& matrix, const SkPaint& paint) { |
521 // todo | 548 // todo |
522 SkDebugf("unsupported operation: drawBitmap()\n"); | 549 SkDebugf("unsupported operation: drawBitmap()\n"); |
523 } | 550 } |
524 | 551 |
525 void SkSVGDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, | 552 void SkSVGDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, |
526 int x, int y, const SkPaint& paint) { | 553 int x, int y, const SkPaint& paint) { |
527 // todo | 554 // todo |
528 SkDebugf("unsupported operation: drawSprite()\n"); | 555 SkDebugf("unsupported operation: drawSprite()\n"); |
529 } | 556 } |
530 | 557 |
531 void SkSVGDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, const SkRect* s
rcOrNull, | 558 void SkSVGDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, const SkRect* s
rcOrNull, |
532 const SkRect& dst, const SkPaint& paint, | 559 const SkRect& dst, const SkPaint& paint, |
533 SkCanvas::DrawBitmapRectFlags flags) { | 560 SkCanvas::DrawBitmapRectFlags flags) { |
534 // todo | 561 // todo |
535 SkDebugf("unsupported operation: drawBitmapRect()\n"); | 562 SkDebugf("unsupported operation: drawBitmapRect()\n"); |
536 } | 563 } |
537 | 564 |
538 void SkSVGDevice::drawText(const SkDraw& draw, const void* text, size_t len, | 565 void SkSVGDevice::drawText(const SkDraw& draw, const void* text, size_t len, |
539 SkScalar x, SkScalar y, const SkPaint& paint) { | 566 SkScalar x, SkScalar y, const SkPaint& paint) { |
540 AutoElement elem("text", fWriter, fResourceBucket, draw, paint); | 567 AutoElement elem("text", fWriter, fResourceBucket, draw, paint); |
541 elem.addFontAttributes(paint); | 568 elem.addTextAttributes(paint); |
542 elem.addAttribute("x", x); | 569 elem.addAttribute("x", x); |
543 elem.addAttribute("y", y); | 570 elem.addAttribute("y", y); |
544 elem.addText(svg_text(text, len, paint)); | 571 elem.addText(svg_text(text, len, paint)); |
545 } | 572 } |
546 | 573 |
547 void SkSVGDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, | 574 void SkSVGDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, |
548 const SkScalar pos[], int scalarsPerPos, const SkP
oint& offset, | 575 const SkScalar pos[], int scalarsPerPos, const SkP
oint& offset, |
549 const SkPaint& paint) { | 576 const SkPaint& paint) { |
550 SkASSERT(scalarsPerPos == 1 || scalarsPerPos == 2); | 577 SkASSERT(scalarsPerPos == 1 || scalarsPerPos == 2); |
551 | 578 |
552 AutoElement elem("text", fWriter, fResourceBucket, draw, paint); | 579 AutoElement elem("text", fWriter, fResourceBucket, draw, paint); |
553 elem.addFontAttributes(paint); | 580 elem.addTextAttributes(paint); |
554 | 581 |
555 SkString xStr; | 582 SkString xStr; |
556 SkString yStr; | 583 SkString yStr; |
557 for (int i = 0; i < paint.countText(text, len); ++i) { | 584 for (int i = 0; i < paint.countText(text, len); ++i) { |
558 xStr.appendf("%.8g, ", offset.x() + pos[i * scalarsPerPos]); | 585 xStr.appendf("%.8g, ", offset.x() + pos[i * scalarsPerPos]); |
559 | 586 |
560 if (scalarsPerPos == 2) { | 587 if (scalarsPerPos == 2) { |
561 yStr.appendf("%.8g, ", offset.y() + pos[i * scalarsPerPos + 1]); | 588 yStr.appendf("%.8g, ", offset.y() + pos[i * scalarsPerPos + 1]); |
562 } | 589 } |
563 } | 590 } |
564 | 591 |
565 if (scalarsPerPos != 2) { | 592 if (scalarsPerPos != 2) { |
566 yStr.appendScalar(offset.y()); | 593 yStr.appendScalar(offset.y()); |
567 } | 594 } |
568 | 595 |
569 elem.addAttribute("x", xStr); | 596 elem.addAttribute("x", xStr); |
570 elem.addAttribute("y", yStr); | 597 elem.addAttribute("y", yStr); |
571 elem.addText(svg_text(text, len, paint)); | 598 elem.addText(svg_text(text, len, paint)); |
572 } | 599 } |
573 | 600 |
574 void SkSVGDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, co
nst SkPath& path, | 601 void SkSVGDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, co
nst SkPath& path, |
575 const SkMatrix* matrix, const SkPaint& paint) { | 602 const SkMatrix* matrix, const SkPaint& paint) { |
576 // todo | 603 SkString pathID = fResourceBucket->addPath(); |
577 SkDebugf("unsupported operation: drawTextOnPath()\n"); | 604 |
| 605 { |
| 606 AutoElement defs("defs", fWriter); |
| 607 AutoElement pathElement("path", fWriter); |
| 608 pathElement.addAttribute("id", pathID); |
| 609 pathElement.addPathAttributes(path); |
| 610 |
| 611 } |
| 612 |
| 613 { |
| 614 AutoElement textElement("text", fWriter); |
| 615 textElement.addTextAttributes(paint); |
| 616 |
| 617 if (matrix && !matrix->isIdentity()) { |
| 618 textElement.addAttribute("transform", svg_transform(*matrix)); |
| 619 } |
| 620 |
| 621 { |
| 622 AutoElement textPathElement("textPath", fWriter); |
| 623 textPathElement.addAttribute("xlink:href", SkStringPrintf("#%s", pat
hID.c_str())); |
| 624 |
| 625 if (paint.getTextAlign() != SkPaint::kLeft_Align) { |
| 626 SkASSERT(paint.getTextAlign() == SkPaint::kCenter_Align || |
| 627 paint.getTextAlign() == SkPaint::kRight_Align); |
| 628 textPathElement.addAttribute("startOffset", |
| 629 paint.getTextAlign() == SkPaint::kCenter_Align ? "50%" : "10
0%"); |
| 630 } |
| 631 |
| 632 textPathElement.addText(svg_text(text, len, paint)); |
| 633 } |
| 634 } |
578 } | 635 } |
579 | 636 |
580 void SkSVGDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCo
unt, | 637 void SkSVGDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCo
unt, |
581 const SkPoint verts[], const SkPoint texs[], | 638 const SkPoint verts[], const SkPoint texs[], |
582 const SkColor colors[], SkXfermode* xmode, | 639 const SkColor colors[], SkXfermode* xmode, |
583 const uint16_t indices[], int indexCount, | 640 const uint16_t indices[], int indexCount, |
584 const SkPaint& paint) { | 641 const SkPaint& paint) { |
585 // todo | 642 // todo |
586 SkDebugf("unsupported operation: drawVertices()\n"); | 643 SkDebugf("unsupported operation: drawVertices()\n"); |
587 } | 644 } |
588 | 645 |
589 void SkSVGDevice::drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, | 646 void SkSVGDevice::drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, |
590 const SkPaint&) { | 647 const SkPaint&) { |
591 // todo | 648 // todo |
592 SkDebugf("unsupported operation: drawDevice()\n"); | 649 SkDebugf("unsupported operation: drawDevice()\n"); |
593 } | 650 } |
OLD | NEW |