| Index: src/pdf/SkPDFFont.cpp
|
| diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
|
| index db687fba5f7942400e4fab0b35e0d4ce94c4ffc3..093ad4a90daa95470ba3c0674e02190f7a383dbf 100644
|
| --- a/src/pdf/SkPDFFont.cpp
|
| +++ b/src/pdf/SkPDFFont.cpp
|
| @@ -36,12 +36,230 @@
|
| // 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;
|
| +};
|
| +
|
| namespace {
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
| // 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.
|
| + @param num_glyphs Total number of glyphs in the given font.
|
| + @param glyphIDs For per-glyph info, specify subset of the
|
| + font by giving glyph ids. Each integer
|
| + represents a glyph id. Passing nullptr
|
| + means all glyphs in the font.
|
| + @param glyphIDsCount Number of elements in subsetGlyphIds.
|
| + Ignored if glyphIDs is nullptr.
|
| +*/
|
| +// 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 get_glyph_widths(SkSinglyLinkedList<AdvanceMetric>* glyphWidths,
|
| + int num_glyphs,
|
| + const uint32_t* subsetGlyphIDs,
|
| + uint32_t subsetGlyphIDsLength,
|
| + SkGlyphCache* glyphCache) {
|
| + // 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
|
| +
|
| + AdvanceMetric* prevRange = nullptr;
|
| + int16_t lastAdvance = kInvalidAdvance;
|
| + int repeatedAdvances = 0;
|
| + int wildCardsInRun = 0;
|
| + int trailingWildCards = 0;
|
| + uint32_t subsetIndex = 0;
|
| +
|
| + // Limit the loop count to glyph id ranges provided.
|
| + int firstIndex = 0;
|
| + int lastIndex = num_glyphs;
|
| + if (subsetGlyphIDs) {
|
| + firstIndex = static_cast<int>(subsetGlyphIDs[0]);
|
| + lastIndex =
|
| + static_cast<int>(subsetGlyphIDs[subsetGlyphIDsLength - 1]) + 1;
|
| + }
|
| + AdvanceMetric curRange(firstIndex);
|
| +
|
| + for (int gId = firstIndex; gId <= lastIndex; gId++) {
|
| + int16_t advance = kInvalidAdvance;
|
| + if (gId < lastIndex) {
|
| + // Get glyph id only when subset is nullptr, or the id is in subset.
|
| + SkASSERT(!subsetGlyphIDs || (subsetIndex < subsetGlyphIDsLength &&
|
| + static_cast<uint32_t>(gId) <= subsetGlyphIDs[subsetIndex]));
|
| + if (!subsetGlyphIDs ||
|
| + (subsetIndex < subsetGlyphIDsLength &&
|
| + static_cast<uint32_t>(gId) == subsetGlyphIDs[subsetIndex])) {
|
| + advance = (int16_t)glyphCache->getGlyphIDAdvance(gId).fAdvanceX;
|
| + ++subsetIndex;
|
| + } 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));
|
| + }
|
| +}
|
| +
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +
|
| bool parsePFBSection(const uint8_t** src, size_t* len, int sectionType,
|
| size_t* size) {
|
| // PFB sections have a two or six bytes header. 0x80 and a one byte
|
| @@ -302,18 +520,18 @@ static sk_sp<SkPDFArray> makeFontBBox(SkIRect glyphBBox, uint16_t emSize) {
|
| }
|
|
|
| sk_sp<SkPDFArray> composeAdvanceData(
|
| - const SkSinglyLinkedList<SkAdvancedTypefaceMetrics::WidthRange>& advanceInfo,
|
| + const SkSinglyLinkedList<AdvanceMetric>& advanceInfo,
|
| uint16_t emSize,
|
| int16_t* defaultAdvance) {
|
| auto result = sk_make_sp<SkPDFArray>();
|
| - for (const SkAdvancedTypefaceMetrics::WidthRange& range : advanceInfo) {
|
| + for (const AdvanceMetric& range : advanceInfo) {
|
| switch (range.fType) {
|
| - case SkAdvancedTypefaceMetrics::WidthRange::kDefault: {
|
| + case AdvanceMetric::kDefault: {
|
| SkASSERT(range.fAdvance.count() == 1);
|
| *defaultAdvance = range.fAdvance[0];
|
| break;
|
| }
|
| - case SkAdvancedTypefaceMetrics::WidthRange::kRange: {
|
| + case AdvanceMetric::kRange: {
|
| auto advanceArray = sk_make_sp<SkPDFArray>();
|
| for (int j = 0; j < range.fAdvance.count(); j++)
|
| advanceArray->appendScalar(
|
| @@ -322,7 +540,7 @@ sk_sp<SkPDFArray> composeAdvanceData(
|
| result->appendObject(std::move(advanceArray));
|
| break;
|
| }
|
| - case SkAdvancedTypefaceMetrics::WidthRange::kRun: {
|
| + case AdvanceMetric::kRun: {
|
| SkASSERT(range.fAdvance.count() == 1);
|
| result->appendInt(range.fStartId);
|
| result->appendInt(range.fEndId);
|
| @@ -1042,24 +1260,17 @@ bool SkPDFCIDFont::addFontDescriptor(int16_t defaultWidth,
|
|
|
| void set_glyph_widths(SkTypeface* tf,
|
| const SkTDArray<uint32_t>* glyphIDs,
|
| - SkAdvancedTypefaceMetrics* dst) {
|
| + SkSinglyLinkedList<AdvanceMetric>* dst) {
|
| SkPaint tmpPaint;
|
| tmpPaint.setHinting(SkPaint::kNo_Hinting);
|
| tmpPaint.setTypeface(sk_ref_sp(tf));
|
| tmpPaint.setTextSize((SkScalar)tf->getUnitsPerEm());
|
| SkAutoGlyphCache autoGlyphCache(tmpPaint, nullptr, nullptr);
|
| - SkGlyphCache* glyphCache = autoGlyphCache.get();
|
| - SkAdvancedTypefaceMetrics::GetAdvance advanceFn =
|
| - [glyphCache](int gid, int16_t* advance) {
|
| - *advance = (int16_t)glyphCache->getGlyphIDAdvance(gid).fAdvanceX;
|
| - return true;
|
| - };
|
| if (!glyphIDs || glyphIDs->isEmpty()) {
|
| - dst->setGlyphWidths(tf->countGlyphs(), nullptr, 0, advanceFn);
|
| + get_glyph_widths(dst, tf->countGlyphs(), nullptr, 0, autoGlyphCache.get());
|
| } else {
|
| - dst->setGlyphWidths(tf->countGlyphs(),
|
| - glyphIDs->begin(),
|
| - glyphIDs->count(), advanceFn);
|
| + get_glyph_widths(dst, tf->countGlyphs(), glyphIDs->begin(),
|
| + glyphIDs->count(), autoGlyphCache.get());
|
| }
|
| }
|
|
|
| @@ -1103,12 +1314,11 @@ bool SkPDFCIDFont::populate(const SkPDFGlyphSet* subset) {
|
| sysInfo->insertInt("Supplement", 0);
|
| this->insertObject("CIDSystemInfo", std::move(sysInfo));
|
|
|
| - SkAdvancedTypefaceMetrics tmpMetrics;
|
| + SkSinglyLinkedList<AdvanceMetric> tmpMetrics;
|
| set_glyph_widths(this->typeface(), &glyphIDs, &tmpMetrics);
|
| int16_t defaultWidth = 0;
|
| uint16_t emSize = (uint16_t)this->fontInfo()->fEmSize;
|
| - sk_sp<SkPDFArray> widths = composeAdvanceData(
|
| - tmpMetrics.fGlyphWidths, emSize, &defaultWidth);
|
| + sk_sp<SkPDFArray> widths = composeAdvanceData(tmpMetrics, emSize, &defaultWidth);
|
| if (widths->size()) {
|
| this->insertObject("W", std::move(widths));
|
| }
|
| @@ -1169,25 +1379,22 @@ bool SkPDFType1Font::addFontDescriptor(int16_t defaultWidth) {
|
| }
|
|
|
| bool SkPDFType1Font::populate(int16_t glyphID) {
|
| - SkASSERT(fontInfo()->fVerticalMetrics.empty());
|
| - SkASSERT(fontInfo()->fGlyphWidths.empty());
|
| -
|
| adjustGlyphRangeForSingleByteEncoding(glyphID);
|
|
|
| int16_t defaultWidth = 0;
|
| - const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry = nullptr;
|
| + const AdvanceMetric* widthRangeEntry = nullptr;
|
| {
|
| - SkAdvancedTypefaceMetrics tmpMetrics;
|
| + SkSinglyLinkedList<AdvanceMetric> tmpMetrics;
|
| set_glyph_widths(this->typeface(), nullptr, &tmpMetrics);
|
| - for (const auto& widthEntry : tmpMetrics.fGlyphWidths) {
|
| + for (const auto& widthEntry : tmpMetrics) {
|
| switch (widthEntry.fType) {
|
| - case SkAdvancedTypefaceMetrics::WidthRange::kDefault:
|
| + case AdvanceMetric::kDefault:
|
| defaultWidth = widthEntry.fAdvance[0];
|
| break;
|
| - case SkAdvancedTypefaceMetrics::WidthRange::kRun:
|
| + case AdvanceMetric::kRun:
|
| SkASSERT(false);
|
| break;
|
| - case SkAdvancedTypefaceMetrics::WidthRange::kRange:
|
| + case AdvanceMetric::kRange:
|
| SkASSERT(widthRangeEntry == nullptr);
|
| widthRangeEntry = &widthEntry;
|
| break;
|
| @@ -1206,8 +1413,9 @@ bool SkPDFType1Font::populate(int16_t glyphID) {
|
| auto encDiffs = sk_make_sp<SkPDFArray>();
|
| encDiffs->reserve(lastGlyphID() - firstGlyphID() + 2);
|
| encDiffs->appendInt(1);
|
| + SkASSERT(this->fontInfo()->fGlyphNames.count() >= this->lastGlyphID());
|
| for (int gID = firstGlyphID(); gID <= lastGlyphID(); gID++) {
|
| - encDiffs->appendName(fontInfo()->fGlyphNames->get()[gID].c_str());
|
| + encDiffs->appendName(fontInfo()->fGlyphNames[gID].c_str());
|
| }
|
|
|
| auto encoding = sk_make_sp<SkPDFDict>("Encoding");
|
| @@ -1218,7 +1426,7 @@ bool SkPDFType1Font::populate(int16_t glyphID) {
|
|
|
| void SkPDFType1Font::addWidthInfoFromRange(
|
| int16_t defaultWidth,
|
| - const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry) {
|
| + const AdvanceMetric* widthRangeEntry) {
|
| auto widthArray = sk_make_sp<SkPDFArray>();
|
| int firstChar = 0;
|
| if (widthRangeEntry) {
|
|
|