xref: /aosp_15_r20/external/skia/src/pdf/SkPDFMakeCIDGlyphWidthsArray.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/pdf/SkPDFMakeCIDGlyphWidthsArray.h"
9 
10 #include "include/core/SkScalar.h"
11 #include "include/core/SkSpan.h"
12 #include "include/core/SkTypes.h"
13 #include "include/private/base/SkTo.h"
14 #include "src/core/SkGlyph.h"
15 #include "src/core/SkStrikeSpec.h"
16 #include "src/pdf/SkPDFFont.h"
17 #include "src/pdf/SkPDFGlyphUse.h"
18 #include "src/pdf/SkPDFTypes.h"
19 
20 #include <algorithm>
21 #include <cstddef>
22 #include <utility>
23 #include <vector>
24 
25 namespace {
26 
27 // Scale from em-units to 1000-units.
from_font_units(SkScalar scaled,uint16_t emSize)28 SkScalar from_font_units(SkScalar scaled, uint16_t emSize) {
29     if (emSize == 1000) {
30         return scaled;
31     } else {
32         return scaled * 1000 / emSize;
33     }
34 }
35 
find_mode_or_0(SkSpan<const SkScalar> advances)36 SkScalar find_mode_or_0(SkSpan<const SkScalar> advances) {
37     if (advances.empty()) {
38         return 0;
39     }
40 
41     SkScalar currentAdvance = advances[0];
42     SkScalar currentModeAdvance = advances[0];
43     size_t currentCount = 1;
44     size_t currentModeCount = 1;
45 
46     for (size_t i = 1; i < advances.size(); ++i) {
47         if (advances[i] == currentAdvance) {
48             ++currentCount;
49         } else {
50             if (currentCount > currentModeCount) {
51                 currentModeAdvance = currentAdvance;
52                 currentModeCount = currentCount;
53             }
54             currentAdvance = advances[i];
55             currentCount = 1;
56         }
57     }
58     return currentCount > currentModeCount ? currentAdvance : currentModeAdvance;
59 }
60 
61 } // namespace
62 
SkPDFMakeCIDGlyphWidthsArray(const SkPDFStrikeSpec & pdfStrikeSpec,const SkPDFGlyphUse & subset,int32_t * defaultAdvance)63 std::unique_ptr<SkPDFArray> SkPDFMakeCIDGlyphWidthsArray(const SkPDFStrikeSpec& pdfStrikeSpec,
64                                                          const SkPDFGlyphUse& subset,
65                                                          int32_t* defaultAdvance) {
66     // There are two ways of expressing advances
67     //
68     // range: " gfid [adv.ances adv.ances ... adv.ances]"
69     //   run: " gfid gfid adv.ances"
70     //
71     // Assuming that on average
72     // the ASCII representation of an advance plus a space is 10 characters
73     // the ASCII representation of a glyph id plus a space is 4 characters
74     // the ASCII representation of unused gid plus a space in a range is 2 characters
75     //
76     // When not in a range or run
77     //  a. Skipping don't cares or defaults is a win (trivial)
78     //  b. Run wins for 2+ repeats " gid gid adv.ances"
79     //                             " gid [adv.ances adv.ances]"
80     //     rule: 2+ repeats create run as long as possible, else start range
81     //
82     // When in a range
83     // Cost of stopping and starting a range is 8 characters  "] gid ["
84     //  c. Skipping defaults is always a win                  " adv.ances"
85     //     rule: end range if default seen
86     //  d. Skipping 4+ don't cares is a win                   " 0 0 0 0"
87     //     rule: end range if 4+ don't cares
88     // Cost of stop and start range plus run is 28 characters "] gid gid adv.ances gid ["
89     //  e. Switching for 2+ repeats and 4+ don't cares wins   " 0 0 adv.ances 0 0 adv.ances"
90     //     rule: end range for 2+ repeats with 4+ don't cares
91     //  f. Switching for 3+ repeats wins                      " adv.ances adv.ances adv.ances"
92     //     rule: end range for 3+ repeats
93 
94     int emSize = pdfStrikeSpec.fUnitsPerEM;
95     SkBulkGlyphMetricsAndPaths paths{pdfStrikeSpec.fStrikeSpec};
96 
97     auto result = SkPDFMakeArray();
98 
99     std::vector<SkGlyphID> glyphIDs;
100     subset.getSetValues([&](unsigned index) {
101         glyphIDs.push_back(SkToU16(index));
102     });
103     auto glyphs = paths.glyphs(SkSpan(glyphIDs));
104 
105     // C++20 = make_unique_for_overwrite<SkScalar[]>(glyphs.size());
106     auto advances = std::unique_ptr<SkScalar[]>(new SkScalar[glyphs.size()]);
107 
108     // Find the pdf integer mode (most common pdf integer advance).
109     // Unfortunately, poppler enforces DW (default width) must be an integer,
110     // so only consider integer pdf advances when finding the mode.
111     size_t numIntAdvances = 0;
112     for (const SkGlyph* glyph : glyphs) {
113         SkScalar currentAdvance = from_font_units(glyph->advanceX(), emSize);
114         if ((int32_t)currentAdvance == currentAdvance) {
115             advances[numIntAdvances++] = currentAdvance;
116         }
117     }
118     std::sort(advances.get(), advances.get() + numIntAdvances);
119     int32_t modeAdvance = (int32_t)find_mode_or_0(SkSpan(advances.get(), numIntAdvances));
120     *defaultAdvance = modeAdvance;
121 
122     // Pre-convert to pdf advances.
123     for (size_t i = 0; i < glyphs.size(); ++i) {
124         advances[i] = from_font_units(glyphs[i]->advanceX(), emSize);
125     }
126 
127     for (size_t i = 0; i < glyphs.size(); ++i) {
128         SkScalar advance = advances[i];
129 
130         // a. Skipping don't cares or defaults is a win (trivial)
131         if (advance == modeAdvance) {
132             continue;
133         }
134 
135         // b. 2+ repeats create run as long as possible, else start range
136         {
137             size_t j = i + 1; // j is always one past the last known repeat
138             for (; j < glyphs.size(); ++j) {
139                 SkScalar next_advance = advances[j];
140                 if (advance != next_advance) {
141                     break;
142                 }
143             }
144             if (j - i >= 2) {
145                 result->appendInt(glyphs[i]->getGlyphID());
146                 result->appendInt(glyphs[j - 1]->getGlyphID());
147                 result->appendScalar(advance);
148                 i = j - 1;
149                 continue;
150             }
151         }
152 
153         {
154             result->appendInt(glyphs[i]->getGlyphID());
155             auto advanceArray = SkPDFMakeArray();
156             advanceArray->appendScalar(advance);
157             size_t j = i + 1; // j is always one past the last output
158             for (; j < glyphs.size(); ++j) {
159                 advance = advances[j];
160 
161                 // c. end range if default seen
162                 if (advance == modeAdvance) {
163                     break;
164                 }
165 
166                 int dontCares = glyphs[j]->getGlyphID() - glyphs[j - 1]->getGlyphID() - 1;
167                 // d. end range if 4+ don't cares
168                 if (dontCares >= 4) {
169                     break;
170                 }
171 
172                 SkScalar next_advance = 0;
173                 // e. end range for 2+ repeats with 4+ don't cares
174                 if (j + 1 < glyphs.size()) {
175                     next_advance = advances[j+1];
176                     int next_dontCares = glyphs[j+1]->getGlyphID() - glyphs[j]->getGlyphID() - 1;
177                     if (advance == next_advance && dontCares + next_dontCares >= 4) {
178                         break;
179                     }
180                 }
181 
182                 // f. end range for 3+ repeats
183                 if (j + 2 < glyphs.size() && advance == next_advance) {
184                     next_advance = advances[j+2];
185                     if (advance == next_advance) {
186                         break;
187                     }
188                 }
189 
190                 while (dontCares --> 0) {
191                     advanceArray->appendScalar(0);
192                 }
193                 advanceArray->appendScalar(advance);
194             }
195             result->appendObject(std::move(advanceArray));
196             i = j - 1;
197         }
198     }
199 
200     return result;
201 }
202