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