Chromium Code Reviews| Index: experimental/svg/SkSVGDevice.cpp |
| diff --git a/experimental/svg/SkSVGDevice.cpp b/experimental/svg/SkSVGDevice.cpp |
| index c0ca612cdec3b877f774bc018d885ec16b40e032..7d3122fec6ab12f718a42eb32ae4e1caf43c8952 100644 |
| --- a/experimental/svg/SkSVGDevice.cpp |
| +++ b/experimental/svg/SkSVGDevice.cpp |
| @@ -13,6 +13,8 @@ |
| #include "SkParsePath.h" |
| #include "SkShader.h" |
| #include "SkStream.h" |
| +#include "SkTypeface.h" |
| +#include "SkUtils.h" |
| #include "SkXMLWriter.h" |
| namespace { |
| @@ -30,6 +32,71 @@ static SkScalar svg_opacity(SkColor color) { |
| return SkIntToScalar(SkColorGetA(color)) / SK_AlphaOPAQUE; |
| } |
| +static void append_escaped_unichar(SkUnichar c, SkString* text) { |
| + switch(c) { |
| + case '&': |
| + text->append("&"); |
| + break; |
| + case '"': |
| + text->append("""); |
| + break; |
| + case '\'': |
| + text->append("'"); |
| + break; |
| + case '<': |
| + text->append("<"); |
| + break; |
| + case '>': |
| + text->append(">"); |
| + break; |
| + default: |
| + text->appendUnichar(c); |
| + break; |
| + } |
| +} |
| + |
| +static SkString svg_text(const void* text, size_t byteLen, const SkPaint& paint) { |
| + SkString svgText; |
| + int count = paint.countText(text, byteLen); |
| + |
| + switch(paint.getTextEncoding()) { |
| + case SkPaint::kGlyphID_TextEncoding: { |
| + SkASSERT(count * sizeof(uint16_t) == byteLen); |
| + SkAutoSTArray<64, SkUnichar> unichars(count); |
| + paint.glyphsToUnichars((const uint16_t*)text, count, unichars.get()); |
| + for (int i = 0; i < count; ++i) { |
| + append_escaped_unichar(unichars[i], &svgText); |
| + } |
| + } break; |
| + case SkPaint::kUTF8_TextEncoding: { |
| + const char* c8 = reinterpret_cast<const char*>(text); |
| + for (int i = 0; i < count; ++i) { |
| + append_escaped_unichar(SkUTF8_NextUnichar(&c8), &svgText); |
| + } |
| + SkASSERT(reinterpret_cast<const char*>(text) + byteLen == c8); |
| + } break; |
| + case SkPaint::kUTF16_TextEncoding: { |
| + const uint16_t* c16 = reinterpret_cast<const uint16_t*>(text); |
| + for (int i = 0; i < count; ++i) { |
| + append_escaped_unichar(SkUTF16_NextUnichar(&c16), &svgText); |
| + } |
| + SkASSERT(SkIsAlign2(byteLen)); |
| + SkASSERT(reinterpret_cast<const uint16_t*>(text) + (byteLen / 2) == c16); |
| + } break; |
| + case SkPaint::kUTF32_TextEncoding: { |
| + SkASSERT(count * sizeof(uint32_t) == byteLen); |
| + const uint32_t* c32 = reinterpret_cast<const uint32_t*>(text); |
| + for (int i = 0; i < count; ++i) { |
| + append_escaped_unichar(c32[i], &svgText); |
| + } |
| + } break; |
| + default: |
| + SkFAIL("unknown text encoding"); |
| + } |
| + |
| + return svgText; |
| +} |
| + |
| struct Resources { |
| Resources(const SkPaint& paint) |
| : fPaintServer(svg_color(paint.getColor())) {} |
| @@ -96,6 +163,12 @@ public: |
| fWriter->addScalarAttribute(name, val); |
| } |
| + void addText(const SkString& text) { |
| + fWriter->addText(text); |
| + } |
| + |
| + void addFontAttributes(const SkPaint&); |
| + |
| private: |
| Resources addResources(const SkPaint& paint); |
| void addResourceDefs(const SkPaint& paint, Resources* resources); |
| @@ -234,6 +307,26 @@ SkString SkSVGDevice::AutoElement::addLinearGradientDef(const SkShader::Gradient |
| return id; |
| } |
| +void SkSVGDevice::AutoElement::addFontAttributes(const SkPaint& paint) { |
| + this->addAttribute("font-size", paint.getTextSize()); |
| + |
| + SkTypeface::Style style = paint.getTypeface()->style(); |
| + if (style & SkTypeface::kItalic) { |
| + this->addAttribute("font-style", "italic"); |
| + } |
| + if (style & SkTypeface::kBold) { |
| + this->addAttribute("font-weight", "bold"); |
| + } |
| + |
| + SkAutoTUnref<const SkTypeface> tface(paint.getTypeface() ? |
| + SkRef(paint.getTypeface()) : SkTypeface::RefDefault(style)); |
| + SkString familyName; |
| + tface->getFamilyName(&familyName); |
| + if (!familyName.isEmpty()) { |
| + this->addAttribute("font-family", familyName); |
| + } |
| +} |
| + |
| SkBaseDevice* SkSVGDevice::Create(const SkISize& size, SkWStream* wstream) { |
| if (!SkToBool(wstream)) { |
| return NULL; |
| @@ -281,7 +374,7 @@ void SkSVGDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { |
| void SkSVGDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count, |
| const SkPoint[], const SkPaint& paint) { |
| // todo |
| - SkDebugf("unsupported operation: drawPoints()"); |
| + SkDebugf("unsupported operation: drawPoints()\n"); |
| } |
| void SkSVGDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) { |
| @@ -302,7 +395,7 @@ void SkSVGDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint |
| void SkSVGDevice::drawRRect(const SkDraw&, const SkRRect& rr, const SkPaint& paint) { |
| // todo |
| - SkDebugf("unsupported operation: drawRRect()"); |
| + SkDebugf("unsupported operation: drawRRect()\n"); |
| } |
| void SkSVGDevice::drawPath(const SkDraw& draw, const SkPath& path, const SkPaint& paint, |
| @@ -317,38 +410,60 @@ void SkSVGDevice::drawPath(const SkDraw& draw, const SkPath& path, const SkPaint |
| void SkSVGDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, |
| const SkMatrix& matrix, const SkPaint& paint) { |
| // todo |
| - SkDebugf("unsupported operation: drawBitmap()"); |
| + SkDebugf("unsupported operation: drawBitmap()\n"); |
| } |
| void SkSVGDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap, |
| int x, int y, const SkPaint& paint) { |
| // todo |
| - SkDebugf("unsupported operation: drawSprite()"); |
| + SkDebugf("unsupported operation: drawSprite()\n"); |
| } |
| void SkSVGDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, const SkRect* srcOrNull, |
| const SkRect& dst, const SkPaint& paint, |
| SkCanvas::DrawBitmapRectFlags flags) { |
| // todo |
| - SkDebugf("unsupported operation: drawBitmapRect()"); |
| + SkDebugf("unsupported operation: drawBitmapRect()\n"); |
| } |
| -void SkSVGDevice::drawText(const SkDraw&, const void* text, size_t len, |
| +void SkSVGDevice::drawText(const SkDraw& draw, const void* text, size_t len, |
| SkScalar x, SkScalar y, const SkPaint& paint) { |
| - // todo |
| - SkDebugf("unsupported operation: drawText()"); |
| + AutoElement elem("text", fWriter, fResourceBucket, draw, paint); |
| + elem.addFontAttributes(paint); |
| + elem.addAttribute("x", x); |
| + elem.addAttribute("y", y); |
| + elem.addText(svg_text(text, len, paint)); |
| } |
| -void SkSVGDevice::drawPosText(const SkDraw&, const void* text, size_t len,const SkScalar pos[], |
| - int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) { |
| - // todo |
| - SkDebugf("unsupported operation: drawPosText()"); |
| +void SkSVGDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, |
| + const SkScalar pos[], int scalarsPerPos, const SkPoint& offset, |
| + const SkPaint& paint) { |
| + AutoElement elem("text", fWriter, fResourceBucket, draw, paint); |
| + elem.addFontAttributes(paint); |
| + |
| + SkString xStr; |
| + SkString yStr; |
| + for (int i = 0; i < paint.countText(text, len); ++i) { |
| + xStr.appendf("%.8g, ", offset.x() + pos[i * scalarsPerPos]); |
| + |
| + if (scalarsPerPos == 2) { |
| + yStr.appendf("%.8g, ", offset.y() + pos[i * scalarsPerPos + 1]); |
| + } |
| + } |
| + |
|
mtklein
2015/02/03 23:56:08
SkASSERT(scalarsPerPos == 1 || scalarsPerPos == 2)
f(malita)
2015/02/04 00:46:13
Done.
|
| + if (scalarsPerPos != 2) { |
| + yStr.appendScalar(offset.y()); |
| + } |
| + |
| + elem.addAttribute("x", xStr); |
| + elem.addAttribute("y", yStr); |
| + elem.addText(svg_text(text, len, paint)); |
| } |
| void SkSVGDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len, const SkPath& path, |
| const SkMatrix* matrix, const SkPaint& paint) { |
| // todo |
| - SkDebugf("unsupported operation: drawTextOnPath()"); |
| + SkDebugf("unsupported operation: drawTextOnPath()\n"); |
| } |
| void SkSVGDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount, |
| @@ -357,11 +472,11 @@ void SkSVGDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCo |
| const uint16_t indices[], int indexCount, |
| const SkPaint& paint) { |
| // todo |
| - SkDebugf("unsupported operation: drawVertices()"); |
| + SkDebugf("unsupported operation: drawVertices()\n"); |
| } |
| void SkSVGDevice::drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, |
| const SkPaint&) { |
| // todo |
| - SkDebugf("unsupported operation: drawDevice()"); |
| + SkDebugf("unsupported operation: drawDevice()\n"); |
| } |