| 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 |