aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar fmalita <fmalita@chromium.org>2015-02-03 17:47:12 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-02-03 17:47:12 -0800
commitfe3f260ff9b6b3f4c7c33f2b20502b281baab689 (patch)
treec54b1b2b415cbadf750f2c08bd6a3321001849df
parentd5163e2c444f4a7d2111930ec55303a4073cb1dc (diff)
[SkSVGDevice] Initial text support
R=reed@google.com,mtklein@google.com Review URL: https://codereview.chromium.org/899683002
-rw-r--r--experimental/svg/SkSVGDevice.cpp147
-rw-r--r--include/xml/SkXMLWriter.h11
-rw-r--r--src/animator/SkXMLAnimatorWriter.cpp5
-rw-r--r--src/animator/SkXMLAnimatorWriter.h2
-rw-r--r--src/xml/SkXMLWriter.cpp44
5 files changed, 186 insertions, 23 deletions
diff --git a/experimental/svg/SkSVGDevice.cpp b/experimental/svg/SkSVGDevice.cpp
index c0ca612cde..bd503b7d8f 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("&amp;");
+ break;
+ case '"':
+ text->append("&quot;");
+ break;
+ case '\'':
+ text->append("&apos;");
+ break;
+ case '<':
+ text->append("&lt;");
+ break;
+ case '>':
+ text->append("&gt;");
+ 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.c_str());
+ }
+
+ 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,62 @@ 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) {
+ SkASSERT(scalarsPerPos == 1 || scalarsPerPos == 2);
+
+ 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]);
+ }
+ }
+
+ 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 +474,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");
}
diff --git a/include/xml/SkXMLWriter.h b/include/xml/SkXMLWriter.h
index 214fefe862..b33ccd75d7 100644
--- a/include/xml/SkXMLWriter.h
+++ b/include/xml/SkXMLWriter.h
@@ -27,6 +27,7 @@ public:
void addAttributeLen(const char name[], const char value[], size_t length);
void addHexAttribute(const char name[], uint32_t value, int minDigits = 0);
void addScalarAttribute(const char name[], SkScalar value);
+ void addText(const char text[]);
void endElement() { this->onEndElement(); }
void startElement(const char elem[]);
void startElementLen(const char elem[], size_t length);
@@ -37,11 +38,18 @@ public:
protected:
virtual void onStartElementLen(const char elem[], size_t length) = 0;
virtual void onAddAttributeLen(const char name[], const char value[], size_t length) = 0;
+ virtual void onAddText(const char text[]) = 0;
virtual void onEndElement() = 0;
struct Elem {
+ Elem(const char name[], size_t len)
+ : fName(name, len)
+ , fHasChildren(false)
+ , fHasText(false) {}
+
SkString fName;
bool fHasChildren;
+ bool fHasText;
};
void doEnd(Elem* elem);
bool doStart(const char name[], size_t length);
@@ -65,6 +73,8 @@ protected:
virtual void onStartElementLen(const char elem[], size_t length);
virtual void onEndElement();
virtual void onAddAttributeLen(const char name[], const char value[], size_t length);
+ virtual void onAddText(const char text[]) SK_OVERRIDE;
+
private:
SkWStream& fStream;
};
@@ -77,6 +87,7 @@ protected:
virtual void onStartElementLen(const char elem[], size_t length);
virtual void onEndElement();
virtual void onAddAttributeLen(const char name[], const char value[], size_t length);
+ virtual void onAddText(const char text[]) SK_OVERRIDE;
private:
SkXMLParser& fParser;
};
diff --git a/src/animator/SkXMLAnimatorWriter.cpp b/src/animator/SkXMLAnimatorWriter.cpp
index 58f20f136b..9b552c09de 100644
--- a/src/animator/SkXMLAnimatorWriter.cpp
+++ b/src/animator/SkXMLAnimatorWriter.cpp
@@ -26,6 +26,11 @@ void SkXMLAnimatorWriter::onAddAttributeLen(const char name[], const char value[
fParser->onAddAttributeLen(name, value, length);
}
+void SkXMLAnimatorWriter::onAddText(const char text[])
+{
+ SkDebugf("not implemented: SkXMLAnimatorWriter::onAddText()\n");
+}
+
void SkXMLAnimatorWriter::onEndElement()
{
Elem* elem = getEnd();
diff --git a/src/animator/SkXMLAnimatorWriter.h b/src/animator/SkXMLAnimatorWriter.h
index 1b17f6ffd6..9cb596628d 100644
--- a/src/animator/SkXMLAnimatorWriter.h
+++ b/src/animator/SkXMLAnimatorWriter.h
@@ -25,6 +25,8 @@ protected:
virtual void onAddAttributeLen(const char name[], const char value[], size_t length);
virtual void onEndElement();
virtual void onStartElementLen(const char elem[], size_t length);
+ virtual void onAddText(const char text[]) SK_OVERRIDE;
+
private:
SkAnimator* fAnimator;
SkDisplayXMLParser* fParser;
diff --git a/src/xml/SkXMLWriter.cpp b/src/xml/SkXMLWriter.cpp
index ec351b728b..56e0889388 100644
--- a/src/xml/SkXMLWriter.cpp
+++ b/src/xml/SkXMLWriter.cpp
@@ -51,6 +51,17 @@ void SkXMLWriter::addScalarAttribute(const char name[], SkScalar value)
this->addAttribute(name, tmp.c_str());
}
+void SkXMLWriter::addText(const char text[])
+{
+ if (fElems.isEmpty()) {
+ return;
+ }
+
+ this->onAddText(text);
+
+ fElems.top()->fHasText = true;
+}
+
void SkXMLWriter::doEnd(Elem* elem)
{
delete elem;
@@ -63,9 +74,7 @@ bool SkXMLWriter::doStart(const char name[], size_t length)
if (firstChild)
fElems[level-1]->fHasChildren = true;
Elem** elem = fElems.push();
- *elem = new Elem;
- (*elem)->fName.set(name, length);
- (*elem)->fHasChildren = 0;
+ *elem = new Elem(name, length);
return firstChild;
}
@@ -212,7 +221,7 @@ SkXMLStreamWriter::~SkXMLStreamWriter()
void SkXMLStreamWriter::onAddAttributeLen(const char name[], const char value[], size_t length)
{
- SkASSERT(!fElems.top()->fHasChildren);
+ SkASSERT(!fElems.top()->fHasChildren && !fElems.top()->fHasText);
fStream.writeText(" ");
fStream.writeText(name);
fStream.writeText("=\"");
@@ -220,18 +229,32 @@ void SkXMLStreamWriter::onAddAttributeLen(const char name[], const char value[],
fStream.writeText("\"");
}
+void SkXMLStreamWriter::onAddText(const char text[])
+{
+ Elem* elem = fElems.top();
+
+ if (!elem->fHasChildren && !elem->fHasText) {
+ fStream.writeText(">");
+ fStream.newline();
+ }
+
+ tab(fStream, fElems.count() + 1);
+ fStream.writeText(text);
+ fStream.newline();
+}
+
void SkXMLStreamWriter::onEndElement()
{
Elem* elem = getEnd();
- if (elem->fHasChildren)
+ if (elem->fHasChildren || elem->fHasText)
{
tab(fStream, fElems.count());
fStream.writeText("</");
fStream.writeText(elem->fName.c_str());
fStream.writeText(">");
- }
- else
+ } else {
fStream.writeText("/>");
+ }
fStream.newline();
doEnd(elem);
}
@@ -274,11 +297,16 @@ SkXMLParserWriter::~SkXMLParserWriter()
void SkXMLParserWriter::onAddAttributeLen(const char name[], const char value[], size_t length)
{
- SkASSERT(fElems.count() == 0 || !fElems.top()->fHasChildren);
+ SkASSERT(fElems.count() == 0 || (!fElems.top()->fHasChildren && !fElems.top()->fHasText));
SkString str(value, length);
fParser.addAttribute(name, str.c_str());
}
+void SkXMLParserWriter::onAddText(const char text[])
+{
+ fParser.text(text, SkToInt(strlen(text)));
+}
+
void SkXMLParserWriter::onEndElement()
{
Elem* elem = this->getEnd();