| 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 "SkBase64.h" |
| 10 #include "SkBitmap.h" | 11 #include "SkBitmap.h" |
| 11 #include "SkChecksum.h" | 12 #include "SkChecksum.h" |
| 13 #include "SkData.h" |
| 12 #include "SkDraw.h" | 14 #include "SkDraw.h" |
| 15 #include "SkImageEncoder.h" |
| 13 #include "SkPaint.h" | 16 #include "SkPaint.h" |
| 14 #include "SkParsePath.h" | 17 #include "SkParsePath.h" |
| 15 #include "SkPathOps.h" | |
| 16 #include "SkShader.h" | 18 #include "SkShader.h" |
| 17 #include "SkStream.h" | 19 #include "SkStream.h" |
| 18 #include "SkTHash.h" | 20 #include "SkTHash.h" |
| 19 #include "SkTypeface.h" | 21 #include "SkTypeface.h" |
| 20 #include "SkUtils.h" | 22 #include "SkUtils.h" |
| 21 #include "SkXMLWriter.h" | 23 #include "SkXMLWriter.h" |
| 22 | 24 |
| 23 namespace { | 25 namespace { |
| 24 | 26 |
| 25 static SkString svg_color(SkColor color) { | 27 static SkString svg_color(SkColor color) { |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 244 SkString fText, fPosX, fPosY; | 246 SkString fText, fPosX, fPosY; |
| 245 bool fLastCharWasWhitespace; | 247 bool fLastCharWasWhitespace; |
| 246 }; | 248 }; |
| 247 | 249 |
| 248 } | 250 } |
| 249 | 251 |
| 250 // For now all this does is serve unique serial IDs, but it will eventually evol
ve to track | 252 // For now all this does is serve unique serial IDs, but it will eventually evol
ve to track |
| 251 // and deduplicate resources. | 253 // and deduplicate resources. |
| 252 class SkSVGDevice::ResourceBucket : ::SkNoncopyable { | 254 class SkSVGDevice::ResourceBucket : ::SkNoncopyable { |
| 253 public: | 255 public: |
| 254 ResourceBucket() : fGradientCount(0), fClipCount(0), fPathCount(0) {} | 256 ResourceBucket() : fGradientCount(0), fClipCount(0), fPathCount(0), fImageCo
unt(0) {} |
| 255 | 257 |
| 256 SkString addLinearGradient() { | 258 SkString addLinearGradient() { |
| 257 return SkStringPrintf("gradient_%d", fGradientCount++); | 259 return SkStringPrintf("gradient_%d", fGradientCount++); |
| 258 } | 260 } |
| 259 | 261 |
| 260 SkString addClip() { | 262 SkString addClip() { |
| 261 return SkStringPrintf("clip_%d", fClipCount++); | 263 return SkStringPrintf("clip_%d", fClipCount++); |
| 262 } | 264 } |
| 263 | 265 |
| 264 SkString addPath() { | 266 SkString addPath() { |
| 265 return SkStringPrintf("path_%d", fPathCount++); | 267 return SkStringPrintf("path_%d", fPathCount++); |
| 266 } | 268 } |
| 267 | 269 |
| 270 SkString addImage() { |
| 271 return SkStringPrintf("img_%d", fImageCount++); |
| 272 } |
| 273 |
| 268 private: | 274 private: |
| 269 uint32_t fGradientCount; | 275 uint32_t fGradientCount; |
| 270 uint32_t fClipCount; | 276 uint32_t fClipCount; |
| 271 uint32_t fPathCount; | 277 uint32_t fPathCount; |
| 278 uint32_t fImageCount; |
| 272 }; | 279 }; |
| 273 | 280 |
| 274 class SkSVGDevice::AutoElement : ::SkNoncopyable { | 281 class SkSVGDevice::AutoElement : ::SkNoncopyable { |
| 275 public: | 282 public: |
| 276 AutoElement(const char name[], SkXMLWriter* writer) | 283 AutoElement(const char name[], SkXMLWriter* writer) |
| 277 : fWriter(writer) | 284 : fWriter(writer) |
| 278 , fResourceBucket(NULL) { | 285 , fResourceBucket(NULL) { |
| 279 fWriter->startElement(name); | 286 fWriter->startElement(name); |
| 280 } | 287 } |
| 281 | 288 |
| 282 AutoElement(const char name[], SkXMLWriter* writer, ResourceBucket* bucket, | 289 AutoElement(const char name[], SkXMLWriter* writer, ResourceBucket* bucket, |
| 283 const SkDraw& draw, const SkPaint& paint) | 290 const SkDraw& draw, const SkPaint& paint) |
| 284 : fWriter(writer) | 291 : fWriter(writer) |
| 285 , fResourceBucket(bucket) { | 292 , fResourceBucket(bucket) { |
| 286 | 293 |
| 287 Resources res = this->addResources(draw, paint); | 294 Resources res = this->addResources(draw, paint); |
| 295 if (!res.fClip.isEmpty()) { |
| 296 // The clip is in device space. Apply it via a <g> wrapper to avoid
local transform |
| 297 // interference. |
| 298 fClipGroup.reset(SkNEW_ARGS(AutoElement, ("g", fWriter))); |
| 299 fClipGroup->addAttribute("clip-path",res.fClip); |
| 300 } |
| 288 | 301 |
| 289 fWriter->startElement(name); | 302 fWriter->startElement(name); |
| 290 | 303 |
| 291 this->addPaint(paint, res); | 304 this->addPaint(paint, res); |
| 292 | 305 |
| 293 if (!draw.fMatrix->isIdentity()) { | 306 if (!draw.fMatrix->isIdentity()) { |
| 294 this->addAttribute("transform", svg_transform(*draw.fMatrix)); | 307 this->addAttribute("transform", svg_transform(*draw.fMatrix)); |
| 295 } | 308 } |
| 296 } | 309 } |
| 297 | 310 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 325 | 338 |
| 326 private: | 339 private: |
| 327 Resources addResources(const SkDraw& draw, const SkPaint& paint); | 340 Resources addResources(const SkDraw& draw, const SkPaint& paint); |
| 328 void addClipResources(const SkDraw& draw, Resources* resources); | 341 void addClipResources(const SkDraw& draw, Resources* resources); |
| 329 void addShaderResources(const SkPaint& paint, Resources* resources); | 342 void addShaderResources(const SkPaint& paint, Resources* resources); |
| 330 | 343 |
| 331 void addPaint(const SkPaint& paint, const Resources& resources); | 344 void addPaint(const SkPaint& paint, const Resources& resources); |
| 332 | 345 |
| 333 SkString addLinearGradientDef(const SkShader::GradientInfo& info, const SkSh
ader* shader); | 346 SkString addLinearGradientDef(const SkShader::GradientInfo& info, const SkSh
ader* shader); |
| 334 | 347 |
| 335 SkXMLWriter* fWriter; | 348 SkXMLWriter* fWriter; |
| 336 ResourceBucket* fResourceBucket; | 349 ResourceBucket* fResourceBucket; |
| 350 SkAutoTDelete<AutoElement> fClipGroup; |
| 337 }; | 351 }; |
| 338 | 352 |
| 339 void SkSVGDevice::AutoElement::addPaint(const SkPaint& paint, const Resources& r
esources) { | 353 void SkSVGDevice::AutoElement::addPaint(const SkPaint& paint, const Resources& r
esources) { |
| 340 SkPaint::Style style = paint.getStyle(); | 354 SkPaint::Style style = paint.getStyle(); |
| 341 if (style == SkPaint::kFill_Style || style == SkPaint::kStrokeAndFill_Style)
{ | 355 if (style == SkPaint::kFill_Style || style == SkPaint::kStrokeAndFill_Style)
{ |
| 342 this->addAttribute("fill", resources.fPaintServer); | 356 this->addAttribute("fill", resources.fPaintServer); |
| 343 | 357 |
| 344 if (SK_AlphaOPAQUE != SkColorGetA(paint.getColor())) { | 358 if (SK_AlphaOPAQUE != SkColorGetA(paint.getColor())) { |
| 345 this->addAttribute("fill-opacity", svg_opacity(paint.getColor())); | 359 this->addAttribute("fill-opacity", svg_opacity(paint.getColor())); |
| 346 } | 360 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 372 this->addAttribute("stroke-miterlimit", paint.getStrokeMiter()); | 386 this->addAttribute("stroke-miterlimit", paint.getStrokeMiter()); |
| 373 } | 387 } |
| 374 | 388 |
| 375 if (SK_AlphaOPAQUE != SkColorGetA(paint.getColor())) { | 389 if (SK_AlphaOPAQUE != SkColorGetA(paint.getColor())) { |
| 376 this->addAttribute("stroke-opacity", svg_opacity(paint.getColor())); | 390 this->addAttribute("stroke-opacity", svg_opacity(paint.getColor())); |
| 377 } | 391 } |
| 378 } else { | 392 } else { |
| 379 SkASSERT(style == SkPaint::kFill_Style); | 393 SkASSERT(style == SkPaint::kFill_Style); |
| 380 this->addAttribute("stroke", "none"); | 394 this->addAttribute("stroke", "none"); |
| 381 } | 395 } |
| 382 | |
| 383 if (!resources.fClip.isEmpty()) { | |
| 384 this->addAttribute("clip-path", resources.fClip); | |
| 385 } | |
| 386 } | 396 } |
| 387 | 397 |
| 388 Resources SkSVGDevice::AutoElement::addResources(const SkDraw& draw, const SkPai
nt& paint) { | 398 Resources SkSVGDevice::AutoElement::addResources(const SkDraw& draw, const SkPai
nt& paint) { |
| 389 Resources resources(paint); | 399 Resources resources(paint); |
| 390 | 400 |
| 391 // FIXME: this is a weak heuristic and we end up with LOTS of redundant clip
s. | 401 // FIXME: this is a weak heuristic and we end up with LOTS of redundant clip
s. |
| 392 bool hasClip = !draw.fClipStack->isWideOpen(); | 402 bool hasClip = !draw.fClipStack->isWideOpen(); |
| 393 bool hasShader = SkToBool(paint.getShader()); | 403 bool hasShader = SkToBool(paint.getShader()); |
| 394 | 404 |
| 395 if (hasClip || hasShader) { | 405 if (hasClip || hasShader) { |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 622 // todo | 632 // todo |
| 623 SkDebugf("unsupported operation: drawRRect()\n"); | 633 SkDebugf("unsupported operation: drawRRect()\n"); |
| 624 } | 634 } |
| 625 | 635 |
| 626 void SkSVGDevice::drawPath(const SkDraw& draw, const SkPath& path, const SkPaint
& paint, | 636 void SkSVGDevice::drawPath(const SkDraw& draw, const SkPath& path, const SkPaint
& paint, |
| 627 const SkMatrix* prePathMatrix, bool pathIsMutable) { | 637 const SkMatrix* prePathMatrix, bool pathIsMutable) { |
| 628 AutoElement elem("path", fWriter, fResourceBucket, draw, paint); | 638 AutoElement elem("path", fWriter, fResourceBucket, draw, paint); |
| 629 elem.addPathAttributes(path); | 639 elem.addPathAttributes(path); |
| 630 } | 640 } |
| 631 | 641 |
| 632 void SkSVGDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, | 642 void SkSVGDevice::drawBitmapCommon(const SkDraw& draw, const SkBitmap& bm, |
| 633 const SkMatrix& matrix, const SkPaint& paint) { | 643 const SkPaint& paint) { |
| 634 // todo | 644 SkAutoTUnref<const SkData> pngData( |
| 635 SkDebugf("unsupported operation: drawBitmap()\n"); | 645 SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, SkImageEncoder
::kDefaultQuality)); |
| 646 if (!pngData) { |
| 647 return; |
| 648 } |
| 649 |
| 650 size_t b64Size = SkBase64::Encode(pngData->data(), pngData->size(), NULL); |
| 651 SkAutoTMalloc<char> b64Data(b64Size); |
| 652 SkBase64::Encode(pngData->data(), pngData->size(), b64Data.get()); |
| 653 |
| 654 SkString svgImageData("data:image/png;base64,"); |
| 655 svgImageData.append(b64Data.get(), b64Size); |
| 656 |
| 657 SkString imageID = fResourceBucket->addImage(); |
| 658 { |
| 659 AutoElement defs("defs", fWriter); |
| 660 { |
| 661 AutoElement image("image", fWriter); |
| 662 image.addAttribute("id", imageID); |
| 663 image.addAttribute("width", bm.width()); |
| 664 image.addAttribute("height", bm.height()); |
| 665 image.addAttribute("xlink:href", svgImageData); |
| 666 } |
| 667 } |
| 668 |
| 669 { |
| 670 AutoElement imageUse("use", fWriter, fResourceBucket, draw, paint); |
| 671 imageUse.addAttribute("xlink:href", SkStringPrintf("#%s", imageID.c_str(
))); |
| 672 } |
| 636 } | 673 } |
| 637 | 674 |
| 638 void SkSVGDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, | 675 void SkSVGDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, |
| 639 int x, int y, const SkPaint& paint) { | 676 const SkMatrix& matrix, const SkPaint& paint) { |
| 640 // todo | 677 SkMatrix adjustedMatrix = *draw.fMatrix; |
| 641 SkDebugf("unsupported operation: drawSprite()\n"); | 678 adjustedMatrix.preConcat(matrix); |
| 679 SkDraw adjustedDraw(draw); |
| 680 adjustedDraw.fMatrix = &adjustedMatrix; |
| 681 |
| 682 drawBitmapCommon(adjustedDraw, bitmap, paint); |
| 642 } | 683 } |
| 643 | 684 |
| 644 void SkSVGDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, const SkRect* s
rcOrNull, | 685 void SkSVGDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, |
| 686 int x, int y, const SkPaint& paint) { |
| 687 SkMatrix adjustedMatrix = *draw.fMatrix; |
| 688 adjustedMatrix.preTranslate(SkIntToScalar(x), SkIntToScalar(y)); |
| 689 SkDraw adjustedDraw(draw); |
| 690 adjustedDraw.fMatrix = &adjustedMatrix; |
| 691 |
| 692 drawBitmapCommon(adjustedDraw, bitmap, paint); |
| 693 } |
| 694 |
| 695 void SkSVGDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bm, const S
kRect* srcOrNull, |
| 645 const SkRect& dst, const SkPaint& paint, | 696 const SkRect& dst, const SkPaint& paint, |
| 646 SkCanvas::DrawBitmapRectFlags flags) { | 697 SkCanvas::DrawBitmapRectFlags) { |
| 647 // todo | 698 SkMatrix adjustedMatrix; |
| 648 SkDebugf("unsupported operation: drawBitmapRect()\n"); | 699 adjustedMatrix.setRectToRect(srcOrNull ? *srcOrNull : SkRect::Make(bm.bounds
()), |
| 700 dst, |
| 701 SkMatrix::kFill_ScaleToFit); |
| 702 adjustedMatrix.postConcat(*draw.fMatrix); |
| 703 |
| 704 SkDraw adjustedDraw(draw); |
| 705 adjustedDraw.fMatrix = &adjustedMatrix; |
| 706 |
| 707 SkClipStack adjustedClipStack; |
| 708 if (srcOrNull && *srcOrNull != SkRect::Make(bm.bounds())) { |
| 709 SkRect devClipRect; |
| 710 draw.fMatrix->mapRect(&devClipRect, dst); |
| 711 |
| 712 adjustedClipStack = *draw.fClipStack; |
| 713 adjustedClipStack.clipDevRect(devClipRect, SkRegion::kIntersect_Op, pain
t.isAntiAlias()); |
| 714 adjustedDraw.fClipStack = &adjustedClipStack; |
| 715 } |
| 716 |
| 717 drawBitmapCommon(adjustedDraw, bm, paint); |
| 649 } | 718 } |
| 650 | 719 |
| 651 void SkSVGDevice::drawText(const SkDraw& draw, const void* text, size_t len, | 720 void SkSVGDevice::drawText(const SkDraw& draw, const void* text, size_t len, |
| 652 SkScalar x, SkScalar y, const SkPaint& paint) { | 721 SkScalar x, SkScalar y, const SkPaint& paint) { |
| 653 AutoElement elem("text", fWriter, fResourceBucket, draw, paint); | 722 AutoElement elem("text", fWriter, fResourceBucket, draw, paint); |
| 654 elem.addTextAttributes(paint); | 723 elem.addTextAttributes(paint); |
| 655 | 724 |
| 656 SVGTextBuilder builder(text, len, paint, SkPoint::Make(x, y), 0); | 725 SVGTextBuilder builder(text, len, paint, SkPoint::Make(x, y), 0); |
| 657 elem.addAttribute("x", builder.posX()); | 726 elem.addAttribute("x", builder.posX()); |
| 658 elem.addAttribute("y", builder.posY()); | 727 elem.addAttribute("y", builder.posY()); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 717 const SkPaint& paint) { | 786 const SkPaint& paint) { |
| 718 // todo | 787 // todo |
| 719 SkDebugf("unsupported operation: drawVertices()\n"); | 788 SkDebugf("unsupported operation: drawVertices()\n"); |
| 720 } | 789 } |
| 721 | 790 |
| 722 void SkSVGDevice::drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, | 791 void SkSVGDevice::drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, |
| 723 const SkPaint&) { | 792 const SkPaint&) { |
| 724 // todo | 793 // todo |
| 725 SkDebugf("unsupported operation: drawDevice()\n"); | 794 SkDebugf("unsupported operation: drawDevice()\n"); |
| 726 } | 795 } |
| OLD | NEW |