diff options
Diffstat (limited to 'chromium/third_party/skia/src')
4 files changed, 149 insertions, 218 deletions
diff --git a/chromium/third_party/skia/src/pdf/SkPDFFont.cpp b/chromium/third_party/skia/src/pdf/SkPDFFont.cpp index 33ec05b76ab..ba79a15c9a5 100644 --- a/chromium/third_party/skia/src/pdf/SkPDFFont.cpp +++ b/chromium/third_party/skia/src/pdf/SkPDFFont.cpp @@ -231,7 +231,11 @@ SkPDFFont::SkPDFFont(sk_sp<SkTypeface> typeface, : fTypeface(std::move(typeface)) , fGlyphUsage(firstGlyphID, lastGlyphID) , fIndirectReference(indirectReference) - , fFontType(fontType) {} + , fFontType(fontType) +{ + // Always include glyph 0 + this->noteGlyphUsage(0); +} void SkPDFFont::PopulateCommonFontDescriptor(SkPDFDict* descriptor, const SkAdvancedTypefaceMetrics& metrics, @@ -290,7 +294,7 @@ static void emit_subset_type0(const SkPDFFont& font, SkPDFDocument* doc) { auto descriptor = SkPDFMakeDict("FontDescriptor"); uint16_t emSize = SkToU16(font.typeface()->getUnitsPerEm()); - SkPDFFont::PopulateCommonFontDescriptor(descriptor.get(), metrics, emSize , 0); + SkPDFFont::PopulateCommonFontDescriptor(descriptor.get(), metrics, emSize, 0); int ttcIndex; std::unique_ptr<SkStreamAsset> fontAsset = face->openStream(&ttcIndex); @@ -369,7 +373,7 @@ static void emit_subset_type0(const SkPDFFont& font, SkPDFDocument* doc) { SkScalar defaultWidth = 0; { std::unique_ptr<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray( - *face, &font.glyphUsage(), &defaultWidth); + *face, font.glyphUsage(), &defaultWidth); if (widths && widths->size() > 0) { newCIDFont->insertObject("W", std::move(widths)); } diff --git a/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp b/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp index 589cfa76202..210202db4d1 100644 --- a/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp +++ b/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp @@ -13,6 +13,7 @@ #include "src/core/SkStrikeSpec.h" #include "src/pdf/SkPDFGlyphUse.h" +#include <algorithm> #include <vector> // TODO(halcanary): Write unit tests for SkPDFMakeCIDGlyphWidthsArray(). @@ -23,28 +24,8 @@ namespace { -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; - std::vector<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; -}; -const int16_t kInvalidAdvance = SK_MinS16; -const int16_t kDontCareAdvance = SK_MinS16 + 1; -} // namespace - // scale from em-units to base-1000, returning as a SkScalar -static SkScalar from_font_units(SkScalar scaled, uint16_t emSize) { +SkScalar from_font_units(SkScalar scaled, uint16_t emSize) { if (emSize == 1000) { return scaled; } else { @@ -52,224 +33,174 @@ static SkScalar from_font_units(SkScalar scaled, uint16_t emSize) { } } -static SkScalar scale_from_font_units(int16_t val, uint16_t emSize) { +SkScalar scale_from_font_units(int16_t val, uint16_t emSize) { return from_font_units(SkIntToScalar(val), emSize); } -static void strip_uninteresting_trailing_advances_from_range( - AdvanceMetric* range) { - SkASSERT(range); - - int expectedAdvanceCount = range->fEndId - range->fStartId + 1; - if (SkToInt(range->fAdvance.size()) < 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 zero_wildcards_in_range(AdvanceMetric* range) { - SkASSERT(range); - if (range->fType != AdvanceMetric::kRange) { - return; +// Unfortunately poppler does not appear to respect the default width setting. +#if defined(SK_PDF_CAN_USE_DW) +int16_t findMode(SkSpan<const int16_t> advances) { + if (advances.empty()) { + return 0; } - SkASSERT(SkToInt(range->fAdvance.size()) == range->fEndId - range->fStartId + 1); - // Zero out wildcards. - for (size_t i = 0; i < range->fAdvance.size(); ++i) { - if (range->fAdvance[i] == kDontCareAdvance) { - range->fAdvance[i] = 0; - } - } -} + int16_t previousAdvance = advances[0]; + int16_t currentModeAdvance = advances[0]; + size_t currentCount = 1; + size_t currentModeCount = 1; -static void finish_range( - AdvanceMetric* range, - int endId, - AdvanceMetric::MetricType type) { - range->fEndId = endId; - range->fType = type; - strip_uninteresting_trailing_advances_from_range(range); - size_t newLength; - if (type == AdvanceMetric::kRange) { - newLength = range->fEndId - range->fStartId + 1; - } else { - if (range->fEndId == range->fStartId) { - range->fType = AdvanceMetric::kRange; + for (size_t i = 1; i < advances.size(); ++i) { + if (advances[i] == previousAdvance) { + ++currentCount; + } else { + if (currentCount > currentModeCount) { + currentModeAdvance = previousAdvance; + currentModeCount = currentCount; + } + previousAdvance = advances[i]; + currentCount = 1; } - newLength = 1; } - SkASSERT(range->fAdvance.size() >= newLength); - range->fAdvance.resize(newLength); - zero_wildcards_in_range(range); -} -static void compose_advance_data(const AdvanceMetric& range, - uint16_t emSize, - SkScalar* defaultAdvance, - SkPDFArray* result) { - switch (range.fType) { - case AdvanceMetric::kDefault: { - SkASSERT(range.fAdvance.size() == 1); - *defaultAdvance = scale_from_font_units(range.fAdvance[0], emSize); - break; - } - case AdvanceMetric::kRange: { - auto advanceArray = SkPDFMakeArray(); - for (size_t j = 0; j < range.fAdvance.size(); j++) - advanceArray->appendScalar(scale_from_font_units(range.fAdvance[j], emSize)); - result->appendInt(range.fStartId); - result->appendObject(std::move(advanceArray)); - break; - } - case AdvanceMetric::kRun: { - SkASSERT(range.fAdvance.size() == 1); - result->appendInt(range.fStartId); - result->appendInt(range.fEndId); - result->appendScalar(scale_from_font_units(range.fAdvance[0], emSize)); - break; - } - } + return currentCount > currentModeCount ? previousAdvance : currentModeAdvance; } +#endif +} // namespace /** 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. std::unique_ptr<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(const SkTypeface& typeface, - const SkPDFGlyphUse* subset, + const SkPDFGlyphUse& subset, SkScalar* defaultAdvance) { - // 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 characters - // 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 - // characters, so: - // d. Removing a leading 0/don't cares is a win because it is omitted - // e. Removing 2 repeating advances is a win + // There are two ways of expressing advances + // + // range: " gfid [adv.ances adv.ances ... adv.ances]" + // run: " gfid gfid adv.ances" + // + // Assuming that on average + // the ASCII representation of an advance plus a space is 10 characters + // the ASCII representation of a glyph id plus a space is 4 characters + // the ASCII representation of unused gid plus a space in a range is 2 characters + // + // When not in a range or run + // a. Skipping don't cares or defaults is a win (trivial) + // b. Run wins for 2+ repeats " gid gid adv.ances" + // " gid [adv.ances adv.ances]" + // rule: 2+ repeats create run as long as possible, else start range + // + // When in a range + // Cost of stopping and starting a range is 8 characters "] gid [" + // c. Skipping defaults is always a win " adv.ances" + // rule: end range if default seen + // d. Skipping 4+ don't cares is a win " 0 0 0 0" + // rule: end range if 4+ don't cares + // Cost of stop and start range plus run is 28 characters "] gid gid adv.ances gid [" + // e. Switching for 2+ repeats and 4+ don't cares wins " 0 0 adv.ances 0 0 adv.ances" + // rule: end range for 2+ repeats with 4+ don't cares + // f. Switching for 3+ repeats wins " adv.ances adv.ances adv.ances" + // rule: end range for 3+ repeats int emSize; SkStrikeSpec strikeSpec = SkStrikeSpec::MakePDFVector(typeface, &emSize); SkBulkGlyphMetricsAndPaths paths{strikeSpec}; auto result = SkPDFMakeArray(); - int num_glyphs = SkToInt(typeface.countGlyphs()); - - bool prevRange = false; - - 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); - - SkAutoTArray<SkGlyphID> glyphIDs{lastIndex + 1}; - for (int gId = 0; gId <= lastIndex; gId++) { - glyphIDs[gId] = gId; + std::vector<SkGlyphID> glyphIDs; + subset.getSetValues([&](unsigned index) { + glyphIDs.push_back(SkToU16(index)); + }); + auto glyphs = paths.glyphs(SkMakeSpan(glyphIDs)); + +#if defined(SK_PDF_CAN_USE_DW) + std::vector<int16_t> advances; + advances.reserve(glyphs.size()); + for (const SkGlyph* glyph : glyphs) { + advances.push_back((int16_t)glyph->advanceX()); } - - auto glyphs = paths.glyphs(SkMakeSpan(glyphIDs.get(), lastIndex + 1)); - - for (int gId = 0; gId <= lastIndex; gId++) { - int16_t advance = kInvalidAdvance; - if (gId < lastIndex) { - if (!subset || 0 == gId || subset->has(gId)) { - advance = (int16_t)glyphs[gId]->advanceX(); - } else { - advance = kDontCareAdvance; - } + std::sort(advances.begin(), advances.end()); + int16_t modeAdvance = findMode(SkMakeSpan(advances)); + *defaultAdvance = scale_from_font_units(modeAdvance, emSize); +#else + *defaultAdvance = 0; +#endif + + for (size_t i = 0; i < glyphs.size(); ++i) { + int16_t advance = (int16_t)glyphs[i]->advanceX(); + +#if defined(SK_PDF_CAN_USE_DW) + // a. Skipping don't cares or defaults is a win (trivial) + if (advance == modeAdvance) { + continue; } - if (advance == lastAdvance) { - repeatedAdvances++; - trailingWildCards = 0; - } else if (advance == kDontCareAdvance) { - wildCardsInRun++; - trailingWildCards++; - } else if (SkToInt(curRange.fAdvance.size()) == - repeatedAdvances + 1 + wildCardsInRun) { // All in run. - if (lastAdvance == 0) { - curRange.fStartId = gId; // reset - curRange.fAdvance.resize(0); - trailingWildCards = 0; - } else if (repeatedAdvances + 1 >= 2 || trailingWildCards >= 4) { - finish_range(&curRange, gId - 1, AdvanceMetric::kRun); - compose_advance_data(curRange, emSize, defaultAdvance, result.get()); - prevRange = true; - curRange = AdvanceMetric(gId); - trailingWildCards = 0; +#endif + + // b. 2+ repeats create run as long as possible, else start range + { + size_t j = i + 1; // j is always one past the last known repeat + for (; j < glyphs.size(); ++j) { + int16_t next_advance = (int16_t)glyphs[j]->advanceX(); + if (advance != next_advance) { + break; + } } - repeatedAdvances = 0; - wildCardsInRun = trailingWildCards; - trailingWildCards = 0; - } else { - if (lastAdvance == 0 && - repeatedAdvances + 1 + wildCardsInRun >= 4) { - finish_range(&curRange, - gId - repeatedAdvances - wildCardsInRun - 2, - AdvanceMetric::kRange); - compose_advance_data(curRange, emSize, defaultAdvance, result.get()); - prevRange = true; - curRange = AdvanceMetric(gId); - trailingWildCards = 0; - } else if (trailingWildCards >= 4 && repeatedAdvances + 1 < 2) { - finish_range(&curRange, gId - trailingWildCards - 1, - AdvanceMetric::kRange); - compose_advance_data(curRange, emSize, defaultAdvance, result.get()); - prevRange = true; - curRange = AdvanceMetric(gId); - trailingWildCards = 0; - } else if (lastAdvance != 0 && - (repeatedAdvances + 1 >= 3 || - (repeatedAdvances + 1 >= 2 && wildCardsInRun >= 3))) { - finish_range(&curRange, - gId - repeatedAdvances - wildCardsInRun - 2, - AdvanceMetric::kRange); - compose_advance_data(curRange, emSize, defaultAdvance, result.get()); - curRange = - AdvanceMetric(gId - repeatedAdvances - wildCardsInRun - 1); - curRange.fAdvance.push_back(lastAdvance); - finish_range(&curRange, gId - 1, AdvanceMetric::kRun); - compose_advance_data(curRange, emSize, defaultAdvance, result.get()); - prevRange = true; - curRange = AdvanceMetric(gId); - trailingWildCards = 0; + if (j - i >= 2) { + result->appendInt(glyphs[i]->getGlyphID()); + result->appendInt(glyphs[j - 1]->getGlyphID()); + result->appendScalar(scale_from_font_units(advance, emSize)); + i = j - 1; + continue; } - repeatedAdvances = 0; - wildCardsInRun = trailingWildCards; - trailingWildCards = 0; - } - curRange.fAdvance.push_back(advance); - if (advance != kDontCareAdvance) { - lastAdvance = advance; } - } - if (curRange.fStartId == lastIndex) { - if (!prevRange) { - return nullptr; // https://crbug.com/567031 + + { + result->appendInt(glyphs[i]->getGlyphID()); + auto advanceArray = SkPDFMakeArray(); + advanceArray->appendScalar(scale_from_font_units(advance, emSize)); + size_t j = i + 1; // j is always one past the last output + for (; j < glyphs.size(); ++j) { + advance = (int16_t)glyphs[j]->advanceX(); +#if defined(SK_PDF_CAN_USE_DW) + // c. end range if default seen + if (advance == modeAdvance) { + break; + } +#endif + + int dontCares = glyphs[j]->getGlyphID() - glyphs[j - 1]->getGlyphID() - 1; + // d. end range if 4+ don't cares + if (dontCares >= 4) { + break; + } + + int16_t next_advance = 0; + // e. end range for 2+ repeats with 4+ don't cares + if (j + 1 < glyphs.size()) { + next_advance = (int16_t)glyphs[j+1]->advanceX(); + int next_dontCares = glyphs[j+1]->getGlyphID() - glyphs[j]->getGlyphID() - 1; + if (advance == next_advance && dontCares + next_dontCares >= 4) { + break; + } + } + + // f. end range for 3+ repeats + if (j + 2 < glyphs.size() && advance == next_advance) { + next_advance = (int16_t)glyphs[j+2]->advanceX(); + if (advance == next_advance) { + break; + } + } + + while (dontCares --> 0) { + advanceArray->appendScalar(0); + } + advanceArray->appendScalar(scale_from_font_units(advance, emSize)); + } + result->appendObject(std::move(advanceArray)); + i = j - 1; } - } else { - finish_range(&curRange, lastIndex - 1, AdvanceMetric::kRange); - compose_advance_data(curRange, emSize, defaultAdvance, result.get()); } + return result; } diff --git a/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h b/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h index b2e1e1df55a..041fe28d8cb 100644 --- a/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h +++ b/chromium/third_party/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.h @@ -17,7 +17,7 @@ class SkTypeface; format that can specify individual widths for consecutive CIDs or one width for a range of CIDs". */ std::unique_ptr<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(const SkTypeface& typeface, - const SkPDFGlyphUse* subset, + const SkPDFGlyphUse& subset, SkScalar* defaultAdvance); #endif // SkPDFMakeCIDGlyphWidthsArray_DEFINED diff --git a/chromium/third_party/skia/src/pdf/SkPDFSubsetFont.cpp b/chromium/third_party/skia/src/pdf/SkPDFSubsetFont.cpp index 0bb92bb9622..5485f3b4ba3 100644 --- a/chromium/third_party/skia/src/pdf/SkPDFSubsetFont.cpp +++ b/chromium/third_party/skia/src/pdf/SkPDFSubsetFont.cpp @@ -68,7 +68,6 @@ static sk_sp<SkData> subset_harfbuzz(sk_sp<SkData> fontData, return nullptr; } hb_set_t* glyphs = hb_subset_input_glyph_set(input.get()); - hb_set_add(glyphs, 0); glyphUsage.getSetValues([&glyphs](unsigned gid) { hb_set_add(glyphs, gid);}); hb_subset_input_set_retain_gids(input.get(), true); @@ -99,9 +98,6 @@ static sk_sp<SkData> subset_sfntly(sk_sp<SkData> fontData, // Generate glyph id array in format needed by sfntly. // TODO(halcanary): sfntly should take a more compact format. std::vector<unsigned> subset; - if (!glyphUsage.has(0)) { - subset.push_back(0); // Always include glyph 0. - } glyphUsage.getSetValues([&subset](unsigned v) { subset.push_back(v); }); unsigned char* subsetFont{nullptr}; |