Chromium Code Reviews| Index: experimental/svg/SkSVGDevice.cpp |
| diff --git a/experimental/svg/SkSVGDevice.cpp b/experimental/svg/SkSVGDevice.cpp |
| index c0ca612cdec3b877f774bc018d885ec16b40e032..61ecf3c76143fcad8a5990a95cddb3737647850f 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,66 @@ 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); |
| + |
|
mtklein
2015/02/03 20:51:08
Worth asserting byteLen alignment for each of thes
f(malita)
2015/02/03 22:51:25
We can probably be even more opinionated and asser
|
| + switch(paint.getTextEncoding()) { |
| + case SkPaint::kGlyphID_TextEncoding: { |
| + 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); |
| + } |
| + } 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); |
| + } |
| + } break; |
| + case SkPaint::kUTF32_TextEncoding: { |
| + 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 +158,10 @@ public: |
| fWriter->addScalarAttribute(name, val); |
| } |
| + void addText(const SkString& text) { |
| + fWriter->addText(text); |
| + } |
| + |
| private: |
| Resources addResources(const SkPaint& paint); |
| void addResourceDefs(const SkPaint& paint, Resources* resources); |
| @@ -333,16 +399,58 @@ void SkSVGDevice::drawBitmapRect(const SkDraw&, const SkBitmap&, const SkRect* s |
| SkDebugf("unsupported operation: drawBitmapRect()"); |
| } |
| -void SkSVGDevice::drawText(const SkDraw&, const void* text, size_t len, |
| +void SkSVGDevice::AddFontAttributes(const SkPaint& paint, AutoElement* elem) { |
|
mtklein
2015/02/03 20:51:08
void AutoElement::addFontAttributes(const SkPaint&
f(malita)
2015/02/03 22:51:25
Done.
|
| + elem->addAttribute("font-size", paint.getTextSize()); |
| + |
| + SkTypeface::Style style = paint.getTypeface()->style(); |
| + if (style & SkTypeface::kItalic) { |
| + elem->addAttribute("font-style", "italic"); |
| + } |
| + if (style & SkTypeface::kBold) { |
| + elem->addAttribute("font-weight", "bold"); |
| + } |
| + |
| + SkAutoTUnref<const SkTypeface> tface(paint.getTypeface() ? |
| + SkRef(paint.getTypeface()) : SkTypeface::RefDefault(style)); |
| + SkString familyName; |
| + tface->getFamilyName(&familyName); |
| + if (!familyName.isEmpty()) { |
| + elem->addAttribute("font-family", familyName); |
| + } |
| +} |
| + |
| +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); |
| + AddFontAttributes(paint, &elem); |
| + 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); |
| + AddFontAttributes(paint, &elem); |
| + |
| + SkString xStr; |
| + SkString yStr; |
| + for (int i = 0; i < paint.countText(text, len); ++i) { |
| + SkScalar x = offset.x() + pos[i * scalarsPerPos]; |
|
mtklein
2015/02/03 20:51:08
Are offset.x() and offset.y() "dx" and "dy"? If s
f(malita)
2015/02/03 22:51:25
The syntactic rules are quirky though and this wou
|
| + SkScalar y = offset.y() + (scalarsPerPos > 1 ? pos[i * scalarsPerPos + 1] : 0); |
|
mtklein
2015/02/03 20:51:08
When scalarsPerPos == 1, can we just use a single
f(malita)
2015/02/03 22:51:25
Yeah, I think that will work. Done.
|
| + |
| + if (i > 0) { |
| + xStr.append(", "); |
| + yStr.append(", "); |
| + } |
| + xStr.appendScalar(x); |
| + yStr.appendScalar(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, |