diff options
author | fmalita <fmalita@chromium.org> | 2015-02-03 17:47:12 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-03 17:47:12 -0800 |
commit | fe3f260ff9b6b3f4c7c33f2b20502b281baab689 (patch) | |
tree | c54b1b2b415cbadf750f2c08bd6a3321001849df | |
parent | d5163e2c444f4a7d2111930ec55303a4073cb1dc (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.cpp | 147 | ||||
-rw-r--r-- | include/xml/SkXMLWriter.h | 11 | ||||
-rw-r--r-- | src/animator/SkXMLAnimatorWriter.cpp | 5 | ||||
-rw-r--r-- | src/animator/SkXMLAnimatorWriter.h | 2 | ||||
-rw-r--r-- | src/xml/SkXMLWriter.cpp | 44 |
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("&"); + 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.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(); |