diff options
author | fmalita <fmalita@chromium.org> | 2015-02-27 07:44:47 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-27 07:44:47 -0800 |
commit | 827da23c71310408b2854516af5e2a8910bf700e (patch) | |
tree | 5628221074451d1e361e535a5d166a0ed5864c9d /src/svg | |
parent | e70de9e4f0b7bf73f7cd1a20dbabcb233ffbb7f1 (diff) |
[SkSVGDevice] drawBitmap* support
Also fix a clip transform issue: clips are tracked in device space,
but if applied directly to leaf elements they are also subject to local
transforms ("transform='...'"). Instead, apply via <g> wrapper elements.
R=reed@google.com,mtklein@google.com
Review URL: https://codereview.chromium.org/959883003
Diffstat (limited to 'src/svg')
-rw-r--r-- | src/svg/SkSVGDevice.cpp | 105 | ||||
-rw-r--r-- | src/svg/SkSVGDevice.h | 2 |
2 files changed, 89 insertions, 18 deletions
diff --git a/src/svg/SkSVGDevice.cpp b/src/svg/SkSVGDevice.cpp index a56a631446..45e616b3f6 100644 --- a/src/svg/SkSVGDevice.cpp +++ b/src/svg/SkSVGDevice.cpp @@ -7,12 +7,14 @@ #include "SkSVGDevice.h" +#include "SkBase64.h" #include "SkBitmap.h" #include "SkChecksum.h" +#include "SkData.h" #include "SkDraw.h" +#include "SkImageEncoder.h" #include "SkPaint.h" #include "SkParsePath.h" -#include "SkPathOps.h" #include "SkShader.h" #include "SkStream.h" #include "SkTHash.h" @@ -251,7 +253,7 @@ private: // and deduplicate resources. class SkSVGDevice::ResourceBucket : ::SkNoncopyable { public: - ResourceBucket() : fGradientCount(0), fClipCount(0), fPathCount(0) {} + ResourceBucket() : fGradientCount(0), fClipCount(0), fPathCount(0), fImageCount(0) {} SkString addLinearGradient() { return SkStringPrintf("gradient_%d", fGradientCount++); @@ -265,10 +267,15 @@ public: return SkStringPrintf("path_%d", fPathCount++); } + SkString addImage() { + return SkStringPrintf("img_%d", fImageCount++); + } + private: uint32_t fGradientCount; uint32_t fClipCount; uint32_t fPathCount; + uint32_t fImageCount; }; class SkSVGDevice::AutoElement : ::SkNoncopyable { @@ -285,6 +292,12 @@ public: , fResourceBucket(bucket) { Resources res = this->addResources(draw, paint); + if (!res.fClip.isEmpty()) { + // The clip is in device space. Apply it via a <g> wrapper to avoid local transform + // interference. + fClipGroup.reset(SkNEW_ARGS(AutoElement, ("g", fWriter))); + fClipGroup->addAttribute("clip-path",res.fClip); + } fWriter->startElement(name); @@ -332,8 +345,9 @@ private: SkString addLinearGradientDef(const SkShader::GradientInfo& info, const SkShader* shader); - SkXMLWriter* fWriter; - ResourceBucket* fResourceBucket; + SkXMLWriter* fWriter; + ResourceBucket* fResourceBucket; + SkAutoTDelete<AutoElement> fClipGroup; }; void SkSVGDevice::AutoElement::addPaint(const SkPaint& paint, const Resources& resources) { @@ -379,10 +393,6 @@ void SkSVGDevice::AutoElement::addPaint(const SkPaint& paint, const Resources& r SkASSERT(style == SkPaint::kFill_Style); this->addAttribute("stroke", "none"); } - - if (!resources.fClip.isEmpty()) { - this->addAttribute("clip-path", resources.fClip); - } } Resources SkSVGDevice::AutoElement::addResources(const SkDraw& draw, const SkPaint& paint) { @@ -629,23 +639,82 @@ void SkSVGDevice::drawPath(const SkDraw& draw, const SkPath& path, const SkPaint elem.addPathAttributes(path); } -void SkSVGDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, +void SkSVGDevice::drawBitmapCommon(const SkDraw& draw, const SkBitmap& bm, + const SkPaint& paint) { + SkAutoTUnref<const SkData> pngData( + SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality)); + if (!pngData) { + return; + } + + size_t b64Size = SkBase64::Encode(pngData->data(), pngData->size(), NULL); + SkAutoTMalloc<char> b64Data(b64Size); + SkBase64::Encode(pngData->data(), pngData->size(), b64Data.get()); + + SkString svgImageData("data:image/png;base64,"); + svgImageData.append(b64Data.get(), b64Size); + + SkString imageID = fResourceBucket->addImage(); + { + AutoElement defs("defs", fWriter); + { + AutoElement image("image", fWriter); + image.addAttribute("id", imageID); + image.addAttribute("width", bm.width()); + image.addAttribute("height", bm.height()); + image.addAttribute("xlink:href", svgImageData); + } + } + + { + AutoElement imageUse("use", fWriter, fResourceBucket, draw, paint); + imageUse.addAttribute("xlink:href", SkStringPrintf("#%s", imageID.c_str())); + } +} + +void SkSVGDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, const SkMatrix& matrix, const SkPaint& paint) { - // todo - SkDebugf("unsupported operation: drawBitmap()\n"); + SkMatrix adjustedMatrix = *draw.fMatrix; + adjustedMatrix.preConcat(matrix); + SkDraw adjustedDraw(draw); + adjustedDraw.fMatrix = &adjustedMatrix; + + drawBitmapCommon(adjustedDraw, bitmap, paint); } -void SkSVGDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, +void SkSVGDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, int x, int y, const SkPaint& paint) { - // todo - SkDebugf("unsupported operation: drawSprite()\n"); + SkMatrix adjustedMatrix = *draw.fMatrix; + adjustedMatrix.preTranslate(SkIntToScalar(x), SkIntToScalar(y)); + SkDraw adjustedDraw(draw); + adjustedDraw.fMatrix = &adjustedMatrix; + + drawBitmapCommon(adjustedDraw, bitmap, paint); } -void SkSVGDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, const SkRect* srcOrNull, +void SkSVGDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bm, const SkRect* srcOrNull, const SkRect& dst, const SkPaint& paint, - SkCanvas::DrawBitmapRectFlags flags) { - // todo - SkDebugf("unsupported operation: drawBitmapRect()\n"); + SkCanvas::DrawBitmapRectFlags) { + SkMatrix adjustedMatrix; + adjustedMatrix.setRectToRect(srcOrNull ? *srcOrNull : SkRect::Make(bm.bounds()), + dst, + SkMatrix::kFill_ScaleToFit); + adjustedMatrix.postConcat(*draw.fMatrix); + + SkDraw adjustedDraw(draw); + adjustedDraw.fMatrix = &adjustedMatrix; + + SkClipStack adjustedClipStack; + if (srcOrNull && *srcOrNull != SkRect::Make(bm.bounds())) { + SkRect devClipRect; + draw.fMatrix->mapRect(&devClipRect, dst); + + adjustedClipStack = *draw.fClipStack; + adjustedClipStack.clipDevRect(devClipRect, SkRegion::kIntersect_Op, paint.isAntiAlias()); + adjustedDraw.fClipStack = &adjustedClipStack; + } + + drawBitmapCommon(adjustedDraw, bm, paint); } void SkSVGDevice::drawText(const SkDraw& draw, const void* text, size_t len, diff --git a/src/svg/SkSVGDevice.h b/src/svg/SkSVGDevice.h index fdfc8c3e03..914642392f 100644 --- a/src/svg/SkSVGDevice.h +++ b/src/svg/SkSVGDevice.h @@ -61,6 +61,8 @@ private: SkSVGDevice(const SkISize& size, SkXMLWriter* writer); virtual ~SkSVGDevice(); + void drawBitmapCommon(const SkDraw& draw, const SkBitmap& bm, const SkPaint& paint); + class AutoElement; class ResourceBucket; |