Index: src/pdf/SkPDFDevice.cpp |
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp |
index 8e417b1f529dbf9e4b41909175a9cf7107aeb940..8e76c442befaabe89e492455c631285d141fdeab 100644 |
--- a/src/pdf/SkPDFDevice.cpp |
+++ b/src/pdf/SkPDFDevice.cpp |
@@ -1079,6 +1079,72 @@ static void write_wide_string(SkDynamicMemoryWStream* wStream, |
} |
} |
+namespace { |
+class GlyphPositioner { |
+public: |
+ GlyphPositioner(SkDynamicMemoryWStream* content, |
+ SkScalar textSkewX, |
+ bool wideChars) |
+ : fContent(content) |
+ , fCurrentMatrixX(0.0f) |
+ , fCurrentMatrixY(0.0f) |
+ , fXAdvance(0.0f) |
+ , fWideChars(wideChars) |
+ , fInText(false) { |
+ set_text_transform(0.0f, 0.0f, textSkewX, fContent); |
+ } |
+ ~GlyphPositioner() { SkASSERT(!fInText); /* flush first */ } |
+ void flush() { |
+ if (fInText) { |
+ fContent->writeText("> Tj\n"); |
+ fInText = false; |
+ } |
+ } |
+ void setWideChars(bool wideChars) { |
+ if (fWideChars != wideChars) { |
+ SkASSERT(!fInText); |
+ fWideChars = wideChars; |
+ } |
+ } |
+ void writeGlyph(SkScalar x, |
+ SkScalar y, |
+ SkScalar advanceWidth, |
+ uint16_t glyph) { |
+ SkScalar xPosition = x - fCurrentMatrixX; |
+ SkScalar yPosition = y - fCurrentMatrixY; |
+ if (xPosition != fXAdvance || yPosition != 0) { |
+ this->flush(); |
+ SkPDFUtils::AppendScalar(xPosition, fContent); |
+ fContent->writeText(" "); |
+ SkPDFUtils::AppendScalar(-yPosition, fContent); |
+ fContent->writeText(" Td "); |
+ fCurrentMatrixX = x; |
+ fCurrentMatrixY = y; |
+ fXAdvance = 0; |
+ } |
+ if (!fInText) { |
+ fContent->writeText("<"); |
+ fInText = true; |
+ } |
+ if (fWideChars) { |
+ SkPDFUtils::WriteUInt16BE(fContent, glyph); |
+ } else { |
+ SkASSERT(0 == glyph >> 8); |
+ SkPDFUtils::WriteUInt8(fContent, static_cast<uint8_t>(glyph)); |
+ } |
+ fXAdvance += advanceWidth; |
+ } |
+ |
+private: |
+ SkDynamicMemoryWStream* fContent; |
+ SkScalar fCurrentMatrixX; |
+ SkScalar fCurrentMatrixY; |
+ SkScalar fXAdvance; |
+ bool fWideChars; |
+ bool fInText; |
+}; |
+} // namespace |
+ |
static void draw_transparent_text(SkPDFDevice* device, |
const SkDraw& d, |
const void* text, size_t len, |
@@ -1230,6 +1296,9 @@ void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, |
SkPaint::GlyphCacheProc glyphCacheProc = textPaint.getGlyphCacheProc(true); |
content.entry()->fContent.writeText("BT\n"); |
this->updateFont(textPaint, glyphIDs[0], content.entry()); |
+ GlyphPositioner glyphPositioner(&content.entry()->fContent, |
+ textPaint.getTextSkewX(), |
+ content.entry()->fState.fFont->multiByteGlyphs()); |
SkPDFGlyphSetMap* fontGlyphUsage = fDocument->getGlyphUsage(); |
for (size_t i = 0; i < numGlyphs; i++) { |
SkPDFFont* font = content.entry()->fState.fFont; |
@@ -1237,8 +1306,10 @@ void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, |
if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { |
// The current pdf font cannot encode the current glyph. |
// Try to get a pdf font which can encode the current glyph. |
+ glyphPositioner.flush(); |
this->updateFont(textPaint, glyphIDs[i], content.entry()); |
font = content.entry()->fState.fFont; |
+ glyphPositioner.setWideChars(font->multiByteGlyphs()); |
if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { |
SkDEBUGFAIL("PDF could not encode glyph."); |
continue; |
@@ -1248,13 +1319,12 @@ void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, |
fontGlyphUsage->noteGlyphUsage(font, &encodedValue, 1); |
SkScalar x = offset.x() + pos[i * scalarsPerPos]; |
SkScalar y = offset.y() + (2 == scalarsPerPos ? pos[i * scalarsPerPos + 1] : 0); |
- |
align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y); |
- set_text_transform(x, y, textPaint.getTextSkewX(), &content.entry()->fContent); |
- write_wide_string(&content.entry()->fContent, &encodedValue, 1, |
- font->multiByteGlyphs()); |
- content.entry()->fContent.writeText(" Tj\n"); |
+ |
+ SkScalar advanceWidth = textPaint.measureText(&encodedValue, sizeof(uint16_t)); |
+ glyphPositioner.writeGlyph(x, y, advanceWidth, encodedValue); |
} |
+ glyphPositioner.flush(); // Must flush before ending text object. |
content.entry()->fContent.writeText("ET\n"); |
} |