• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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