2 * Copyright 2016 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "src/pdf/SkPDFMakeCIDGlyphWidthsArray.h"
10 #include "include/core/SkPaint.h"
11 #include "include/private/SkTo.h"
12 #include "src/core/SkScalerCache.h"
13 #include "src/core/SkStrikeSpec.h"
14 #include "src/pdf/SkPDFGlyphUse.h"
19 // TODO(halcanary): Write unit tests for SkPDFMakeCIDGlyphWidthsArray().
21 // TODO(halcanary): The logic in this file originated in several
22 // disparate places. I feel sure that someone could simplify this
23 // down to a single easy-to-read function.
27 // scale from em-units to base-1000, returning as a SkScalar
28 SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
32 return scaled * 1000 / emSize;
36 SkScalar scale_from_font_units(int16_t val, uint16_t emSize) {
37 return from_font_units(SkIntToScalar(val), emSize);
40 // Unfortunately poppler does not appear to respect the default width setting.
41 #if defined(SK_PDF_CAN_USE_DW)
42 int16_t findMode(SkSpan<const int16_t> advances) {
43 if (advances.empty()) {
47 int16_t previousAdvance = advances[0];
48 int16_t currentModeAdvance = advances[0];
49 size_t currentCount = 1;
50 size_t currentModeCount = 1;
52 for (size_t i = 1; i < advances.size(); ++i) {
53 if (advances[i] == previousAdvance) {
56 if (currentCount > currentModeCount) {
57 currentModeAdvance = previousAdvance;
58 currentModeCount = currentCount;
60 previousAdvance = advances[i];
65 return currentCount > currentModeCount ? previousAdvance : currentModeAdvance;
70 /** Retrieve advance data for glyphs. Used by the PDF backend. */
71 // TODO(halcanary): this function is complex enough to need its logic
72 // tested with unit tests.
73 std::unique_ptr<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(const SkTypeface& typeface,
74 const SkPDFGlyphUse& subset,
75 SkScalar* defaultAdvance) {
76 // There are two ways of expressing advances
78 // range: " gfid [adv.ances adv.ances ... adv.ances]"
79 // run: " gfid gfid adv.ances"
81 // Assuming that on average
82 // the ASCII representation of an advance plus a space is 10 characters
83 // the ASCII representation of a glyph id plus a space is 4 characters
84 // the ASCII representation of unused gid plus a space in a range is 2 characters
86 // When not in a range or run
87 // a. Skipping don't cares or defaults is a win (trivial)
88 // b. Run wins for 2+ repeats " gid gid adv.ances"
89 // " gid [adv.ances adv.ances]"
90 // rule: 2+ repeats create run as long as possible, else start range
93 // Cost of stopping and starting a range is 8 characters "] gid ["
94 // c. Skipping defaults is always a win " adv.ances"
95 // rule: end range if default seen
96 // d. Skipping 4+ don't cares is a win " 0 0 0 0"
97 // rule: end range if 4+ don't cares
98 // Cost of stop and start range plus run is 28 characters "] gid gid adv.ances gid ["
99 // e. Switching for 2+ repeats and 4+ don't cares wins " 0 0 adv.ances 0 0 adv.ances"
100 // rule: end range for 2+ repeats with 4+ don't cares
101 // f. Switching for 3+ repeats wins " adv.ances adv.ances adv.ances"
102 // rule: end range for 3+ repeats
105 SkStrikeSpec strikeSpec = SkStrikeSpec::MakePDFVector(typeface, &emSize);
106 SkBulkGlyphMetricsAndPaths paths{strikeSpec};
108 auto result = SkPDFMakeArray();
110 std::vector<SkGlyphID> glyphIDs;
111 subset.getSetValues([&](unsigned index) {
112 glyphIDs.push_back(SkToU16(index));
114 auto glyphs = paths.glyphs(SkMakeSpan(glyphIDs));
116 #if defined(SK_PDF_CAN_USE_DW)
117 std::vector<int16_t> advances;
118 advances.reserve_back(glyphs.size());
119 for (const SkGlyph* glyph : glyphs) {
120 advances.push_back((int16_t)glyph->advanceX());
122 std::sort(advances.begin(), advances.end());
123 int16_t modeAdvance = findMode(SkMakeSpan(advances));
124 *defaultAdvance = scale_from_font_units(modeAdvance, emSize);
129 for (size_t i = 0; i < glyphs.size(); ++i) {
130 int16_t advance = (int16_t)glyphs[i]->advanceX();
132 #if defined(SK_PDF_CAN_USE_DW)
133 // a. Skipping don't cares or defaults is a win (trivial)
134 if (advance == modeAdvance) {
139 // b. 2+ repeats create run as long as possible, else start range
141 size_t j = i + 1; // j is always one past the last known repeat
142 for (; j < glyphs.size(); ++j) {
143 int16_t next_advance = (int16_t)glyphs[j]->advanceX();
144 if (advance != next_advance) {
149 result->appendInt(glyphs[i]->getGlyphID());
150 result->appendInt(glyphs[j - 1]->getGlyphID());
151 result->appendScalar(scale_from_font_units(advance, emSize));
158 result->appendInt(glyphs[i]->getGlyphID());
159 auto advanceArray = SkPDFMakeArray();
160 advanceArray->appendScalar(scale_from_font_units(advance, emSize));
161 size_t j = i + 1; // j is always one past the last output
162 for (; j < glyphs.size(); ++j) {
163 advance = (int16_t)glyphs[j]->advanceX();
164 #if defined(SK_PDF_CAN_USE_DW)
165 // c. end range if default seen
166 if (advance == modeAdvance) {
171 int dontCares = glyphs[j]->getGlyphID() - glyphs[j - 1]->getGlyphID() - 1;
172 // d. end range if 4+ don't cares
173 if (dontCares >= 4) {
177 int16_t next_advance = 0;
178 // e. end range for 2+ repeats with 4+ don't cares
179 if (j + 1 < glyphs.size()) {
180 next_advance = (int16_t)glyphs[j+1]->advanceX();
181 int next_dontCares = glyphs[j+1]->getGlyphID() - glyphs[j]->getGlyphID() - 1;
182 if (advance == next_advance && dontCares + next_dontCares >= 4) {
187 // f. end range for 3+ repeats
188 if (j + 2 < glyphs.size() && advance == next_advance) {
189 next_advance = (int16_t)glyphs[j+2]->advanceX();
190 if (advance == next_advance) {
195 while (dontCares --> 0) {
196 advanceArray->appendScalar(0);
198 advanceArray->appendScalar(scale_from_font_units(advance, emSize));
200 result->appendObject(std::move(advanceArray));