SkPDF: refactor & code cleanup ahead of https://crrev.com/2322403002
SkPDFDevice::GraphicStateEntry: remove unnecessary fFont and fTextSize. SkPDFDevice::updateFont(): replace with update_font() and inlined code. De-duplicate this block of code. SkPDFResourceDict::GetResourceTypePrefix function made public: removes need for temporary SkString returned by SkPDFResourceDict::getResourceName() GlyphPositioner: delay writing intial matrix until first glyph. Assert that widechars is a constant. SkPDFFont::FontType(): make public so that PDFDevice can know about multibyte status. SkPDFFont::countStretch() removed, and the stretch loop flattened. *no changes in PDF output* BUG=skia:5434 GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2327953002 Review-Url: https://codereview.chromium.org/2327953002
This commit is contained in:
parent
5192475bd8
commit
c2f9ec1f5e
@ -85,9 +85,7 @@ SkPDFDevice::GraphicStateEntry::GraphicStateEntry()
|
||||
, fTextScaleX(SK_Scalar1)
|
||||
, fTextFill(SkPaint::kFill_Style)
|
||||
, fShaderIndex(-1)
|
||||
, fGraphicStateIndex(-1)
|
||||
, fFont(nullptr)
|
||||
, fTextSize(SK_ScalarNaN) {
|
||||
, fGraphicStateIndex(-1) {
|
||||
fMatrix.reset();
|
||||
}
|
||||
|
||||
@ -861,20 +859,10 @@ public:
|
||||
bool defaultPositioning,
|
||||
SkPoint origin)
|
||||
: fContent(content)
|
||||
, fCurrentMatrixOrigin{0.0f, 0.0f}
|
||||
, fXAdvance(0.0f)
|
||||
, fCurrentMatrixOrigin(origin)
|
||||
, fTextSkewX(textSkewX)
|
||||
, fWideChars(wideChars)
|
||||
, fInText(false)
|
||||
, fDefaultPositioning(defaultPositioning) {
|
||||
// Flip the text about the x-axis to account for origin swap and include
|
||||
// the passed parameters.
|
||||
fContent->writeText("1 0 ");
|
||||
SkPDFUtils::AppendScalar(0 - textSkewX, fContent);
|
||||
fContent->writeText(" -1 ");
|
||||
SkPDFUtils::AppendScalar(origin.x(), fContent);
|
||||
fContent->writeText(" ");
|
||||
SkPDFUtils::AppendScalar(origin.y(), fContent);
|
||||
fContent->writeText(" Tm\n");
|
||||
}
|
||||
~GlyphPositioner() { this->flush(); }
|
||||
void flush() {
|
||||
@ -883,16 +871,22 @@ public:
|
||||
fInText = false;
|
||||
}
|
||||
}
|
||||
void setWideChars(bool wideChars) {
|
||||
if (fWideChars != wideChars) {
|
||||
SkASSERT(!fInText);
|
||||
SkASSERT(fWideChars == wideChars);
|
||||
fWideChars = wideChars;
|
||||
}
|
||||
}
|
||||
void writeGlyph(SkPoint xy,
|
||||
SkScalar advanceWidth,
|
||||
uint16_t glyph) {
|
||||
if (!fInitialized) {
|
||||
// Flip the text about the x-axis to account for origin swap and include
|
||||
// the passed parameters.
|
||||
fContent->writeText("1 0 ");
|
||||
SkPDFUtils::AppendScalar(-fTextSkewX, fContent);
|
||||
fContent->writeText(" -1 ");
|
||||
SkPDFUtils::AppendScalar(fCurrentMatrixOrigin.x(), fContent);
|
||||
fContent->writeText(" ");
|
||||
SkPDFUtils::AppendScalar(fCurrentMatrixOrigin.y(), fContent);
|
||||
fContent->writeText(" Tm\n");
|
||||
fCurrentMatrixOrigin.set(0.0f, 0.0f);
|
||||
fInitialized = true;
|
||||
}
|
||||
if (!fDefaultPositioning) {
|
||||
SkPoint position = xy - fCurrentMatrixOrigin;
|
||||
if (position != SkPoint{fXAdvance, 0}) {
|
||||
@ -921,9 +915,11 @@ public:
|
||||
private:
|
||||
SkDynamicMemoryWStream* fContent;
|
||||
SkPoint fCurrentMatrixOrigin;
|
||||
SkScalar fXAdvance;
|
||||
SkScalar fXAdvance = 0.0f;
|
||||
SkScalar fTextSkewX;
|
||||
bool fWideChars;
|
||||
bool fInText;
|
||||
bool fInText = false;
|
||||
bool fInitialized = false;
|
||||
const bool fDefaultPositioning;
|
||||
};
|
||||
} // namespace
|
||||
@ -969,6 +965,16 @@ static void draw_transparent_text(SkPDFDevice* device,
|
||||
}
|
||||
}
|
||||
|
||||
static void update_font(SkWStream* wStream, int fontIndex, SkScalar textSize) {
|
||||
wStream->writeText("/");
|
||||
char prefix = SkPDFResourceDict::GetResourceTypePrefix(SkPDFResourceDict::kFont_ResourceType);
|
||||
wStream->write(&prefix, 1);
|
||||
wStream->writeDecAsText(fontIndex);
|
||||
wStream->writeText(" ");
|
||||
SkPDFUtils::AppendScalar(textSize, wStream);
|
||||
wStream->writeText(" Tf\n");
|
||||
}
|
||||
|
||||
void SkPDFDevice::internalDrawText(
|
||||
const SkDraw& d, const void* sourceText, size_t sourceByteCount,
|
||||
const SkScalar pos[], SkTextBlob::GlyphPositioning positioning,
|
||||
@ -1067,74 +1073,50 @@ void SkPDFDevice::internalDrawText(
|
||||
SkDynamicMemoryWStream* out = &content.entry()->fContent;
|
||||
SkScalar textSize = paint.getTextSize();
|
||||
|
||||
int index = 0;
|
||||
while (glyphs[index] > maxGlyphID) { // Invalid glyphID for this font.
|
||||
++index; // Skip this glyphID
|
||||
if (index == glyphCount) {
|
||||
return; // all glyphIDs were bad.
|
||||
}
|
||||
}
|
||||
|
||||
out->writeText("BT\n");
|
||||
SK_AT_SCOPE_EXIT(out->writeText("ET\n"));
|
||||
|
||||
SkPDFFont* font = this->updateFont(
|
||||
typeface, textSize, glyphs[index], content.entry());
|
||||
SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met.
|
||||
if (!font) { return; }
|
||||
|
||||
bool multiByteGlyphs = SkPDFFont::IsMultiByte(SkPDFFont::FontType(*metrics));
|
||||
GlyphPositioner glyphPositioner(out,
|
||||
paint.getTextSkewX(),
|
||||
font->multiByteGlyphs(),
|
||||
multiByteGlyphs,
|
||||
defaultPositioning,
|
||||
offset);
|
||||
|
||||
while (index < glyphCount) {
|
||||
int stretch = font->countStretch(&glyphs[index], glyphCount - index, maxGlyphID);
|
||||
SkASSERT(index + stretch <= glyphCount);
|
||||
if (stretch < 1) {
|
||||
// The current pdf font cannot encode the next glyph.
|
||||
// Try to get a pdf font which can encode the next glyph.
|
||||
SkPDFFont* font = nullptr;
|
||||
for (int index = 0; index < glyphCount; ++index) {
|
||||
SkGlyphID gid = glyphs[index];
|
||||
if (gid > maxGlyphID) {
|
||||
continue; // Skip this invalid glyphID.
|
||||
}
|
||||
if (!font || !font->hasGlyph(gid)) {
|
||||
// Either this is the first loop iteration or the current
|
||||
// PDFFont cannot encode this glyph.
|
||||
glyphPositioner.flush();
|
||||
// first, validate the next glyph
|
||||
while (glyphs[index] > maxGlyphID) {
|
||||
++index; // Skip this glyphID
|
||||
if (index == glyphCount) {
|
||||
return; // all remainng glyphIDs were bad.
|
||||
}
|
||||
}
|
||||
SkASSERT(index < glyphCount);
|
||||
font = this->updateFont(typeface, textSize, glyphs[index], content.entry());
|
||||
SkASSERT(font); // preconditions for SkPDFFont::GetFontResource met.
|
||||
// Try to get a font which can encode the glyph.
|
||||
int fontIndex = this->getFontResourceIndex(typeface, gid);
|
||||
SkASSERT(fontIndex >= 0);
|
||||
if (fontIndex < 0) { return; }
|
||||
update_font(out, fontIndex, textSize);
|
||||
font = fFontResources[fontIndex];
|
||||
SkASSERT(font); // All preconditions for SkPDFFont::GetFontResource are met.
|
||||
if (!font) { return; }
|
||||
glyphPositioner.setWideChars(font->multiByteGlyphs());
|
||||
// Get stretch for this new font.
|
||||
stretch = font->countStretch(&glyphs[index], glyphCount - index, maxGlyphID);
|
||||
if (stretch < 1) {
|
||||
SkDEBUGFAIL("PDF could not encode glyph.");
|
||||
return;
|
||||
SkASSERT(font->multiByteGlyphs() == multiByteGlyphs);
|
||||
}
|
||||
font->noteGlyphUsage(gid);
|
||||
SkScalar advance{0.0f};
|
||||
SkPoint xy{0.0f, 0.0f};
|
||||
if (!defaultPositioning) {
|
||||
advance = glyphCache->getGlyphIDAdvance(gid).fAdvanceX;
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
++index;
|
||||
}
|
||||
SkGlyphID encodedGlyph =
|
||||
multiByteGlyphs ? gid : font->glyphToPDFFontEncoding(gid);
|
||||
glyphPositioner.writeGlyph(xy, advance, encodedGlyph);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1837,30 +1819,6 @@ int SkPDFDevice::addXObjectResource(SkPDFObject* xObject) {
|
||||
return result;
|
||||
}
|
||||
|
||||
SkPDFFont* SkPDFDevice::updateFont(SkTypeface* typeface,
|
||||
SkScalar textSize,
|
||||
uint16_t glyphID,
|
||||
SkPDFDevice::ContentEntry* contentEntry) {
|
||||
if (contentEntry->fState.fFont == nullptr ||
|
||||
contentEntry->fState.fTextSize != textSize ||
|
||||
!contentEntry->fState.fFont->hasGlyph(glyphID)) {
|
||||
int fontIndex = getFontResourceIndex(typeface, glyphID);
|
||||
if (fontIndex < 0) {
|
||||
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(textSize, &contentEntry->fContent);
|
||||
contentEntry->fContent.writeText(" Tf\n");
|
||||
contentEntry->fState.fFont = fFontResources[fontIndex];
|
||||
}
|
||||
return contentEntry->fState.fFont;
|
||||
}
|
||||
|
||||
int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
|
||||
sk_sp<SkPDFFont> newFont(
|
||||
SkPDFFont::GetFontResource(fDocument->canon(), typeface, glyphID));
|
||||
|
@ -170,13 +170,6 @@ public:
|
||||
SkPaint::Style fTextFill; // Only if TextScaleX is non-zero.
|
||||
int fShaderIndex;
|
||||
int fGraphicStateIndex;
|
||||
|
||||
// We may change the font (i.e. for Type1 support) within a
|
||||
// ContentEntry. This is the one currently in effect, or nullptr if none.
|
||||
SkPDFFont* fFont;
|
||||
// In PDF, text size has no default value. It is only valid if fFont is
|
||||
// not nullptr.
|
||||
SkScalar fTextSize;
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -279,11 +272,6 @@ private:
|
||||
int addGraphicStateResource(SkPDFObject* gs);
|
||||
int addXObjectResource(SkPDFObject* xObject);
|
||||
|
||||
// returns nullptr when a valid SkFont can not be produced
|
||||
SkPDFFont* updateFont(SkTypeface* typeface,
|
||||
SkScalar textSize,
|
||||
uint16_t glyphID,
|
||||
ContentEntry* contentEntry);
|
||||
int getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID);
|
||||
|
||||
|
||||
|
@ -161,7 +161,7 @@ const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(SkTypeface* typeface,
|
||||
return *canon->fTypefaceMetrics.set(id, metrics.release());
|
||||
}
|
||||
|
||||
SkAdvancedTypefaceMetrics::FontType font_type(const SkAdvancedTypefaceMetrics& metrics) {
|
||||
SkAdvancedTypefaceMetrics::FontType SkPDFFont::FontType(const SkAdvancedTypefaceMetrics& metrics) {
|
||||
if (SkToBool(metrics.fFlags & SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag)) {
|
||||
// force Type3 fallback.
|
||||
return SkAdvancedTypefaceMetrics::kOther_Font;
|
||||
@ -182,7 +182,7 @@ SkPDFFont* SkPDFFont::GetFontResource(SkPDFCanon* canon,
|
||||
SkASSERT(fontMetrics); // SkPDFDevice::internalDrawText ensures the typeface is good.
|
||||
// GetMetrics only returns null to signify a bad typeface.
|
||||
const SkAdvancedTypefaceMetrics& metrics = *fontMetrics;
|
||||
SkAdvancedTypefaceMetrics::FontType type = font_type(metrics);
|
||||
SkAdvancedTypefaceMetrics::FontType type = SkPDFFont::FontType(metrics);
|
||||
bool multibyte = SkPDFFont::IsMultiByte(type);
|
||||
SkGlyphID subsetCode = multibyte ? 0 : first_nonzero_glyph_for_single_byte_encoding(glyphID);
|
||||
uint64_t fontID = (SkTypeface::UniqueID(face) << 16) | subsetCode;
|
||||
|
@ -40,6 +40,8 @@ public:
|
||||
*/
|
||||
SkAdvancedTypefaceMetrics::FontType getType() const { return fFontType; }
|
||||
|
||||
static SkAdvancedTypefaceMetrics::FontType FontType(const SkAdvancedTypefaceMetrics&);
|
||||
|
||||
static bool IsMultiByte(SkAdvancedTypefaceMetrics::FontType type) {
|
||||
return type == SkAdvancedTypefaceMetrics::kType1CID_Font ||
|
||||
type == SkAdvancedTypefaceMetrics::kTrueType_Font;
|
||||
@ -65,24 +67,6 @@ public:
|
||||
return gid - fFirstGlyphID + 1;
|
||||
}
|
||||
|
||||
/** Count the number of glyphIDs that can be encoded with this font.
|
||||
* glyphIDs > maxGlyphID are considered okay. */
|
||||
int countStretch(const SkGlyphID* glyphIDs,
|
||||
int numGlyphs,
|
||||
SkGlyphID maxGlyphID) const {
|
||||
if (this->multiByteGlyphs()) {
|
||||
return numGlyphs;
|
||||
}
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
SkGlyphID gid = glyphIDs[i];
|
||||
if (gid != 0 && gid <= maxGlyphID &&
|
||||
(gid < fFirstGlyphID || gid > fLastGlyphID)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return numGlyphs;
|
||||
}
|
||||
|
||||
void noteGlyphUsage(SkGlyphID glyph) {
|
||||
SkASSERT(this->hasGlyph(glyph));
|
||||
fGlyphUsage.set(glyph);
|
||||
|
@ -32,7 +32,7 @@ static const char* resource_type_names[] = {
|
||||
"Font"
|
||||
};
|
||||
|
||||
static char get_resource_type_prefix(
|
||||
char SkPDFResourceDict::GetResourceTypePrefix(
|
||||
SkPDFResourceDict::SkPDFResourceType type) {
|
||||
SkASSERT(type >= 0);
|
||||
SkASSERT(type < SkPDFResourceDict::kResourceTypeCount);
|
||||
@ -50,9 +50,7 @@ static const char* get_resource_type_name(
|
||||
|
||||
SkString SkPDFResourceDict::getResourceName(
|
||||
SkPDFResourceDict::SkPDFResourceType type, int key) {
|
||||
SkString keyString;
|
||||
keyString.printf("%c%d", get_resource_type_prefix(type), key);
|
||||
return keyString;
|
||||
return SkStringPrintf("%c%d", SkPDFResourceDict::GetResourceTypePrefix(type), key);
|
||||
}
|
||||
|
||||
static void add_subdict(
|
||||
|
@ -32,6 +32,8 @@ public:
|
||||
kResourceTypeCount
|
||||
};
|
||||
|
||||
static char GetResourceTypePrefix(SkPDFResourceDict::SkPDFResourceType type);
|
||||
|
||||
/** Create a PDF resource dictionary.
|
||||
* The full set of ProcSet entries is automatically created for backwards
|
||||
* compatibility, as recommended by the PDF spec.
|
||||
|
Loading…
Reference in New Issue
Block a user