1 /*
2 * Copyright 2018 The Android Open Source Project
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/core/SkGlyphRun.h"
9
10 #include "include/core/SkFont.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkTextBlob.h"
13 #include "include/private/SkTo.h"
14 #include "src/core/SkDevice.h"
15 #include "src/core/SkFontPriv.h"
16 #include "src/core/SkStrike.h"
17 #include "src/core/SkStrikeCache.h"
18 #include "src/core/SkStrikeSpec.h"
19 #include "src/core/SkTextBlobPriv.h"
20 #include "src/core/SkUtils.h"
21
22 // -- SkGlyphRun -----------------------------------------------------------------------------------
SkGlyphRun(const SkFont & font,SkSpan<const SkPoint> positions,SkSpan<const SkGlyphID> glyphIDs,SkSpan<const char> text,SkSpan<const uint32_t> clusters)23 SkGlyphRun::SkGlyphRun(const SkFont& font,
24 SkSpan<const SkPoint> positions,
25 SkSpan<const SkGlyphID> glyphIDs,
26 SkSpan<const char> text,
27 SkSpan<const uint32_t> clusters)
28 : fPositions{positions}
29 , fGlyphIDs{glyphIDs}
30 , fText{text}
31 , fClusters{clusters}
32 , fFont{font} {}
33
SkGlyphRun(const SkGlyphRun & that,const SkFont & font)34 SkGlyphRun::SkGlyphRun(const SkGlyphRun& that, const SkFont& font)
35 : fPositions{that.fPositions}
36 , fGlyphIDs{that.fGlyphIDs}
37 , fText{that.fText}
38 , fClusters{that.fClusters}
39 , fFont{font} {}
40
filloutGlyphsAndPositions(SkGlyphID * glyphIDs,SkPoint * positions)41 void SkGlyphRun::filloutGlyphsAndPositions(SkGlyphID* glyphIDs, SkPoint* positions) {
42 memcpy(glyphIDs, fGlyphIDs.data(), fGlyphIDs.size_bytes());
43 memcpy(positions, fPositions.data(), fPositions.size_bytes());
44 }
45
46 // -- SkGlyphRunList -------------------------------------------------------------------------------
47 SkGlyphRunList::SkGlyphRunList() = default;
SkGlyphRunList(const SkPaint & paint,const SkTextBlob * blob,SkPoint origin,SkSpan<const SkGlyphRun> glyphRunList)48 SkGlyphRunList::SkGlyphRunList(
49 const SkPaint& paint,
50 const SkTextBlob* blob,
51 SkPoint origin,
52 SkSpan<const SkGlyphRun> glyphRunList)
53 : fOriginalPaint{&paint}
54 , fOriginalTextBlob{blob}
55 , fOrigin{origin}
56 , fGlyphRuns{glyphRunList} { }
57
SkGlyphRunList(const SkGlyphRun & glyphRun,const SkPaint & paint)58 SkGlyphRunList::SkGlyphRunList(const SkGlyphRun& glyphRun, const SkPaint& paint)
59 : fOriginalPaint{&paint}
60 , fOriginalTextBlob{nullptr}
61 , fOrigin{SkPoint::Make(0, 0)}
62 , fGlyphRuns{SkSpan<const SkGlyphRun>{&glyphRun, 1}} {}
63
uniqueID() const64 uint64_t SkGlyphRunList::uniqueID() const {
65 return fOriginalTextBlob != nullptr ? fOriginalTextBlob->uniqueID()
66 : SK_InvalidUniqueID;
67 }
68
anyRunsLCD() const69 bool SkGlyphRunList::anyRunsLCD() const {
70 for (const auto& r : fGlyphRuns) {
71 if (r.font().getEdging() == SkFont::Edging::kSubpixelAntiAlias) {
72 return true;
73 }
74 }
75 return false;
76 }
77
anyRunsSubpixelPositioned() const78 bool SkGlyphRunList::anyRunsSubpixelPositioned() const {
79 for (const auto& r : fGlyphRuns) {
80 if (r.font().isSubpixel()) {
81 return true;
82 }
83 }
84 return false;
85 }
86
allFontsFinite() const87 bool SkGlyphRunList::allFontsFinite() const {
88 for (const auto& r : fGlyphRuns) {
89 if (!SkFontPriv::IsFinite(r.font())) {
90 return false;
91 }
92 }
93 return true;
94 }
95
temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const96 void SkGlyphRunList::temporaryShuntBlobNotifyAddedToCache(uint32_t cacheID) const {
97 SkASSERT(fOriginalTextBlob != nullptr);
98 fOriginalTextBlob->notifyAddedToCache(cacheID);
99 }
100
101 // -- SkGlyphIDSet ---------------------------------------------------------------------------------
102 // A faster set implementation that does not need any initialization, and reading the set items
103 // is order the number of items, and not the size of the universe.
104 // This implementation is based on the paper by Briggs and Torczon, "An Efficient Representation
105 // for Sparse Sets"
106 //
107 // This implementation assumes that the unique glyphs added are appended to a vector that may
108 // already have unique glyph from a previous computation. This allows the packing of multiple
109 // UniqueID sequences in a single vector.
uniquifyGlyphIDs(uint32_t universeSize,SkSpan<const SkGlyphID> glyphIDs,SkGlyphID * uniqueGlyphIDs,uint16_t * denseIndices)110 SkSpan<const SkGlyphID> SkGlyphIDSet::uniquifyGlyphIDs(
111 uint32_t universeSize,
112 SkSpan<const SkGlyphID> glyphIDs,
113 SkGlyphID* uniqueGlyphIDs,
114 uint16_t* denseIndices) {
115 static constexpr SkGlyphID kUndefGlyph{0};
116
117 if (universeSize > fUniverseToUniqueSize) {
118 fUniverseToUnique.reset(universeSize);
119 fUniverseToUniqueSize = universeSize;
120 // If the following bzero becomes a performance problem, the memory can be marked as
121 // initialized for valgrind and msan.
122 // valgrind = VALGRIND_MAKE_MEM_DEFINED(fUniverseToUnique, universeSize * sizeof(SkGlyphID))
123 // msan = sk_msan_mark_initialized(fUniverseToUnique, universeSize * sizeof(SkGlyphID))
124 sk_bzero(fUniverseToUnique, universeSize * sizeof(SkGlyphID));
125 }
126
127 // No need to clear fUniverseToUnique here... the set insertion algorithm is designed to work
128 // correctly even when the fUniverseToUnique buffer is uninitialized!
129
130 size_t uniqueSize = 0;
131 size_t denseIndicesCursor = 0;
132 for (auto glyphID : glyphIDs) {
133
134 // If the glyphID is not in range then it is the undefined glyph.
135 if (glyphID >= universeSize) {
136 glyphID = kUndefGlyph;
137 }
138
139 // The index into the unique ID vector.
140 auto uniqueIndex = fUniverseToUnique[glyphID];
141
142 if (uniqueIndex >= uniqueSize || uniqueGlyphIDs[uniqueIndex] != glyphID) {
143 uniqueIndex = SkTo<uint16_t>(uniqueSize);
144 uniqueGlyphIDs[uniqueSize] = glyphID;
145 fUniverseToUnique[glyphID] = uniqueIndex;
146 uniqueSize += 1;
147 }
148
149 denseIndices[denseIndicesCursor++] = uniqueIndex;
150 }
151
152 // If we're hanging onto these arrays for a long time, we don't want their size to drift
153 // endlessly upwards. It's unusual to see a typeface with more than 4096 possible glyphs.
154 if (fUniverseToUniqueSize > 4096) {
155 fUniverseToUnique.reset(4096);
156 sk_bzero(fUniverseToUnique, 4096 * sizeof(SkGlyphID));
157 fUniverseToUniqueSize = 4096;
158 }
159
160 return SkSpan<const SkGlyphID>(uniqueGlyphIDs, uniqueSize);
161 }
162
163 // -- SkGlyphRunBuilder ----------------------------------------------------------------------------
drawTextUTF8(const SkPaint & paint,const SkFont & font,const void * bytes,size_t byteLength,SkPoint origin)164 void SkGlyphRunBuilder::drawTextUTF8(const SkPaint& paint, const SkFont& font, const void* bytes,
165 size_t byteLength, SkPoint origin) {
166 auto glyphIDs = textToGlyphIDs(font, bytes, byteLength, SkTextEncoding::kUTF8);
167 if (!glyphIDs.empty()) {
168 this->initialize(glyphIDs.size());
169 this->simplifyDrawText(font, glyphIDs, origin, fPositions);
170 }
171
172 this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0));
173 }
174
drawTextBlob(const SkPaint & paint,const SkTextBlob & blob,SkPoint origin,SkBaseDevice * device)175 void SkGlyphRunBuilder::drawTextBlob(const SkPaint& paint, const SkTextBlob& blob, SkPoint origin,
176 SkBaseDevice* device) {
177 // Figure out all the storage needed to pre-size everything below.
178 size_t totalGlyphs = 0;
179 for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) {
180 totalGlyphs += it.glyphCount();
181 }
182
183 // Pre-size all the buffers so they don't move during processing.
184 this->initialize(totalGlyphs);
185
186 SkPoint* positions = fPositions;
187
188 for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) {
189 if (it.positioning() != SkTextBlobRunIterator::kRSXform_Positioning) {
190 simplifyTextBlobIgnoringRSXForm(it, positions);
191 } else {
192 // Handle kRSXform_Positioning
193 if (!this->empty()) {
194 this->makeGlyphRunList(paint, &blob, origin);
195 device->drawGlyphRunList(this->useGlyphRunList());
196 }
197
198 device->drawGlyphRunRSXform(it.font(), it.glyphs(), (const SkRSXform*)it.pos(),
199 it.glyphCount(), origin, paint);
200
201 // re-init in case we keep looping and need the builder again
202 this->initialize(totalGlyphs);
203 }
204 positions += it.glyphCount();
205 }
206
207 if (!this->empty()) {
208 this->makeGlyphRunList(paint, &blob, origin);
209 device->drawGlyphRunList(this->useGlyphRunList());
210 }
211 }
212
textBlobToGlyphRunListIgnoringRSXForm(const SkPaint & paint,const SkTextBlob & blob,SkPoint origin)213 void SkGlyphRunBuilder::textBlobToGlyphRunListIgnoringRSXForm(
214 const SkPaint& paint, const SkTextBlob& blob, SkPoint origin) {
215 // Figure out all the storage needed to pre-size everything below.
216 size_t totalGlyphs = 0;
217 for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) {
218 totalGlyphs += it.glyphCount();
219 }
220
221 // Pre-size all the buffers so they don't move during processing.
222 this->initialize(totalGlyphs);
223
224 SkPoint* positions = fPositions;
225
226 for (SkTextBlobRunIterator it(&blob); !it.done(); it.next()) {
227 simplifyTextBlobIgnoringRSXForm(it, positions);
228 positions += it.glyphCount();
229 }
230
231 if (!this->empty()) {
232 this->makeGlyphRunList(paint, &blob, origin);
233 }
234 }
235
simplifyTextBlobIgnoringRSXForm(const SkTextBlobRunIterator & it,SkPoint * positions)236 void SkGlyphRunBuilder::simplifyTextBlobIgnoringRSXForm(const SkTextBlobRunIterator& it,
237 SkPoint* positions) {
238 size_t runSize = it.glyphCount();
239
240 auto text = SkSpan<const char>(it.text(), it.textSize());
241 auto clusters = SkSpan<const uint32_t>(it.clusters(), runSize);
242 const SkPoint& offset = it.offset();
243 auto glyphIDs = SkSpan<const SkGlyphID>{it.glyphs(), runSize};
244
245 switch (it.positioning()) {
246 case SkTextBlobRunIterator::kDefault_Positioning: {
247 this->simplifyDrawText(
248 it.font(), glyphIDs, offset, positions, text, clusters);
249 break;
250 }
251 case SkTextBlobRunIterator::kHorizontal_Positioning: {
252 auto constY = offset.y();
253 this->simplifyDrawPosTextH(
254 it.font(), glyphIDs, it.pos(), constY, positions, text, clusters);
255 break;
256 }
257 case SkTextBlobRunIterator::kFull_Positioning: {
258 this->simplifyDrawPosText(
259 it.font(), glyphIDs, (const SkPoint*) it.pos(), text, clusters);
260 break;
261 }
262 case SkTextBlobRunIterator::kRSXform_Positioning: break;
263 }
264 }
265
drawGlyphsWithPositions(const SkPaint & paint,const SkFont & font,SkSpan<const SkGlyphID> glyphIDs,const SkPoint * pos)266 void SkGlyphRunBuilder::drawGlyphsWithPositions(const SkPaint& paint, const SkFont& font,
267 SkSpan<const SkGlyphID> glyphIDs, const SkPoint* pos) {
268 if (!glyphIDs.empty()) {
269 this->initialize(glyphIDs.size());
270 this->simplifyDrawPosText(font, glyphIDs, pos);
271 this->makeGlyphRunList(paint, nullptr, SkPoint::Make(0, 0));
272 }
273 }
274
useGlyphRunList()275 const SkGlyphRunList& SkGlyphRunBuilder::useGlyphRunList() {
276 return fGlyphRunList;
277 }
278
initialize(size_t totalRunSize)279 void SkGlyphRunBuilder::initialize(size_t totalRunSize) {
280
281 if (totalRunSize > fMaxTotalRunSize) {
282 fMaxTotalRunSize = totalRunSize;
283 fPositions.reset(fMaxTotalRunSize);
284 }
285
286 fGlyphRunListStorage.clear();
287 }
288
textToGlyphIDs(const SkFont & font,const void * bytes,size_t byteLength,SkTextEncoding encoding)289 SkSpan<const SkGlyphID> SkGlyphRunBuilder::textToGlyphIDs(
290 const SkFont& font, const void* bytes, size_t byteLength, SkTextEncoding encoding) {
291 if (encoding != SkTextEncoding::kGlyphID) {
292 int count = font.countText(bytes, byteLength, encoding);
293 if (count > 0) {
294 fScratchGlyphIDs.resize(count);
295 font.textToGlyphs(bytes, byteLength, encoding, fScratchGlyphIDs.data(), count);
296 return SkMakeSpan(fScratchGlyphIDs);
297 } else {
298 return SkSpan<const SkGlyphID>();
299 }
300 } else {
301 return SkSpan<const SkGlyphID>((const SkGlyphID*)bytes, byteLength / 2);
302 }
303 }
304
makeGlyphRun(const SkFont & font,SkSpan<const SkGlyphID> glyphIDs,SkSpan<const SkPoint> positions,SkSpan<const char> text,SkSpan<const uint32_t> clusters)305 void SkGlyphRunBuilder::makeGlyphRun(
306 const SkFont& font,
307 SkSpan<const SkGlyphID> glyphIDs,
308 SkSpan<const SkPoint> positions,
309 SkSpan<const char> text,
310 SkSpan<const uint32_t> clusters) {
311
312 // Ignore empty runs.
313 if (!glyphIDs.empty()) {
314 fGlyphRunListStorage.emplace_back(
315 font,
316 positions,
317 glyphIDs,
318 text,
319 clusters);
320 }
321 }
322
makeGlyphRunList(const SkPaint & paint,const SkTextBlob * blob,SkPoint origin)323 void SkGlyphRunBuilder::makeGlyphRunList(
324 const SkPaint& paint, const SkTextBlob* blob, SkPoint origin) {
325
326 fGlyphRunList.~SkGlyphRunList();
327 new (&fGlyphRunList) SkGlyphRunList{
328 paint, blob, origin, SkMakeSpan(fGlyphRunListStorage)};
329 }
330
simplifyDrawText(const SkFont & font,SkSpan<const SkGlyphID> glyphIDs,SkPoint origin,SkPoint * positions,SkSpan<const char> text,SkSpan<const uint32_t> clusters)331 void SkGlyphRunBuilder::simplifyDrawText(
332 const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
333 SkPoint origin, SkPoint* positions,
334 SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
335 SkASSERT(!glyphIDs.empty());
336
337 auto runSize = glyphIDs.size();
338
339 if (!glyphIDs.empty()) {
340 SkStrikeSpec strikeSpec = SkStrikeSpec::MakeWithNoDevice(font);
341 SkBulkGlyphMetrics storage{strikeSpec};
342 auto glyphs = storage.glyphs(glyphIDs);
343
344 SkPoint endOfLastGlyph = origin;
345 SkPoint* cursor = positions;
346 for (auto glyph : glyphs) {
347 *cursor++ = endOfLastGlyph;
348 endOfLastGlyph += glyph->advanceVector();
349 }
350
351 this->makeGlyphRun(
352 font,
353 glyphIDs,
354 SkSpan<const SkPoint>{positions, runSize},
355 text,
356 clusters);
357 }
358 }
359
simplifyDrawPosTextH(const SkFont & font,SkSpan<const SkGlyphID> glyphIDs,const SkScalar * xpos,SkScalar constY,SkPoint * positions,SkSpan<const char> text,SkSpan<const uint32_t> clusters)360 void SkGlyphRunBuilder::simplifyDrawPosTextH(
361 const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
362 const SkScalar* xpos, SkScalar constY, SkPoint* positions,
363 SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
364
365 auto posCursor = positions;
366 for (auto x : SkSpan<const SkScalar>{xpos, glyphIDs.size()}) {
367 *posCursor++ = SkPoint::Make(x, constY);
368 }
369
370 simplifyDrawPosText(font, glyphIDs, positions, text, clusters);
371 }
372
simplifyDrawPosText(const SkFont & font,SkSpan<const SkGlyphID> glyphIDs,const SkPoint * pos,SkSpan<const char> text,SkSpan<const uint32_t> clusters)373 void SkGlyphRunBuilder::simplifyDrawPosText(
374 const SkFont& font, SkSpan<const SkGlyphID> glyphIDs,
375 const SkPoint* pos,
376 SkSpan<const char> text, SkSpan<const uint32_t> clusters) {
377 auto runSize = glyphIDs.size();
378
379 this->makeGlyphRun(
380 font,
381 glyphIDs,
382 SkSpan<const SkPoint>{pos, runSize},
383 text,
384 clusters);
385 }
386