Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(157)

Unified Diff: src/pdf/SkPDFDevice.cpp

Issue 2278703002: SkPDF: Glyph validation change (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: major refactor Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/pdf/SkPDFDevice.cpp
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index a36125f38090f26fa574e36a2c2ac0bb31808cb9..455a73de188c75659b745babb9354c5428b2a0e9 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -32,7 +32,6 @@
#include "SkSurface.h"
#include "SkTextFormatParams.h"
#include "SkTemplates.h"
-#include "SkTypefacePriv.h"
#include "SkXfermodeInterpretation.h"
#define DPI_FOR_RASTER_SCALE_ONE 72
@@ -973,7 +972,7 @@ public:
, fDefaultPositioning(defaultPositioning) {
set_text_transform(origin.x(), origin.y(), textSkewX, fContent);
}
- ~GlyphPositioner() { SkASSERT(!fInText); /* flush first */ }
+ ~GlyphPositioner() {this->flush(); }
bungeman-skia 2016/08/25 19:28:43 nit: probably want a space between '{' and 'this'.
hal.canary 2016/08/26 15:27:03 Done. And removed the extra space before '}'
void flush() {
if (fInText) {
fContent->writeText("> Tj\n");
@@ -987,21 +986,20 @@ public:
fWideChars = wideChars;
}
}
- void writeGlyph(SkScalar x,
- SkScalar y,
+ void writeGlyph(SkPoint xy,
SkScalar advanceWidth,
uint16_t glyph) {
if (!fDefaultPositioning) {
- SkScalar xPosition = x - fCurrentMatrixX;
- SkScalar yPosition = y - fCurrentMatrixY;
+ SkScalar xPosition = xy.x() - fCurrentMatrixX;
+ SkScalar yPosition = xy.y() - fCurrentMatrixY;
bungeman-skia 2016/08/25 19:28:43 This handling seems almost painful to read. Is the
hal.canary 2016/08/26 15:27:03 Excellent point. Done. I also used SkPoint::oper
if (xPosition != fXAdvance || yPosition != 0) {
this->flush();
SkPDFUtils::AppendScalar(xPosition, fContent);
fContent->writeText(" ");
SkPDFUtils::AppendScalar(-yPosition, fContent);
fContent->writeText(" Td ");
- fCurrentMatrixX = x;
- fCurrentMatrixY = y;
+ fCurrentMatrixX = xy.x();
+ fCurrentMatrixY = xy.y();
fXAdvance = 0;
}
fXAdvance += advanceWidth;
@@ -1034,12 +1032,14 @@ static void draw_transparent_text(SkPDFDevice* device,
const void* text, size_t len,
SkScalar x, SkScalar y,
const SkPaint& srcPaint) {
- SkPaint transparent;
- if (!SkPDFFont::CanEmbedTypeface(transparent.getTypeface(),
+ sk_sp<SkTypeface> defaultFace = SkTypeface::MakeDefault();
+ if (!SkPDFFont::CanEmbedTypeface(defaultFace.get(),
device->getCanon())) {
bungeman-skia 2016/08/25 19:28:43 nit: Since you're touching this line anyway, will
hal.canary 2016/08/26 15:27:03 Done.
SkDebugf("SkPDF: default typeface should be embeddable");
return; // Avoid infinite loop in release.
}
+ SkPaint transparent;
+ transparent.setTypeface(std::move(defaultFace));
transparent.setTextSize(srcPaint.getTextSize());
transparent.setColor(SK_ColorTRANSPARENT);
switch (srcPaint.getTextEncoding()) {
@@ -1069,6 +1069,21 @@ static void draw_transparent_text(SkPDFDevice* device,
}
}
+namespace {
+struct TextObject {
+ SkDynamicMemoryWStream* fOut;
+ TextObject(SkDynamicMemoryWStream* out) : fOut(out) { fOut->writeText("BT\n"); }
+ ~TextObject() { fOut->writeText("ET\n"); }
+};
+} // namespace
bungeman-skia 2016/08/25 19:28:43 It seems that this struct is only used by internal
hal.canary 2016/08/26 15:27:03 Done.
+
+static int get_stretch(SkPDFFont* font, const SkGlyphID* glyphs, int index,
+ int glyphCount, SkGlyphID maxGlyphID, bool multiByte) {
+ SkASSERT(font);
+ return multiByte ? glyphCount - index
+ : font->countStretch(&glyphs[index], glyphCount - index, maxGlyphID);
+}
+
void SkPDFDevice::internalDrawText(
const SkDraw& d, const void* sourceText, size_t sourceByteCount,
const SkScalar pos[], SkTextBlob::GlyphPositioning positioning,
@@ -1097,11 +1112,11 @@ void SkPDFDevice::internalDrawText(
SkDebugf("SkPDF: SkTypeface::MakeDefault() returned nullptr.\n");
return;
}
- int typefaceGlyphCount = typeface->countGlyphs();
- if (typefaceGlyphCount < 1) {
- SkDebugf("SkPDF: SkTypeface has no glyphs.\n");
+ SkPDFFont::TypefaceInfo faceInfo = SkPDFFont::GetTypefaceInfo(typeface);
+ if (!faceInfo.fGood) {
return;
}
+ const SkGlyphID maxGlyphID = faceInfo.fMaxGlyphID;
if (!SkPDFFont::CanEmbedTypeface(typeface, fDocument->canon())) {
SkPath path; // https://bug.skia.org/3866
paint.getTextPath(sourceText, sourceByteCount,
@@ -1112,21 +1127,19 @@ void SkPDFDevice::internalDrawText(
offset.x(), offset.y(), paint);
return;
}
- // Always make a copy (1) to validate user-input glyphs and
- // (2) because we may modify the glyphs in place (for
- // single-byte-glyph-id PDF fonts).
int glyphCount = paint.textToGlyphs(sourceText, sourceByteCount, nullptr);
- if (glyphCount <= 0) { return; }
- SkAutoSTMalloc<128, SkGlyphID> glyphStorage(SkToSizeT(glyphCount));
- SkGlyphID* glyphs = glyphStorage.get();
- (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphs);
+ if (glyphCount <= 0) {
+ return;
+ }
+ SkAutoSTMalloc<128, SkGlyphID> glyphStorage;
+ const SkGlyphID* glyphs = nullptr;
if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
- // Validate user-input glyphs.
- SkGlyphID maxGlyphID = SkToU16(typefaceGlyphCount - 1);
- for (int i = 0; i < glyphCount; ++i) {
- glyphs[i] = SkTMin(maxGlyphID, glyphs[i]);
- }
+ glyphs = (const SkGlyphID*)sourceText;
+ // validate input later.
} else {
+ glyphStorage.reset(SkToSizeT(glyphCount));
+ (void)paint.textToGlyphs(sourceText, sourceByteCount, glyphStorage.get());
+ glyphs = glyphStorage.get();
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
}
@@ -1135,89 +1148,90 @@ void SkPDFDevice::internalDrawText(
SkAutoGlyphCache glyphCache(paint, nullptr, nullptr);
SkPaint::Align alignment = paint.getTextAlign();
+ float alignmentFactor = SkPaint::kLeft_Align == alignment ? 0.0f :
+ SkPaint::kCenter_Align == alignment ? -0.5f :
+ /* SkPaint::kRight_Align */ -1.0f;
if (defaultPositioning && alignment != SkPaint::kLeft_Align) {
- SkScalar advance{0};
+ SkScalar advance = 0;
for (int i = 0; i < glyphCount; ++i) {
advance += glyphCache->getGlyphIDAdvance(glyphs[i]).fAdvanceX;
}
- SkScalar m = alignment == SkPaint::kCenter_Align
- ? 0.5f * advance : advance;
- offset -= SkPoint{m, 0};
+ offset.offset(alignmentFactor * advance, 0);
}
ScopedContentEntry content(this, d, paint, true);
if (!content.entry()) {
return;
}
SkDynamicMemoryWStream* out = &content.entry()->fContent;
- out->writeText("BT\n");
- if (!this->updateFont(paint, glyphs[0], content.entry())) {
- SkDebugf("SkPDF: Font error.");
- out->writeText("ET\n%SkPDF: Font error.\n");
- return;
+ SkScalar textSize = paint.getTextSize();
+ TextObject textObject(out); // Must be in scope for this->updateFont().
bungeman-skia 2016/08/25 19:28:43 I'm not sure this name clearly conveys the side ef
hal.canary 2016/08/26 15:27:03 Done.
+ int index = 0;
+ while (glyphs[index] > maxGlyphID) { // Invalid glyphID for this font.
+ ++index; // Skip this glyphID
+ if (index == glyphCount) {
+ return; // all glyphIDs were bad.
+ }
}
- SkPDFFont* font = content.entry()->fState.fFont;
+ SkPDFFont* font = this->updateFont(
+ typeface, textSize, glyphs[index], content.entry());
+ SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met.
+ if (!font) { return; }
+
GlyphPositioner glyphPositioner(out,
paint.getTextSkewX(),
font->multiByteGlyphs(),
defaultPositioning,
offset);
- const SkGlyphID* const glyphsEnd = glyphs + glyphCount;
-
- while (glyphs < glyphsEnd) {
- font = content.entry()->fState.fFont;
- int stretch = font->multiByteGlyphs()
- ? SkToInt(glyphsEnd - glyphs)
- : font->glyphsToPDFFontEncodingCount(glyphs, SkToInt(glyphsEnd - glyphs));
- SkASSERT(glyphs + stretch <= glyphsEnd);
+
+ while (index < glyphCount) {
+ bool multiByte = font->multiByteGlyphs();
+ int stretch = get_stretch(font, glyphs, index, glyphCount, maxGlyphID, multiByte);
+ SkASSERT(index + stretch <= glyphCount);
if (stretch < 1) {
- SkASSERT(!font->multiByteGlyphs());
+ SkASSERT(!multiByte);
// The current pdf font cannot encode the next glyph.
// Try to get a pdf font which can encode the next glyph.
glyphPositioner.flush();
- if (!this->updateFont(paint, *glyphs, content.entry())) {
- SkDebugf("SkPDF: Font error.");
- out->writeText("ET\n%SkPDF: Font error.\n");
- return;
+ // first, validate the next glyph
+ while (glyphs[index] > maxGlyphID) {
+ ++index; // Skip this glyphID
+ if (index == glyphCount) {
+ return; // all remainng glyphIDs were bad.
+ }
}
- font = content.entry()->fState.fFont;
+ SkASSERT(index < glyphCount);
+ font = this->updateFont(typeface, textSize, glyphs[index], content.entry());
+ SkASSERT(font); // preconditions for SkPDFFont::GetFontResource met.
+ if (!font) { return; }
glyphPositioner.setWideChars(font->multiByteGlyphs());
- // try again
- stretch = font->glyphsToPDFFontEncodingCount(glyphs,
- SkToInt(glyphsEnd - glyphs));
+ // Get stretch for this new font.
+ stretch = get_stretch(font, glyphs, index, glyphCount, maxGlyphID, false);
if (stretch < 1) {
SkDEBUGFAIL("PDF could not encode glyph.");
- glyphPositioner.flush();
- out->writeText("ET\n%SkPDF: Font encoding error.\n");
return;
}
}
- font->noteGlyphUsage(glyphs, stretch);
- if (defaultPositioning) {
- (void)font->glyphsToPDFFontEncoding(glyphs, SkToInt(glyphsEnd - glyphs));
- while (stretch-- > 0) {
- glyphPositioner.writeGlyph(0, 0, 0, *glyphs);
- ++glyphs;
- }
- } else {
- while (stretch-- > 0) {
- SkScalar advance = glyphCache->getGlyphIDAdvance(*glyphs).fAdvanceX;
- SkScalar x = *pos++;
- // evaluate x and y in order!
- SkScalar y = SkTextBlob::kFull_Positioning == positioning ? *pos++ : 0;
- SkPoint xy{x, y};
- if (alignment != SkPaint::kLeft_Align) {
- SkScalar m = alignment == SkPaint::kCenter_Align
- ? 0.5f * advance : advance;
- xy -= SkPoint{m, 0};
+ while (stretch-- > 0) {
+ SkGlyphID gid = glyphs[index];
+ if (gid <= maxGlyphID) {
+ font->noteGlyphUsage(gid);
+ SkGlyphID encodedGlyph = font->glyphToPDFFontEncoding(gid);
+ if (defaultPositioning) {
+ glyphPositioner.writeGlyph(SkPoint{0, 0}, 0, encodedGlyph);
+ } else {
+ SkScalar advance = glyphCache->getGlyphIDAdvance(gid).fAdvanceX;
+ SkPoint xy = SkTextBlob::kFull_Positioning == positioning
+ ? SkPoint{pos[2 * index], pos[2 * index + 1]}
+ : SkPoint{pos[index], 0};
+ if (alignment != SkPaint::kLeft_Align) {
+ xy.offset(alignmentFactor * advance, 0);
+ }
+ glyphPositioner.writeGlyph(xy, advance, encodedGlyph);
}
- (void)font->glyphsToPDFFontEncoding(glyphs, 1);
- glyphPositioner.writeGlyph(xy.x(), xy.y(), advance, *glyphs);
- ++glyphs;
}
+ ++index;
}
}
- glyphPositioner.flush();
- out->writeText("ET\n");
}
void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
@@ -1903,26 +1917,28 @@ int SkPDFDevice::addXObjectResource(SkPDFObject* xObject) {
return result;
}
-bool SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID,
- SkPDFDevice::ContentEntry* contentEntry) {
- SkTypeface* typeface = paint.getTypeface();
+SkPDFFont* SkPDFDevice::updateFont(SkTypeface* typeface,
+ SkScalar textSize,
+ uint16_t glyphID,
+ SkPDFDevice::ContentEntry* contentEntry) {
if (contentEntry->fState.fFont == nullptr ||
- contentEntry->fState.fTextSize != paint.getTextSize() ||
+ contentEntry->fState.fTextSize != textSize ||
!contentEntry->fState.fFont->hasGlyph(glyphID)) {
int fontIndex = getFontResourceIndex(typeface, glyphID);
if (fontIndex < 0) {
- return false;
+ SkDebugf("SkPDF: Font error.");
+ return nullptr;
}
contentEntry->fContent.writeText("/");
contentEntry->fContent.writeText(SkPDFResourceDict::getResourceName(
SkPDFResourceDict::kFont_ResourceType,
fontIndex).c_str());
contentEntry->fContent.writeText(" ");
- SkPDFUtils::AppendScalar(paint.getTextSize(), &contentEntry->fContent);
+ SkPDFUtils::AppendScalar(textSize, &contentEntry->fContent);
contentEntry->fContent.writeText(" Tf\n");
contentEntry->fState.fFont = fFontResources[fontIndex];
}
- return true;
+ return contentEntry->fState.fFont;
}
int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
« no previous file with comments | « src/pdf/SkPDFDevice.h ('k') | src/pdf/SkPDFFont.h » ('j') | src/pdf/SkPDFFont.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698