Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Functions
SkPDFMakeCIDGlyphWidthsArray.cpp File Reference
#include "src/pdf/SkPDFMakeCIDGlyphWidthsArray.h"
#include "include/core/SkPaint.h"
#include "include/private/base/SkTo.h"
#include "src/core/SkStrike.h"
#include "src/core/SkStrikeSpec.h"
#include "src/pdf/SkPDFGlyphUse.h"
#include <algorithm>
#include <vector>

Go to the source code of this file.

Functions

std::unique_ptr< SkPDFArraySkPDFMakeCIDGlyphWidthsArray (const SkTypeface &typeface, const SkPDFGlyphUse &subset, int32_t *defaultAdvance)
 

Function Documentation

◆ SkPDFMakeCIDGlyphWidthsArray()

std::unique_ptr< SkPDFArray > SkPDFMakeCIDGlyphWidthsArray ( const SkTypeface typeface,
const SkPDFGlyphUse subset,
int32_t *  defaultAdvance 
)

Definition at line 57 of file SkPDFMakeCIDGlyphWidthsArray.cpp.

59 {
60 // There are two ways of expressing advances
61 //
62 // range: " gfid [adv.ances adv.ances ... adv.ances]"
63 // run: " gfid gfid adv.ances"
64 //
65 // Assuming that on average
66 // the ASCII representation of an advance plus a space is 10 characters
67 // the ASCII representation of a glyph id plus a space is 4 characters
68 // the ASCII representation of unused gid plus a space in a range is 2 characters
69 //
70 // When not in a range or run
71 // a. Skipping don't cares or defaults is a win (trivial)
72 // b. Run wins for 2+ repeats " gid gid adv.ances"
73 // " gid [adv.ances adv.ances]"
74 // rule: 2+ repeats create run as long as possible, else start range
75 //
76 // When in a range
77 // Cost of stopping and starting a range is 8 characters "] gid ["
78 // c. Skipping defaults is always a win " adv.ances"
79 // rule: end range if default seen
80 // d. Skipping 4+ don't cares is a win " 0 0 0 0"
81 // rule: end range if 4+ don't cares
82 // Cost of stop and start range plus run is 28 characters "] gid gid adv.ances gid ["
83 // e. Switching for 2+ repeats and 4+ don't cares wins " 0 0 adv.ances 0 0 adv.ances"
84 // rule: end range for 2+ repeats with 4+ don't cares
85 // f. Switching for 3+ repeats wins " adv.ances adv.ances adv.ances"
86 // rule: end range for 3+ repeats
87
88 int emSize;
89 SkStrikeSpec strikeSpec = SkStrikeSpec::MakePDFVector(typeface, &emSize);
90 SkBulkGlyphMetricsAndPaths paths{strikeSpec};
91
92 auto result = SkPDFMakeArray();
93
94 std::vector<SkGlyphID> glyphIDs;
95 subset.getSetValues([&](unsigned index) {
96 glyphIDs.push_back(SkToU16(index));
97 });
98 auto glyphs = paths.glyphs(SkSpan(glyphIDs));
99
100 // C++20 = make_unique_for_overwrite<SkScalar[]>(glyphs.size());
101 auto advances = std::unique_ptr<SkScalar[]>(new SkScalar[glyphs.size()]);
102
103 // Find the pdf integer mode (most common pdf integer advance).
104 // Unfortunately, poppler enforces DW (default width) must be an integer,
105 // so only consider integer pdf advances when finding the mode.
106 size_t numIntAdvances = 0;
107 for (const SkGlyph* glyph : glyphs) {
108 SkScalar currentAdvance = from_font_units(glyph->advanceX(), emSize);
109 if ((int32_t)currentAdvance == currentAdvance) {
110 advances[numIntAdvances++] = currentAdvance;
111 }
112 }
113 std::sort(advances.get(), advances.get() + numIntAdvances);
114 int32_t modeAdvance = (int32_t)find_mode_or_0(SkSpan(advances.get(), numIntAdvances));
115 *defaultAdvance = modeAdvance;
116
117 // Pre-convert to pdf advances.
118 for (size_t i = 0; i < glyphs.size(); ++i) {
119 advances[i] = from_font_units(glyphs[i]->advanceX(), emSize);
120 }
121
122 for (size_t i = 0; i < glyphs.size(); ++i) {
123 SkScalar advance = advances[i];
124
125 // a. Skipping don't cares or defaults is a win (trivial)
126 if (advance == modeAdvance) {
127 continue;
128 }
129
130 // b. 2+ repeats create run as long as possible, else start range
131 {
132 size_t j = i + 1; // j is always one past the last known repeat
133 for (; j < glyphs.size(); ++j) {
134 SkScalar next_advance = advances[j];
135 if (advance != next_advance) {
136 break;
137 }
138 }
139 if (j - i >= 2) {
140 result->appendInt(glyphs[i]->getGlyphID());
141 result->appendInt(glyphs[j - 1]->getGlyphID());
142 result->appendScalar(advance);
143 i = j - 1;
144 continue;
145 }
146 }
147
148 {
149 result->appendInt(glyphs[i]->getGlyphID());
150 auto advanceArray = SkPDFMakeArray();
151 advanceArray->appendScalar(advance);
152 size_t j = i + 1; // j is always one past the last output
153 for (; j < glyphs.size(); ++j) {
154 advance = advances[j];
155
156 // c. end range if default seen
157 if (advance == modeAdvance) {
158 break;
159 }
160
161 int dontCares = glyphs[j]->getGlyphID() - glyphs[j - 1]->getGlyphID() - 1;
162 // d. end range if 4+ don't cares
163 if (dontCares >= 4) {
164 break;
165 }
166
167 SkScalar next_advance = 0;
168 // e. end range for 2+ repeats with 4+ don't cares
169 if (j + 1 < glyphs.size()) {
170 next_advance = advances[j+1];
171 int next_dontCares = glyphs[j+1]->getGlyphID() - glyphs[j]->getGlyphID() - 1;
172 if (advance == next_advance && dontCares + next_dontCares >= 4) {
173 break;
174 }
175 }
176
177 // f. end range for 3+ repeats
178 if (j + 2 < glyphs.size() && advance == next_advance) {
179 next_advance = advances[j+2];
180 if (advance == next_advance) {
181 break;
182 }
183 }
184
185 while (dontCares --> 0) {
186 advanceArray->appendScalar(0);
187 }
188 advanceArray->appendScalar(advance);
189 }
190 result->appendObject(std::move(advanceArray));
191 i = j - 1;
192 }
193 }
194
195 return result;
196}
uint16_t glyphs[5]
static SkScalar from_font_units(SkScalar scaled, uint16_t emSize)
static std::unique_ptr< SkPDFArray > SkPDFMakeArray(Args... args)
Definition SkPDFTypes.h:135
constexpr uint16_t SkToU16(S x)
Definition SkTo.h:24
void getSetValues(FN f) const
static SkStrikeSpec MakePDFVector(const SkTypeface &typeface, int *size)
float SkScalar
Definition extension.cpp:12
GAsyncResult * result