Index: src/pdf/SkPDFFont.cpp |
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp |
index 5cc80b04ec814f34398f89d3934e1b06075cdeb1..4d114f0e1a91b72c6e5ee28269f8c9a5dd341059 100644 |
--- a/src/pdf/SkPDFFont.cpp |
+++ b/src/pdf/SkPDFFont.cpp |
@@ -11,6 +11,7 @@ |
#include "SkPDFCanon.h" |
#include "SkPDFConvertType1FontStream.h" |
#include "SkPDFDevice.h" |
+#include "SkPDFMakeCIDGlyphWidthsArray.h" |
#include "SkPDFMakeToUnicodeCmap.h" |
#include "SkPDFFont.h" |
#include "SkPDFUtils.h" |
@@ -31,29 +32,11 @@ |
#endif |
namespace { |
- |
// PDF's notion of symbolic vs non-symbolic is related to the character set, not |
// symbols vs. characters. Rarely is a font the right character set to call it |
// non-symbolic, so always call it symbolic. (PDF 1.4 spec, section 5.7.1) |
static const int kPdfSymbolic = 4; |
-struct AdvanceMetric { |
- enum MetricType { |
- kDefault, // Default advance: fAdvance.count = 1 |
- kRange, // Advances for a range: fAdvance.count = fEndID-fStartID |
- kRun // fStartID-fEndID have same advance: fAdvance.count = 1 |
- }; |
- MetricType fType; |
- uint16_t fStartId; |
- uint16_t fEndId; |
- SkTDArray<int16_t> fAdvance; |
- AdvanceMetric(uint16_t startId) : fStartId(startId) {} |
- AdvanceMetric(AdvanceMetric&&) = default; |
- AdvanceMetric& operator=(AdvanceMetric&& other) = default; |
- AdvanceMetric(const AdvanceMetric&) = delete; |
- AdvanceMetric& operator=(const AdvanceMetric&) = delete; |
-}; |
- |
class SkPDFType0Font final : public SkPDFFont { |
public: |
SkPDFType0Font(sk_sp<const SkAdvancedTypefaceMetrics> info, |
@@ -107,197 +90,22 @@ public: |
// File-Local Functions |
/////////////////////////////////////////////////////////////////////////////// |
-const int16_t kInvalidAdvance = SK_MinS16; |
-const int16_t kDontCareAdvance = SK_MinS16 + 1; |
- |
-static void stripUninterestingTrailingAdvancesFromRange( |
- AdvanceMetric* range) { |
- SkASSERT(range); |
- |
- int expectedAdvanceCount = range->fEndId - range->fStartId + 1; |
- if (range->fAdvance.count() < expectedAdvanceCount) { |
- return; |
- } |
- |
- for (int i = expectedAdvanceCount - 1; i >= 0; --i) { |
- if (range->fAdvance[i] != kDontCareAdvance && |
- range->fAdvance[i] != kInvalidAdvance && |
- range->fAdvance[i] != 0) { |
- range->fEndId = range->fStartId + i; |
- break; |
- } |
- } |
-} |
- |
-static void zeroWildcardsInRange(AdvanceMetric* range) { |
- SkASSERT(range); |
- if (range->fType != AdvanceMetric::kRange) { |
- return; |
- } |
- SkASSERT(range->fAdvance.count() == range->fEndId - range->fStartId + 1); |
- |
- // Zero out wildcards. |
- for (int i = 0; i < range->fAdvance.count(); ++i) { |
- if (range->fAdvance[i] == kDontCareAdvance) { |
- range->fAdvance[i] = 0; |
- } |
- } |
-} |
- |
-static void FinishRange( |
- AdvanceMetric* range, |
- int endId, |
- AdvanceMetric::MetricType type) { |
- range->fEndId = endId; |
- range->fType = type; |
- stripUninterestingTrailingAdvancesFromRange(range); |
- int newLength; |
- if (type == AdvanceMetric::kRange) { |
- newLength = range->fEndId - range->fStartId + 1; |
- } else { |
- if (range->fEndId == range->fStartId) { |
- range->fType = AdvanceMetric::kRange; |
- } |
- newLength = 1; |
- } |
- SkASSERT(range->fAdvance.count() >= newLength); |
- range->fAdvance.setCount(newLength); |
- zeroWildcardsInRange(range); |
-} |
- |
-/** Retrieve advance data for glyphs. Used by the PDF backend. */ |
-// TODO(halcanary): this function is complex enough to need its logic |
-// tested with unit tests. On the other hand, I want to do another |
-// round of re-factoring before figuring out how to mock this. |
-// TODO(halcanary): this function should be combined with |
-// composeAdvanceData() so that we don't need to produce a linked list |
-// of intermediate values. Or we could make the intermediate value |
-// something other than a linked list. |
-static void set_glyph_widths(SkTypeface* typeface, |
- const SkPDFGlyphSet* subset, |
- SkSinglyLinkedList<AdvanceMetric>* glyphWidths) { |
+static SkAutoGlyphCache vector_cache(SkTypeface* face, SkScalar size = 0) { |
SkPaint tmpPaint; |
tmpPaint.setHinting(SkPaint::kNo_Hinting); |
- tmpPaint.setTypeface(sk_ref_sp(typeface)); |
- tmpPaint.setTextSize((SkScalar)typeface->getUnitsPerEm()); |
+ tmpPaint.setTypeface(sk_ref_sp(face)); |
+ if (0 == size) { |
+ SkASSERT(face); |
+ tmpPaint.setTextSize((SkScalar)face->getUnitsPerEm()); |
+ } else { |
+ tmpPaint.setTextSize(size); |
+ } |
const SkSurfaceProps props(0, kUnknown_SkPixelGeometry); |
SkAutoGlyphCache glyphCache(tmpPaint, &props, nullptr); |
SkASSERT(glyphCache.get()); |
- |
- // Assuming that on average, the ASCII representation of an advance plus |
- // a space is 8 characters and the ASCII representation of a glyph id is 3 |
- // characters, then the following cut offs for using different range types |
- // apply: |
- // The cost of stopping and starting the range is 7 characers |
- // a. Removing 4 0's or don't care's is a win |
- // The cost of stopping and starting the range plus a run is 22 |
- // characters |
- // b. Removing 3 repeating advances is a win |
- // c. Removing 2 repeating advances and 3 don't cares is a win |
- // When not currently in a range the cost of a run over a range is 16 |
- // characaters, so: |
- // d. Removing a leading 0/don't cares is a win because it is omitted |
- // e. Removing 2 repeating advances is a win |
- |
- int num_glyphs = typeface->countGlyphs(); |
- |
- AdvanceMetric* prevRange = nullptr; |
- int16_t lastAdvance = kInvalidAdvance; |
- int repeatedAdvances = 0; |
- int wildCardsInRun = 0; |
- int trailingWildCards = 0; |
- |
- // Limit the loop count to glyph id ranges provided. |
- int lastIndex = num_glyphs; |
- if (subset) { |
- while (!subset->has(lastIndex - 1) && lastIndex > 0) { |
- --lastIndex; |
- } |
- } |
- AdvanceMetric curRange(0); |
- |
- for (int gId = 0; gId <= lastIndex; gId++) { |
- int16_t advance = kInvalidAdvance; |
- if (gId < lastIndex) { |
- if (!subset || 0 == gId || subset->has(gId)) { |
- advance = (int16_t)glyphCache->getGlyphIDAdvance(gId).fAdvanceX; |
- } else { |
- advance = kDontCareAdvance; |
- } |
- } |
- if (advance == lastAdvance) { |
- repeatedAdvances++; |
- trailingWildCards = 0; |
- } else if (advance == kDontCareAdvance) { |
- wildCardsInRun++; |
- trailingWildCards++; |
- } else if (curRange.fAdvance.count() == |
- repeatedAdvances + 1 + wildCardsInRun) { // All in run. |
- if (lastAdvance == 0) { |
- curRange.fStartId = gId; // reset |
- curRange.fAdvance.setCount(0); |
- trailingWildCards = 0; |
- } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) { |
- FinishRange(&curRange, gId - 1, AdvanceMetric::kRun); |
- prevRange = glyphWidths->emplace_back(std::move(curRange)); |
- curRange = AdvanceMetric(gId); |
- trailingWildCards = 0; |
- } |
- repeatedAdvances = 0; |
- wildCardsInRun = trailingWildCards; |
- trailingWildCards = 0; |
- } else { |
- if (lastAdvance == 0 && |
- repeatedAdvances + 1 + wildCardsInRun >= 4) { |
- FinishRange(&curRange, |
- gId - repeatedAdvances - wildCardsInRun - 2, |
- AdvanceMetric::kRange); |
- prevRange = glyphWidths->emplace_back(std::move(curRange)); |
- curRange = AdvanceMetric(gId); |
- trailingWildCards = 0; |
- } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) { |
- FinishRange(&curRange, gId - trailingWildCards - 1, |
- AdvanceMetric::kRange); |
- prevRange = glyphWidths->emplace_back(std::move(curRange)); |
- curRange = AdvanceMetric(gId); |
- trailingWildCards = 0; |
- } else if (lastAdvance != 0 && |
- (repeatedAdvances + 1 >= 3 || |
- (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) { |
- FinishRange(&curRange, |
- gId - repeatedAdvances - wildCardsInRun - 2, |
- AdvanceMetric::kRange); |
- (void)glyphWidths->emplace_back(std::move(curRange)); |
- curRange = |
- AdvanceMetric(gId - repeatedAdvances - wildCardsInRun - 1); |
- curRange.fAdvance.append(1, &lastAdvance); |
- FinishRange(&curRange, gId - 1, AdvanceMetric::kRun); |
- prevRange = glyphWidths->emplace_back(std::move(curRange)); |
- curRange = AdvanceMetric(gId); |
- trailingWildCards = 0; |
- } |
- repeatedAdvances = 0; |
- wildCardsInRun = trailingWildCards; |
- trailingWildCards = 0; |
- } |
- curRange.fAdvance.append(1, &advance); |
- if (advance != kDontCareAdvance) { |
- lastAdvance = advance; |
- } |
- } |
- if (curRange.fStartId == lastIndex) { |
- if (!prevRange) { |
- glyphWidths->reset(); |
- return; // https://crbug.com/567031 |
- } |
- } else { |
- FinishRange(&curRange, lastIndex - 1, AdvanceMetric::kRange); |
- glyphWidths->emplace_back(std::move(curRange)); |
- } |
+ return glyphCache; |
} |
-//////////////////////////////////////////////////////////////////////////////// |
- |
// scale from em-units to base-1000, returning as a SkScalar |
SkScalar from_font_units(SkScalar scaled, uint16_t emSize) { |
if (emSize == 1000) { |
@@ -336,41 +144,6 @@ static sk_sp<SkPDFArray> makeFontBBox(SkIRect glyphBBox, uint16_t emSize) { |
bbox->appendScalar(scaleFromFontUnits(glyphBBox.fTop, emSize)); |
return bbox; |
} |
- |
-sk_sp<SkPDFArray> composeAdvanceData( |
- const SkSinglyLinkedList<AdvanceMetric>& advanceInfo, |
- uint16_t emSize, |
- int16_t* defaultAdvance) { |
- auto result = sk_make_sp<SkPDFArray>(); |
- for (const AdvanceMetric& range : advanceInfo) { |
- switch (range.fType) { |
- case AdvanceMetric::kDefault: { |
- SkASSERT(range.fAdvance.count() == 1); |
- *defaultAdvance = range.fAdvance[0]; |
- break; |
- } |
- case AdvanceMetric::kRange: { |
- auto advanceArray = sk_make_sp<SkPDFArray>(); |
- for (int j = 0; j < range.fAdvance.count(); j++) |
- advanceArray->appendScalar( |
- scaleFromFontUnits(range.fAdvance[j], emSize)); |
- result->appendInt(range.fStartId); |
- result->appendObject(std::move(advanceArray)); |
- break; |
- } |
- case AdvanceMetric::kRun: { |
- SkASSERT(range.fAdvance.count() == 1); |
- result->appendInt(range.fStartId); |
- result->appendInt(range.fEndId); |
- result->appendScalar( |
- scaleFromFontUnits(range.fAdvance[0], emSize)); |
- break; |
- } |
- } |
- } |
- return result; |
-} |
- |
} // namespace |
@@ -834,19 +607,20 @@ bool SkPDFType0Font::populate(const SkPDFGlyphSet* subset) { |
sysInfo->insertInt("Supplement", 0); |
newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo)); |
- SkSinglyLinkedList<AdvanceMetric> tmpMetrics; |
- set_glyph_widths(face, subset, &tmpMetrics); |
+ uint16_t emSize = this->getFontInfo()->fEmSize; |
int16_t defaultWidth = 0; |
- uint16_t emSize = (uint16_t)this->getFontInfo()->fEmSize; |
- sk_sp<SkPDFArray> widths = composeAdvanceData(tmpMetrics, emSize, &defaultWidth); |
- if (widths->size()) { |
- newCIDFont->insertObject("W", std::move(widths)); |
+ const SkBitSet* bitSet = subset ? &subset->bitSet() : nullptr; |
+ { |
+ SkAutoGlyphCache glyphCache = vector_cache(face); |
+ sk_sp<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray( |
+ glyphCache.get(), bitSet, emSize, &defaultWidth); |
+ if (widths && widths->size() > 0) { |
+ newCIDFont->insertObject("W", std::move(widths)); |
+ } |
+ newCIDFont->insertScalar( |
+ "DW", scaleFromFontUnits(defaultWidth, emSize)); |
} |
- newCIDFont->insertScalar( |
- "DW", scaleFromFontUnits(defaultWidth, emSize)); |
- |
- |
//////////////////////////////////////////////////////////////////////////// |
this->insertName("Subtype", "Type0"); |
@@ -933,12 +707,7 @@ bool SkPDFType1Font::populate(int16_t glyphID) { |
this->insertInt("FirstChar", (size_t)0); |
this->insertInt("LastChar", (size_t)glyphCount); |
{ |
- SkPaint tmpPaint; |
- tmpPaint.setHinting(SkPaint::kNo_Hinting); |
- tmpPaint.setTypeface(sk_ref_sp(this->typeface())); |
- tmpPaint.setTextSize((SkScalar)this->typeface()->getUnitsPerEm()); |
- const SkSurfaceProps props(0, kUnknown_SkPixelGeometry); |
- SkAutoGlyphCache glyphCache(tmpPaint, &props, nullptr); |
+ SkAutoGlyphCache glyphCache = vector_cache(this->typeface()); |
auto widths = sk_make_sp<SkPDFArray>(); |
SkScalar advance = glyphCache->getGlyphIDAdvance(0).fAdvanceX; |
const uint16_t emSize = this->getFontInfo()->fEmSize; |
@@ -1012,13 +781,8 @@ static void add_type3_font_info(SkPDFDict* font, |
SkGlyphID firstGlyphID, |
SkGlyphID lastGlyphID) { |
SkASSERT(lastGlyphID >= firstGlyphID); |
- SkPaint paint; |
- paint.setHinting(SkPaint::kNo_Hinting); |
- paint.setTypeface(sk_ref_sp(typeface)); |
- paint.setTextSize(emSize); |
- const SkSurfaceProps props(0, kUnknown_SkPixelGeometry); |
- SkAutoGlyphCache cache(paint, &props, nullptr); |
- |
+ SkASSERT(emSize > 0.0f); |
+ SkAutoGlyphCache cache = vector_cache(typeface, emSize); |
font->insertName("Subtype", "Type3"); |
// Flip about the x-axis and scale by 1/emSize. |
SkMatrix fontMatrix; |