[SkSVGDevice] Initial text support
R=reed@google.com,mtklein@google.com Review URL: https://codereview.chromium.org/899683002
This commit is contained in:
parent
d5163e2c44
commit
fe3f260ff9
@ -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");
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user