xref: /aosp_15_r20/external/skia/modules/skshaper/src/SkShaper_harfbuzz.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 "modules/skshaper/include/SkShaper_harfbuzz.h"
9 
10 #include "include/core/SkData.h"
11 #include "include/core/SkFont.h"
12 #include "include/core/SkFontArguments.h"
13 #include "include/core/SkFontMetrics.h"
14 #include "include/core/SkFontMgr.h"
15 #include "include/core/SkFontTypes.h"
16 #include "include/core/SkPaint.h"
17 #include "include/core/SkPoint.h"
18 #include "include/core/SkRect.h"
19 #include "include/core/SkRefCnt.h"
20 #include "include/core/SkScalar.h"
21 #include "include/core/SkSpan.h"
22 #include "include/core/SkStream.h"
23 #include "include/core/SkString.h"
24 #include "include/core/SkTypeface.h"
25 #include "include/core/SkTypes.h"
26 #include "include/private/base/SkDebug.h"
27 #include "include/private/base/SkMalloc.h"
28 #include "include/private/base/SkMutex.h"
29 #include "include/private/base/SkTArray.h"
30 #include "include/private/base/SkTemplates.h"
31 #include "include/private/base/SkTo.h"
32 #include "include/private/base/SkTypeTraits.h"
33 #include "modules/skshaper/include/SkShaper.h"
34 #include "modules/skunicode/include/SkUnicode.h"
35 #include "src/base/SkTDPQueue.h"
36 #include "src/base/SkUTF.h"
37 #include "src/core/SkLRUCache.h"
38 
39 #if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
40 #include "modules/skshaper/include/SkShaper_skunicode.h"
41 #endif
42 
43 #include <hb-ot.h>
44 #include <hb.h>
45 
46 #include <cstdint>
47 #include <cstring>
48 #include <memory>
49 #include <type_traits>
50 #include <utility>
51 
52 using namespace skia_private;
53 
54 // HB_FEATURE_GLOBAL_START and HB_FEATURE_GLOBAL_END were not added until HarfBuzz 2.0
55 // They would have always worked, they just hadn't been named yet.
56 #if !defined(HB_FEATURE_GLOBAL_START)
57 #  define HB_FEATURE_GLOBAL_START 0
58 #endif
59 #if !defined(HB_FEATURE_GLOBAL_END)
60 # define HB_FEATURE_GLOBAL_END ((unsigned int) -1)
61 #endif
62 
63 namespace {
64 using HBBlob   = std::unique_ptr<hb_blob_t  , SkFunctionObject<hb_blob_destroy>  >;
65 using HBFace   = std::unique_ptr<hb_face_t  , SkFunctionObject<hb_face_destroy>  >;
66 using HBFont   = std::unique_ptr<hb_font_t  , SkFunctionObject<hb_font_destroy>  >;
67 using HBBuffer = std::unique_ptr<hb_buffer_t, SkFunctionObject<hb_buffer_destroy>>;
68 
69 using SkUnicodeBreak = std::unique_ptr<SkBreakIterator>;
70 
skhb_position(SkScalar value)71 hb_position_t skhb_position(SkScalar value) {
72     // Treat HarfBuzz hb_position_t as 16.16 fixed-point.
73     constexpr int kHbPosition1 = 1 << 16;
74     return SkScalarRoundToInt(value * kHbPosition1);
75 }
76 
skhb_glyph(hb_font_t * hb_font,void * font_data,hb_codepoint_t unicode,hb_codepoint_t variation_selector,hb_codepoint_t * glyph,void * user_data)77 hb_bool_t skhb_glyph(hb_font_t* hb_font,
78                      void* font_data,
79                      hb_codepoint_t unicode,
80                      hb_codepoint_t variation_selector,
81                      hb_codepoint_t* glyph,
82                      void* user_data) {
83     SkFont& font = *reinterpret_cast<SkFont*>(font_data);
84 
85     *glyph = font.unicharToGlyph(unicode);
86     return *glyph != 0;
87 }
88 
skhb_nominal_glyph(hb_font_t * hb_font,void * font_data,hb_codepoint_t unicode,hb_codepoint_t * glyph,void * user_data)89 hb_bool_t skhb_nominal_glyph(hb_font_t* hb_font,
90                              void* font_data,
91                              hb_codepoint_t unicode,
92                              hb_codepoint_t* glyph,
93                              void* user_data) {
94   return skhb_glyph(hb_font, font_data, unicode, 0, glyph, user_data);
95 }
96 
skhb_nominal_glyphs(hb_font_t * hb_font,void * font_data,unsigned int count,const hb_codepoint_t * unicodes,unsigned int unicode_stride,hb_codepoint_t * glyphs,unsigned int glyph_stride,void * user_data)97 unsigned skhb_nominal_glyphs(hb_font_t *hb_font, void *font_data,
98                              unsigned int count,
99                              const hb_codepoint_t *unicodes,
100                              unsigned int unicode_stride,
101                              hb_codepoint_t *glyphs,
102                              unsigned int glyph_stride,
103                              void *user_data) {
104     SkFont& font = *reinterpret_cast<SkFont*>(font_data);
105 
106     // Batch call textToGlyphs since entry cost is not cheap.
107     // Copy requred because textToGlyphs is dense and hb is strided.
108     AutoSTMalloc<256, SkUnichar> unicode(count);
109     for (unsigned i = 0; i < count; i++) {
110         unicode[i] = *unicodes;
111         unicodes = SkTAddOffset<const hb_codepoint_t>(unicodes, unicode_stride);
112     }
113     AutoSTMalloc<256, SkGlyphID> glyph(count);
114     font.textToGlyphs(unicode.get(), count * sizeof(SkUnichar), SkTextEncoding::kUTF32,
115                         glyph.get(), count);
116 
117     // Copy the results back to the sparse array.
118     unsigned int done;
119     for (done = 0; done < count && glyph[done] != 0; done++) {
120         *glyphs = glyph[done];
121         glyphs = SkTAddOffset<hb_codepoint_t>(glyphs, glyph_stride);
122     }
123     // return 'done' to allow HarfBuzz to synthesize with NFC and spaces, return 'count' to avoid
124     return done;
125 }
126 
skhb_glyph_h_advance(hb_font_t * hb_font,void * font_data,hb_codepoint_t hbGlyph,void * user_data)127 hb_position_t skhb_glyph_h_advance(hb_font_t* hb_font,
128                                    void* font_data,
129                                    hb_codepoint_t hbGlyph,
130                                    void* user_data) {
131     SkFont& font = *reinterpret_cast<SkFont*>(font_data);
132 
133     SkScalar advance;
134     SkGlyphID skGlyph = SkTo<SkGlyphID>(hbGlyph);
135 
136     font.getWidths(&skGlyph, 1, &advance);
137     if (!font.isSubpixel()) {
138         advance = SkScalarRoundToInt(advance);
139     }
140     return skhb_position(advance);
141 }
142 
skhb_glyph_h_advances(hb_font_t * hb_font,void * font_data,unsigned count,const hb_codepoint_t * glyphs,unsigned int glyph_stride,hb_position_t * advances,unsigned int advance_stride,void * user_data)143 void skhb_glyph_h_advances(hb_font_t* hb_font,
144                            void* font_data,
145                            unsigned count,
146                            const hb_codepoint_t* glyphs,
147                            unsigned int glyph_stride,
148                            hb_position_t* advances,
149                            unsigned int advance_stride,
150                            void* user_data) {
151     SkFont& font = *reinterpret_cast<SkFont*>(font_data);
152 
153     // Batch call getWidths since entry cost is not cheap.
154     // Copy requred because getWidths is dense and hb is strided.
155     AutoSTMalloc<256, SkGlyphID> glyph(count);
156     for (unsigned i = 0; i < count; i++) {
157         glyph[i] = *glyphs;
158         glyphs = SkTAddOffset<const hb_codepoint_t>(glyphs, glyph_stride);
159     }
160     AutoSTMalloc<256, SkScalar> advance(count);
161     font.getWidths(glyph.get(), count, advance.get());
162 
163     if (!font.isSubpixel()) {
164         for (unsigned i = 0; i < count; i++) {
165             advance[i] = SkScalarRoundToInt(advance[i]);
166         }
167     }
168 
169     // Copy the results back to the sparse array.
170     for (unsigned i = 0; i < count; i++) {
171         *advances = skhb_position(advance[i]);
172         advances = SkTAddOffset<hb_position_t>(advances, advance_stride);
173     }
174 }
175 
176 // HarfBuzz callback to retrieve glyph extents, mainly used by HarfBuzz for
177 // fallback mark positioning, i.e. the situation when the font does not have
178 // mark anchors or other mark positioning rules, but instead HarfBuzz is
179 // supposed to heuristically place combining marks around base glyphs. HarfBuzz
180 // does this by measuring "ink boxes" of glyphs, and placing them according to
181 // Unicode mark classes. Above, below, centered or left or right, etc.
skhb_glyph_extents(hb_font_t * hb_font,void * font_data,hb_codepoint_t hbGlyph,hb_glyph_extents_t * extents,void * user_data)182 hb_bool_t skhb_glyph_extents(hb_font_t* hb_font,
183                              void* font_data,
184                              hb_codepoint_t hbGlyph,
185                              hb_glyph_extents_t* extents,
186                              void* user_data) {
187     SkFont& font = *reinterpret_cast<SkFont*>(font_data);
188     SkASSERT(extents);
189 
190     SkRect sk_bounds;
191     SkGlyphID skGlyph = SkTo<SkGlyphID>(hbGlyph);
192 
193     font.getWidths(&skGlyph, 1, nullptr, &sk_bounds);
194     if (!font.isSubpixel()) {
195         sk_bounds.set(sk_bounds.roundOut());
196     }
197 
198     // Skia is y-down but HarfBuzz is y-up.
199     extents->x_bearing = skhb_position(sk_bounds.fLeft);
200     extents->y_bearing = skhb_position(-sk_bounds.fTop);
201     extents->width = skhb_position(sk_bounds.width());
202     extents->height = skhb_position(-sk_bounds.height());
203     return true;
204 }
205 
206 #define SK_HB_VERSION_CHECK(x, y, z) \
207     (HB_VERSION_MAJOR >  (x)) || \
208     (HB_VERSION_MAJOR == (x) && HB_VERSION_MINOR >  (y)) || \
209     (HB_VERSION_MAJOR == (x) && HB_VERSION_MINOR == (y) && HB_VERSION_MICRO >= (z))
210 
skhb_get_font_funcs()211 hb_font_funcs_t* skhb_get_font_funcs() {
212     static hb_font_funcs_t* const funcs = []{
213         // HarfBuzz will use the default (parent) implementation if they aren't set.
214         hb_font_funcs_t* const funcs = hb_font_funcs_create();
215         hb_font_funcs_set_variation_glyph_func(funcs, skhb_glyph, nullptr, nullptr);
216         hb_font_funcs_set_nominal_glyph_func(funcs, skhb_nominal_glyph, nullptr, nullptr);
217 #if SK_HB_VERSION_CHECK(2, 0, 0)
218         hb_font_funcs_set_nominal_glyphs_func(funcs, skhb_nominal_glyphs, nullptr, nullptr);
219 #else
220         sk_ignore_unused_variable(skhb_nominal_glyphs);
221 #endif
222         hb_font_funcs_set_glyph_h_advance_func(funcs, skhb_glyph_h_advance, nullptr, nullptr);
223 #if SK_HB_VERSION_CHECK(1, 8, 6)
224         hb_font_funcs_set_glyph_h_advances_func(funcs, skhb_glyph_h_advances, nullptr, nullptr);
225 #else
226         sk_ignore_unused_variable(skhb_glyph_h_advances);
227 #endif
228         hb_font_funcs_set_glyph_extents_func(funcs, skhb_glyph_extents, nullptr, nullptr);
229         hb_font_funcs_make_immutable(funcs);
230         return funcs;
231     }();
232     SkASSERT(funcs);
233     return funcs;
234 }
235 
skhb_get_table(hb_face_t * face,hb_tag_t tag,void * user_data)236 hb_blob_t* skhb_get_table(hb_face_t* face, hb_tag_t tag, void* user_data) {
237     SkTypeface& typeface = *reinterpret_cast<SkTypeface*>(user_data);
238 
239     auto data = typeface.copyTableData(tag);
240     if (!data) {
241         return nullptr;
242     }
243     SkData* rawData = data.release();
244     return hb_blob_create(reinterpret_cast<char*>(rawData->writable_data()), rawData->size(),
245                           HB_MEMORY_MODE_READONLY, rawData, [](void* ctx) {
246                               SkSafeUnref(((SkData*)ctx));
247                           });
248 }
249 
stream_to_blob(std::unique_ptr<SkStreamAsset> asset)250 HBBlob stream_to_blob(std::unique_ptr<SkStreamAsset> asset) {
251     size_t size = asset->getLength();
252     HBBlob blob;
253     if (const void* base = asset->getMemoryBase()) {
254         blob.reset(hb_blob_create((const char*)base, SkToUInt(size),
255                                   HB_MEMORY_MODE_READONLY, asset.release(),
256                                   [](void* p) { delete (SkStreamAsset*)p; }));
257     } else {
258         // SkDebugf("Extra SkStreamAsset copy\n");
259         void* ptr = size ? sk_malloc_throw(size) : nullptr;
260         asset->read(ptr, size);
261         blob.reset(hb_blob_create((char*)ptr, SkToUInt(size),
262                                   HB_MEMORY_MODE_READONLY, ptr, sk_free));
263     }
264     SkASSERT(blob);
265     hb_blob_make_immutable(blob.get());
266     return blob;
267 }
268 
SkDEBUGCODE(static hb_user_data_key_t gDataIdKey;)269 SkDEBUGCODE(static hb_user_data_key_t gDataIdKey;)
270 
271 HBFace create_hb_face(const SkTypeface& typeface) {
272     int index = 0;
273     std::unique_ptr<SkStreamAsset> typefaceAsset = typeface.openExistingStream(&index);
274     HBFace face;
275     if (typefaceAsset && typefaceAsset->getMemoryBase()) {
276         HBBlob blob(stream_to_blob(std::move(typefaceAsset)));
277         // hb_face_create always succeeds. Check that the format is minimally recognized first.
278         // hb_face_create_for_tables may still create a working hb_face.
279         // See https://github.com/harfbuzz/harfbuzz/issues/248 .
280         unsigned int num_hb_faces = hb_face_count(blob.get());
281         if (0 < num_hb_faces && (unsigned)index < num_hb_faces) {
282             face.reset(hb_face_create(blob.get(), (unsigned)index));
283             // Check the number of glyphs as a basic sanitization step.
284             if (face && hb_face_get_glyph_count(face.get()) == 0) {
285                 face.reset();
286             }
287         }
288     }
289     if (!face) {
290         face.reset(hb_face_create_for_tables(
291             skhb_get_table,
292             const_cast<SkTypeface*>(SkRef(&typeface)),
__anon19b7122a0502(void* user_data)293             [](void* user_data){ SkSafeUnref(reinterpret_cast<SkTypeface*>(user_data)); }));
294         hb_face_set_index(face.get(), (unsigned)index);
295     }
296     SkASSERT(face);
297     if (!face) {
298         return nullptr;
299     }
300     hb_face_set_upem(face.get(), typeface.getUnitsPerEm());
301 
302     SkDEBUGCODE(
303         hb_face_set_user_data(face.get(), &gDataIdKey, const_cast<SkTypeface*>(&typeface),
304                               nullptr, false);
305     )
306 
307     return face;
308 }
309 
create_typeface_hb_font(const SkTypeface & typeface)310 HBFont create_typeface_hb_font(const SkTypeface& typeface) {
311     HBFace face(create_hb_face(typeface));
312     if (!face) {
313         return nullptr;
314     }
315 
316     HBFont otFont(hb_font_create(face.get()));
317     SkASSERT(otFont);
318     if (!otFont) {
319         return nullptr;
320     }
321     hb_ot_font_set_funcs(otFont.get());
322     int axis_count = typeface.getVariationDesignPosition(nullptr, 0);
323     if (axis_count > 0) {
324         AutoSTMalloc<4, SkFontArguments::VariationPosition::Coordinate> axis_values(axis_count);
325         if (typeface.getVariationDesignPosition(axis_values, axis_count) == axis_count) {
326             hb_font_set_variations(otFont.get(),
327                                    reinterpret_cast<hb_variation_t*>(axis_values.get()),
328                                    axis_count);
329         }
330     }
331 
332     return otFont;
333 }
334 
create_sub_hb_font(const SkFont & font,const HBFont & typefaceFont)335 HBFont create_sub_hb_font(const SkFont& font, const HBFont& typefaceFont) {
336     SkDEBUGCODE(
337         hb_face_t* face = hb_font_get_face(typefaceFont.get());
338         void* dataId = hb_face_get_user_data(face, &gDataIdKey);
339         SkASSERT(dataId == font.getTypeface());
340     )
341 
342     // Creating a sub font means that non-available functions
343     // are found from the parent.
344     HBFont skFont(hb_font_create_sub_font(typefaceFont.get()));
345     hb_font_set_funcs(skFont.get(), skhb_get_font_funcs(),
346                       reinterpret_cast<void *>(new SkFont(font)),
347                       [](void* user_data){ delete reinterpret_cast<SkFont*>(user_data); });
348     int scale = skhb_position(font.getSize());
349     hb_font_set_scale(skFont.get(), scale, scale);
350 
351     return skFont;
352 }
353 
354 /** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */
utf8_next(const char ** ptr,const char * end)355 static inline SkUnichar utf8_next(const char** ptr, const char* end) {
356     SkUnichar val = SkUTF::NextUTF8(ptr, end);
357     return val < 0 ? 0xFFFD : val;
358 }
359 
360 class SkUnicodeHbScriptRunIterator final: public SkShaper::ScriptRunIterator {
361 public:
SkUnicodeHbScriptRunIterator(const char * utf8,size_t utf8Bytes,hb_script_t defaultScript)362     SkUnicodeHbScriptRunIterator(const char* utf8,
363                                  size_t utf8Bytes,
364                                  hb_script_t defaultScript)
365             : fCurrent(utf8)
366             , fBegin(utf8)
367             , fEnd(fCurrent + utf8Bytes)
368             , fCurrentScript(defaultScript) {}
hb_script_for_unichar(SkUnichar u)369     hb_script_t hb_script_for_unichar(SkUnichar u) {
370          return hb_unicode_script(hb_unicode_funcs_get_default(), u);
371     }
consume()372     void consume() override {
373         SkASSERT(fCurrent < fEnd);
374         SkUnichar u = utf8_next(&fCurrent, fEnd);
375         fCurrentScript = hb_script_for_unichar(u);
376         while (fCurrent < fEnd) {
377             const char* prev = fCurrent;
378             u = utf8_next(&fCurrent, fEnd);
379             const hb_script_t script = hb_script_for_unichar(u);
380             if (script != fCurrentScript) {
381                 if (fCurrentScript == HB_SCRIPT_INHERITED || fCurrentScript == HB_SCRIPT_COMMON) {
382                     fCurrentScript = script;
383                 } else if (script == HB_SCRIPT_INHERITED || script == HB_SCRIPT_COMMON) {
384                     continue;
385                 } else {
386                     fCurrent = prev;
387                     break;
388                 }
389             }
390         }
391         if (fCurrentScript == HB_SCRIPT_INHERITED) {
392             fCurrentScript = HB_SCRIPT_COMMON;
393         }
394     }
endOfCurrentRun() const395     size_t endOfCurrentRun() const override {
396         return fCurrent - fBegin;
397     }
atEnd() const398     bool atEnd() const override {
399         return fCurrent == fEnd;
400     }
401 
currentScript() const402     SkFourByteTag currentScript() const override {
403         return SkSetFourByteTag(HB_UNTAG(fCurrentScript));
404     }
405 private:
406     char const * fCurrent;
407     char const * const fBegin;
408     char const * const fEnd;
409     hb_script_t fCurrentScript;
410 };
411 
412 class RunIteratorQueue {
413 public:
insert(SkShaper::RunIterator * runIterator,int priority)414     void insert(SkShaper::RunIterator* runIterator, int priority) {
415         fEntries.insert({runIterator, priority});
416     }
417 
advanceRuns()418     bool advanceRuns() {
419         const SkShaper::RunIterator* leastRun = fEntries.peek().runIterator;
420         if (leastRun->atEnd()) {
421             SkASSERT(this->allRunsAreAtEnd());
422             return false;
423         }
424         const size_t leastEnd = leastRun->endOfCurrentRun();
425         SkShaper::RunIterator* currentRun = nullptr;
426         SkDEBUGCODE(size_t previousEndOfCurrentRun);
427         while ((currentRun = fEntries.peek().runIterator)->endOfCurrentRun() <= leastEnd) {
428             int priority = fEntries.peek().priority;
429             fEntries.pop();
430             SkDEBUGCODE(previousEndOfCurrentRun = currentRun->endOfCurrentRun());
431             currentRun->consume();
432             SkASSERT(previousEndOfCurrentRun < currentRun->endOfCurrentRun());
433             fEntries.insert({currentRun, priority});
434         }
435         return true;
436     }
437 
endOfCurrentRun() const438     size_t endOfCurrentRun() const {
439         return fEntries.peek().runIterator->endOfCurrentRun();
440     }
441 
442 private:
allRunsAreAtEnd() const443     bool allRunsAreAtEnd() const {
444         for (int i = 0; i < fEntries.count(); ++i) {
445             if (!fEntries.at(i).runIterator->atEnd()) {
446                 return false;
447             }
448         }
449         return true;
450     }
451 
452     struct Entry {
453         SkShaper::RunIterator* runIterator;
454         int priority;
455     };
CompareEntry(Entry const & a,Entry const & b)456     static bool CompareEntry(Entry const& a, Entry const& b) {
457         size_t aEnd = a.runIterator->endOfCurrentRun();
458         size_t bEnd = b.runIterator->endOfCurrentRun();
459         return aEnd  < bEnd || (aEnd == bEnd && a.priority < b.priority);
460     }
461     SkTDPQueue<Entry, CompareEntry> fEntries;
462 };
463 
464 struct ShapedGlyph {
465     SkGlyphID fID;
466     uint32_t fCluster;
467     SkPoint fOffset;
468     SkVector fAdvance;
469     bool fMayLineBreakBefore;
470     bool fMustLineBreakBefore;
471     bool fHasVisual;
472     bool fGraphemeBreakBefore;
473     bool fUnsafeToBreak;
474 };
475 struct ShapedRun {
ShapedRun__anon19b7122a0111::ShapedRun476     ShapedRun(SkShaper::RunHandler::Range utf8Range, const SkFont& font, SkBidiIterator::Level level,
477               std::unique_ptr<ShapedGlyph[]> glyphs, size_t numGlyphs, SkVector advance = {0, 0})
478         : fUtf8Range(utf8Range), fFont(font), fLevel(level)
479         , fGlyphs(std::move(glyphs)), fNumGlyphs(numGlyphs), fAdvance(advance)
480     {}
481 
482     SkShaper::RunHandler::Range fUtf8Range;
483     SkFont fFont;
484     SkBidiIterator::Level fLevel;
485     std::unique_ptr<ShapedGlyph[]> fGlyphs;
486     size_t fNumGlyphs;
487     SkVector fAdvance;
488 
489     static_assert(::sk_is_trivially_relocatable<decltype(fUtf8Range)>::value);
490     static_assert(::sk_is_trivially_relocatable<decltype(fFont)>::value);
491     static_assert(::sk_is_trivially_relocatable<decltype(fLevel)>::value);
492     static_assert(::sk_is_trivially_relocatable<decltype(fGlyphs)>::value);
493     static_assert(::sk_is_trivially_relocatable<decltype(fAdvance)>::value);
494 
495     using sk_is_trivially_relocatable = std::true_type;
496 };
497 struct ShapedLine {
498     TArray<ShapedRun> runs;
499     SkVector fAdvance = { 0, 0 };
500 };
501 
is_LTR(SkBidiIterator::Level level)502 constexpr bool is_LTR(SkBidiIterator::Level level) {
503     return (level & 1) == 0;
504 }
505 
append(SkShaper::RunHandler * handler,const SkShaper::RunHandler::RunInfo & runInfo,const ShapedRun & run,size_t startGlyphIndex,size_t endGlyphIndex)506 void append(SkShaper::RunHandler* handler, const SkShaper::RunHandler::RunInfo& runInfo,
507                    const ShapedRun& run, size_t startGlyphIndex, size_t endGlyphIndex) {
508     SkASSERT(startGlyphIndex <= endGlyphIndex);
509     const size_t glyphLen = endGlyphIndex - startGlyphIndex;
510 
511     const auto buffer = handler->runBuffer(runInfo);
512     SkASSERT(buffer.glyphs);
513     SkASSERT(buffer.positions);
514 
515     SkVector advance = {0,0};
516     for (size_t i = 0; i < glyphLen; i++) {
517         // Glyphs are in logical order, but output ltr since PDF readers seem to expect that.
518         const ShapedGlyph& glyph = run.fGlyphs[is_LTR(run.fLevel) ? startGlyphIndex + i
519                                                                   : endGlyphIndex - 1 - i];
520         buffer.glyphs[i] = glyph.fID;
521         if (buffer.offsets) {
522             buffer.positions[i] = advance + buffer.point;
523             buffer.offsets[i] = glyph.fOffset;
524         } else {
525             buffer.positions[i] = advance + buffer.point + glyph.fOffset;
526         }
527         if (buffer.clusters) {
528             buffer.clusters[i] = glyph.fCluster;
529         }
530         advance += glyph.fAdvance;
531     }
532     handler->commitRunBuffer(runInfo);
533 }
534 
emit(SkUnicode * unicode,const ShapedLine & line,SkShaper::RunHandler * handler)535 void emit(SkUnicode* unicode, const ShapedLine& line, SkShaper::RunHandler* handler) {
536     // Reorder the runs and glyphs per line and write them out.
537     handler->beginLine();
538 
539     int numRuns = line.runs.size();
540     AutoSTMalloc<4, SkBidiIterator::Level> runLevels(numRuns);
541     for (int i = 0; i < numRuns; ++i) {
542         runLevels[i] = line.runs[i].fLevel;
543     }
544     AutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
545     unicode->reorderVisual(runLevels, numRuns, logicalFromVisual);
546 
547     for (int i = 0; i < numRuns; ++i) {
548         int logicalIndex = logicalFromVisual[i];
549 
550         const auto& run = line.runs[logicalIndex];
551         const SkShaper::RunHandler::RunInfo info = {
552             run.fFont,
553             run.fLevel,
554             run.fAdvance,
555             run.fNumGlyphs,
556             run.fUtf8Range
557         };
558         handler->runInfo(info);
559     }
560     handler->commitRunInfo();
561     for (int i = 0; i < numRuns; ++i) {
562         int logicalIndex = logicalFromVisual[i];
563 
564         const auto& run = line.runs[logicalIndex];
565         const SkShaper::RunHandler::RunInfo info = {
566             run.fFont,
567             run.fLevel,
568             run.fAdvance,
569             run.fNumGlyphs,
570             run.fUtf8Range
571         };
572         append(handler, info, run, 0, run.fNumGlyphs);
573     }
574 
575     handler->commitLine();
576 }
577 
578 struct ShapedRunGlyphIterator {
ShapedRunGlyphIterator__anon19b7122a0111::ShapedRunGlyphIterator579     ShapedRunGlyphIterator(const TArray<ShapedRun>& origRuns)
580         : fRuns(&origRuns), fRunIndex(0), fGlyphIndex(0)
581     { }
582 
583     ShapedRunGlyphIterator(const ShapedRunGlyphIterator& that) = default;
584     ShapedRunGlyphIterator& operator=(const ShapedRunGlyphIterator& that) = default;
operator ==__anon19b7122a0111::ShapedRunGlyphIterator585     bool operator==(const ShapedRunGlyphIterator& that) const {
586         return fRuns == that.fRuns &&
587                fRunIndex == that.fRunIndex &&
588                fGlyphIndex == that.fGlyphIndex;
589     }
operator !=__anon19b7122a0111::ShapedRunGlyphIterator590     bool operator!=(const ShapedRunGlyphIterator& that) const {
591         return fRuns != that.fRuns ||
592                fRunIndex != that.fRunIndex ||
593                fGlyphIndex != that.fGlyphIndex;
594     }
595 
next__anon19b7122a0111::ShapedRunGlyphIterator596     ShapedGlyph* next() {
597         const TArray<ShapedRun>& runs = *fRuns;
598         SkASSERT(fRunIndex < runs.size());
599         SkASSERT(fGlyphIndex < runs[fRunIndex].fNumGlyphs);
600 
601         ++fGlyphIndex;
602         if (fGlyphIndex == runs[fRunIndex].fNumGlyphs) {
603             fGlyphIndex = 0;
604             ++fRunIndex;
605             if (fRunIndex >= runs.size()) {
606                 return nullptr;
607             }
608         }
609         return &runs[fRunIndex].fGlyphs[fGlyphIndex];
610     }
611 
current__anon19b7122a0111::ShapedRunGlyphIterator612     ShapedGlyph* current() {
613         const TArray<ShapedRun>& runs = *fRuns;
614         if (fRunIndex >= runs.size()) {
615             return nullptr;
616         }
617         return &runs[fRunIndex].fGlyphs[fGlyphIndex];
618     }
619 
620     const TArray<ShapedRun>* fRuns;
621     int fRunIndex;
622     size_t fGlyphIndex;
623 };
624 
625 class ShaperHarfBuzz : public SkShaper {
626 public:
627     ShaperHarfBuzz(sk_sp<SkUnicode>,
628                    HBBuffer,
629                    sk_sp<SkFontMgr>);
630 
631 protected:
632     sk_sp<SkUnicode> fUnicode;
633 
634     ShapedRun shape(const char* utf8, size_t utf8Bytes,
635                     const char* utf8Start,
636                     const char* utf8End,
637                     const BiDiRunIterator&,
638                     const LanguageRunIterator&,
639                     const ScriptRunIterator&,
640                     const FontRunIterator&,
641                     const Feature*, size_t featuresSize) const;
642 private:
643     const sk_sp<SkFontMgr> fFontMgr; // for fallback
644     HBBuffer               fBuffer;
645     hb_language_t          fUndefinedLanguage;
646 
647 #if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
648     void shape(const char* utf8, size_t utf8Bytes,
649                const SkFont&,
650                bool leftToRight,
651                SkScalar width,
652                RunHandler*) const override;
653 
654     void shape(const char* utf8Text, size_t textBytes,
655                FontRunIterator&,
656                BiDiRunIterator&,
657                ScriptRunIterator&,
658                LanguageRunIterator&,
659                SkScalar width,
660                RunHandler*) const override;
661 #endif
662 
663     void shape(const char* utf8Text, size_t textBytes,
664                FontRunIterator&,
665                BiDiRunIterator&,
666                ScriptRunIterator&,
667                LanguageRunIterator&,
668                const Feature*, size_t featuresSize,
669                SkScalar width,
670                RunHandler*) const override;
671 
672     virtual void wrap(char const * const utf8, size_t utf8Bytes,
673                       const BiDiRunIterator&,
674                       const LanguageRunIterator&,
675                       const ScriptRunIterator&,
676                       const FontRunIterator&,
677                       RunIteratorQueue& runSegmenter,
678                       const Feature*, size_t featuresSize,
679                       SkScalar width,
680                       RunHandler*) const = 0;
681 };
682 
683 class ShaperDrivenWrapper : public ShaperHarfBuzz {
684 public:
685     using ShaperHarfBuzz::ShaperHarfBuzz;
686 private:
687     void wrap(char const * const utf8, size_t utf8Bytes,
688               const BiDiRunIterator&,
689               const LanguageRunIterator&,
690               const ScriptRunIterator&,
691               const FontRunIterator&,
692               RunIteratorQueue& runSegmenter,
693               const Feature*, size_t featuresSize,
694               SkScalar width,
695               RunHandler*) const override;
696 };
697 
698 class ShapeThenWrap : public ShaperHarfBuzz {
699 public:
700     using ShaperHarfBuzz::ShaperHarfBuzz;
701 private:
702     void wrap(char const * const utf8, size_t utf8Bytes,
703               const BiDiRunIterator&,
704               const LanguageRunIterator&,
705               const ScriptRunIterator&,
706               const FontRunIterator&,
707               RunIteratorQueue& runSegmenter,
708               const Feature*, size_t featuresSize,
709               SkScalar width,
710               RunHandler*) const override;
711 };
712 
713 class ShapeDontWrapOrReorder : public ShaperHarfBuzz {
714 public:
715     using ShaperHarfBuzz::ShaperHarfBuzz;
716 private:
717     void wrap(char const * const utf8, size_t utf8Bytes,
718               const BiDiRunIterator&,
719               const LanguageRunIterator&,
720               const ScriptRunIterator&,
721               const FontRunIterator&,
722               RunIteratorQueue& runSegmenter,
723               const Feature*, size_t featuresSize,
724               SkScalar width,
725               RunHandler*) const override;
726 };
727 
ShaperHarfBuzz(sk_sp<SkUnicode> unicode,HBBuffer buffer,sk_sp<SkFontMgr> fallback)728 ShaperHarfBuzz::ShaperHarfBuzz(sk_sp<SkUnicode> unicode,
729                                HBBuffer buffer,
730                                sk_sp<SkFontMgr> fallback)
731     : fUnicode(unicode)
732     , fFontMgr(fallback ? std::move(fallback) : SkFontMgr::RefEmpty())
733     , fBuffer(std::move(buffer))
734     , fUndefinedLanguage(hb_language_from_string("und", -1)) {
735 #if defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
736     SkASSERT(fUnicode);
737 #endif
738 }
739 
740 #if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
shape(const char * utf8,size_t utf8Bytes,const SkFont & srcFont,bool leftToRight,SkScalar width,RunHandler * handler) const741 void ShaperHarfBuzz::shape(const char* utf8,
742                            size_t utf8Bytes,
743                            const SkFont& srcFont,
744                            bool leftToRight,
745                            SkScalar width,
746                            RunHandler* handler) const {
747     SkBidiIterator::Level defaultLevel = leftToRight ? SkBidiIterator::kLTR : SkBidiIterator::kRTL;
748     std::unique_ptr<BiDiRunIterator> bidi(
749             SkShapers::unicode::BidiRunIterator(fUnicode, utf8, utf8Bytes, defaultLevel));
750 
751     if (!bidi) {
752         return;
753     }
754 
755     std::unique_ptr<LanguageRunIterator> language(MakeStdLanguageRunIterator(utf8, utf8Bytes));
756     if (!language) {
757         return;
758     }
759 
760     std::unique_ptr<ScriptRunIterator> script(SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes));
761     if (!script) {
762         return;
763     }
764 
765     std::unique_ptr<FontRunIterator> font(
766                 MakeFontMgrRunIterator(utf8, utf8Bytes, srcFont, fFontMgr));
767     if (!font) {
768         return;
769     }
770 
771     this->shape(utf8, utf8Bytes, *font, *bidi, *script, *language, width, handler);
772 }
773 
shape(const char * utf8,size_t utf8Bytes,FontRunIterator & font,BiDiRunIterator & bidi,ScriptRunIterator & script,LanguageRunIterator & language,SkScalar width,RunHandler * handler) const774 void ShaperHarfBuzz::shape(const char* utf8,
775                            size_t utf8Bytes,
776                            FontRunIterator& font,
777                            BiDiRunIterator& bidi,
778                            ScriptRunIterator& script,
779                            LanguageRunIterator& language,
780                            SkScalar width,
781                            RunHandler* handler) const {
782     this->shape(utf8, utf8Bytes, font, bidi, script, language, nullptr, 0, width, handler);
783 }
784 #endif  // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
785 
shape(const char * utf8,size_t utf8Bytes,FontRunIterator & font,BiDiRunIterator & bidi,ScriptRunIterator & script,LanguageRunIterator & language,const Feature * features,size_t featuresSize,SkScalar width,RunHandler * handler) const786 void ShaperHarfBuzz::shape(const char* utf8,
787                            size_t utf8Bytes,
788                            FontRunIterator& font,
789                            BiDiRunIterator& bidi,
790                            ScriptRunIterator& script,
791                            LanguageRunIterator& language,
792                            const Feature* features,
793                            size_t featuresSize,
794                            SkScalar width,
795                            RunHandler* handler) const {
796     SkASSERT(handler);
797     RunIteratorQueue runSegmenter;
798     runSegmenter.insert(&font,     3); // The font iterator is always run last in case of tie.
799     runSegmenter.insert(&bidi,     2);
800     runSegmenter.insert(&script,   1);
801     runSegmenter.insert(&language, 0);
802 
803     this->wrap(utf8, utf8Bytes, bidi, language, script, font, runSegmenter,
804                features, featuresSize, width, handler);
805 }
806 
wrap(char const * const utf8,size_t utf8Bytes,const BiDiRunIterator & bidi,const LanguageRunIterator & language,const ScriptRunIterator & script,const FontRunIterator & font,RunIteratorQueue & runSegmenter,const Feature * features,size_t featuresSize,SkScalar width,RunHandler * handler) const807 void ShaperDrivenWrapper::wrap(char const * const utf8, size_t utf8Bytes,
808                                const BiDiRunIterator& bidi,
809                                const LanguageRunIterator& language,
810                                const ScriptRunIterator& script,
811                                const FontRunIterator& font,
812                                RunIteratorQueue& runSegmenter,
813                                const Feature* features, size_t featuresSize,
814                                SkScalar width,
815                                RunHandler* handler) const
816 {
817     ShapedLine line;
818 
819     const char* utf8Start = nullptr;
820     const char* utf8End = utf8;
821     SkUnicodeBreak lineBreakIterator;
822     SkString currentLanguage;
823     while (runSegmenter.advanceRuns()) {  // For each item
824         utf8Start = utf8End;
825         utf8End = utf8 + runSegmenter.endOfCurrentRun();
826 
827         ShapedRun model(RunHandler::Range(), SkFont(), 0, nullptr, 0);
828         bool modelNeedsRegenerated = true;
829         int modelGlyphOffset = 0;
830 
831         struct TextProps {
832             int glyphLen = 0;
833             SkVector advance = {0, 0};
834         };
835         // map from character position to [safe to break, glyph position, advance]
836         std::unique_ptr<TextProps[]> modelText;
837         int modelTextOffset = 0;
838         SkVector modelAdvanceOffset = {0, 0};
839 
840         while (utf8Start < utf8End) {  // While there are still code points left in this item
841             size_t utf8runLength = utf8End - utf8Start;
842             if (modelNeedsRegenerated) {
843                 model = shape(utf8, utf8Bytes,
844                               utf8Start, utf8End,
845                               bidi, language, script, font,
846                               features, featuresSize);
847                 modelGlyphOffset = 0;
848 
849                 SkVector advance = {0, 0};
850                 modelText = std::make_unique<TextProps[]>(utf8runLength + 1);
851                 size_t modelStartCluster = utf8Start - utf8;
852                 size_t previousCluster = 0;
853                 for (size_t i = 0; i < model.fNumGlyphs; ++i) {
854                     SkASSERT(modelStartCluster <= model.fGlyphs[i].fCluster);
855                     SkASSERT(                     model.fGlyphs[i].fCluster < (size_t)(utf8End - utf8));
856                     if (!model.fGlyphs[i].fUnsafeToBreak) {
857                         // Store up to the first glyph in the cluster.
858                         size_t currentCluster = model.fGlyphs[i].fCluster - modelStartCluster;
859                         if (previousCluster != currentCluster) {
860                             previousCluster  = currentCluster;
861                             modelText[currentCluster].glyphLen = i;
862                             modelText[currentCluster].advance = advance;
863                         }
864                     }
865                     advance += model.fGlyphs[i].fAdvance;
866                 }
867                 // Assume it is always safe to break after the end of an item
868                 modelText[utf8runLength].glyphLen = model.fNumGlyphs;
869                 modelText[utf8runLength].advance = model.fAdvance;
870                 modelTextOffset = 0;
871                 modelAdvanceOffset = {0, 0};
872                 modelNeedsRegenerated = false;
873             }
874 
875             // TODO: break iterator per item, but just reset position if needed?
876             // Maybe break iterator with model?
877             if (!lineBreakIterator || !currentLanguage.equals(language.currentLanguage())) {
878                 currentLanguage = language.currentLanguage();
879                 lineBreakIterator = fUnicode->makeBreakIterator(currentLanguage.c_str(),
880                                                                 SkUnicode::BreakType::kLines);
881                 if (!lineBreakIterator) {
882                     return;
883                 }
884             }
885             if (!lineBreakIterator->setText(utf8Start, utf8runLength)) {
886                 return;
887             }
888             SkBreakIterator& breakIterator = *lineBreakIterator;
889 
890             ShapedRun best(RunHandler::Range(), SkFont(), 0, nullptr, 0,
891                            { SK_ScalarNegativeInfinity, SK_ScalarNegativeInfinity });
892             bool bestIsInvalid = true;
893             bool bestUsesModelForGlyphs = false;
894             SkScalar widthLeft = width - line.fAdvance.fX;
895 
896             for (int32_t breakIteratorCurrent = breakIterator.next();
897                  !breakIterator.isDone();
898                  breakIteratorCurrent = breakIterator.next())
899             {
900                 // TODO: if past a safe to break, future safe to break will be at least as long
901 
902                 // TODO: adjust breakIteratorCurrent by ignorable whitespace
903                 bool candidateUsesModelForGlyphs = false;
904                 ShapedRun candidate = [&](const TextProps& props){
905                     if (props.glyphLen) {
906                         candidateUsesModelForGlyphs = true;
907                         return ShapedRun(RunHandler::Range(utf8Start - utf8, breakIteratorCurrent),
908                                          font.currentFont(), bidi.currentLevel(),
909                                          std::unique_ptr<ShapedGlyph[]>(),
910                                          props.glyphLen - modelGlyphOffset,
911                                          props.advance - modelAdvanceOffset);
912                     } else {
913                         return shape(utf8, utf8Bytes,
914                                      utf8Start, utf8Start + breakIteratorCurrent,
915                                      bidi, language, script, font,
916                                      features, featuresSize);
917                     }
918                 }(modelText[breakIteratorCurrent + modelTextOffset]);
919                 auto score = [widthLeft](const ShapedRun& run) -> SkScalar {
920                     if (run.fAdvance.fX < widthLeft) {
921                         return run.fUtf8Range.size();
922                     } else {
923                         return widthLeft - run.fAdvance.fX;
924                     }
925                 };
926                 if (bestIsInvalid || score(best) < score(candidate)) {
927                     best = std::move(candidate);
928                     bestIsInvalid = false;
929                     bestUsesModelForGlyphs = candidateUsesModelForGlyphs;
930                 }
931             }
932 
933             // If nothing fit (best score is negative) and the line is not empty
934             if (width < line.fAdvance.fX + best.fAdvance.fX && !line.runs.empty()) {
935                 emit(fUnicode.get(), line, handler);
936                 line.runs.clear();
937                 line.fAdvance = {0, 0};
938             } else {
939                 if (bestUsesModelForGlyphs) {
940                     best.fGlyphs = std::make_unique<ShapedGlyph[]>(best.fNumGlyphs);
941                     memcpy(best.fGlyphs.get(), model.fGlyphs.get() + modelGlyphOffset,
942                            best.fNumGlyphs * sizeof(ShapedGlyph));
943                     modelGlyphOffset += best.fNumGlyphs;
944                     modelTextOffset += best.fUtf8Range.size();
945                     modelAdvanceOffset += best.fAdvance;
946                 } else {
947                     modelNeedsRegenerated = true;
948                 }
949                 utf8Start += best.fUtf8Range.size();
950                 line.fAdvance += best.fAdvance;
951                 line.runs.emplace_back(std::move(best));
952 
953                 // If item broken, emit line (prevent remainder from accidentally fitting)
954                 if (utf8Start != utf8End) {
955                     emit(fUnicode.get(), line, handler);
956                     line.runs.clear();
957                     line.fAdvance = {0, 0};
958                 }
959             }
960         }
961     }
962     emit(fUnicode.get(), line, handler);
963 }
964 
wrap(char const * const utf8,size_t utf8Bytes,const BiDiRunIterator & bidi,const LanguageRunIterator & language,const ScriptRunIterator & script,const FontRunIterator & font,RunIteratorQueue & runSegmenter,const Feature * features,size_t featuresSize,SkScalar width,RunHandler * handler) const965 void ShapeThenWrap::wrap(char const * const utf8, size_t utf8Bytes,
966                          const BiDiRunIterator& bidi,
967                          const LanguageRunIterator& language,
968                          const ScriptRunIterator& script,
969                          const FontRunIterator& font,
970                          RunIteratorQueue& runSegmenter,
971                          const Feature* features, size_t featuresSize,
972                          SkScalar width,
973                          RunHandler* handler) const
974 {
975     TArray<ShapedRun> runs;
976 {
977     SkString currentLanguage;
978     SkUnicodeBreak lineBreakIterator;
979     SkUnicodeBreak graphemeBreakIterator;
980     bool needIteratorInit = true;
981     const char* utf8Start = nullptr;
982     const char* utf8End = utf8;
983     while (runSegmenter.advanceRuns()) {
984         utf8Start = utf8End;
985         utf8End = utf8 + runSegmenter.endOfCurrentRun();
986 
987         runs.emplace_back(shape(utf8, utf8Bytes,
988                                 utf8Start, utf8End,
989                                 bidi, language, script, font,
990                                 features, featuresSize));
991         ShapedRun& run = runs.back();
992 
993         if (needIteratorInit || !currentLanguage.equals(language.currentLanguage())) {
994             currentLanguage = language.currentLanguage();
995             lineBreakIterator = fUnicode->makeBreakIterator(currentLanguage.c_str(),
996                                                             SkUnicode::BreakType::kLines);
997             if (!lineBreakIterator) {
998                 return;
999             }
1000             graphemeBreakIterator = fUnicode->makeBreakIterator(currentLanguage.c_str(),
1001                                                                 SkUnicode::BreakType::kGraphemes);
1002             if (!graphemeBreakIterator) {
1003                 return;
1004             }
1005             needIteratorInit = false;
1006         }
1007         size_t utf8runLength = utf8End - utf8Start;
1008         if (!lineBreakIterator->setText(utf8Start, utf8runLength)) {
1009             return;
1010         }
1011         if (!graphemeBreakIterator->setText(utf8Start, utf8runLength)) {
1012             return;
1013         }
1014 
1015         uint32_t previousCluster = 0xFFFFFFFF;
1016         for (size_t i = 0; i < run.fNumGlyphs; ++i) {
1017             ShapedGlyph& glyph = run.fGlyphs[i];
1018             int32_t glyphCluster = glyph.fCluster;
1019 
1020             int32_t lineBreakIteratorCurrent = lineBreakIterator->current();
1021             while (!lineBreakIterator->isDone() && lineBreakIteratorCurrent < glyphCluster)
1022             {
1023                 lineBreakIteratorCurrent = lineBreakIterator->next();
1024             }
1025             glyph.fMayLineBreakBefore = glyph.fCluster != previousCluster &&
1026                                         lineBreakIteratorCurrent == glyphCluster;
1027 
1028             int32_t graphemeBreakIteratorCurrent = graphemeBreakIterator->current();
1029             while (!graphemeBreakIterator->isDone() && graphemeBreakIteratorCurrent < glyphCluster)
1030             {
1031                 graphemeBreakIteratorCurrent = graphemeBreakIterator->next();
1032             }
1033             glyph.fGraphemeBreakBefore = glyph.fCluster != previousCluster &&
1034                                          graphemeBreakIteratorCurrent == glyphCluster;
1035 
1036             previousCluster = glyph.fCluster;
1037         }
1038     }
1039 }
1040 
1041 // Iterate over the glyphs in logical order to find potential line lengths.
1042 {
1043     /** The position of the beginning of the line. */
1044     ShapedRunGlyphIterator beginning(runs);
1045 
1046     /** The position of the candidate line break. */
1047     ShapedRunGlyphIterator candidateLineBreak(runs);
1048     SkScalar candidateLineBreakWidth = 0;
1049 
1050     /** The position of the candidate grapheme break. */
1051     ShapedRunGlyphIterator candidateGraphemeBreak(runs);
1052     SkScalar candidateGraphemeBreakWidth = 0;
1053 
1054     /** The position of the current location. */
1055     ShapedRunGlyphIterator current(runs);
1056     SkScalar currentWidth = 0;
1057     while (ShapedGlyph* glyph = current.current()) {
1058         // 'Break' at graphemes until a line boundary, then only at line boundaries.
1059         // Only break at graphemes if no line boundary is valid.
1060         if (current != beginning) {
1061             if (glyph->fGraphemeBreakBefore || glyph->fMayLineBreakBefore) {
1062                 // TODO: preserve line breaks <= grapheme breaks
1063                 // and prevent line breaks inside graphemes
1064                 candidateGraphemeBreak = current;
1065                 candidateGraphemeBreakWidth = currentWidth;
1066                 if (glyph->fMayLineBreakBefore) {
1067                     candidateLineBreak = current;
1068                     candidateLineBreakWidth = currentWidth;
1069                 }
1070             }
1071         }
1072 
1073         SkScalar glyphWidth = glyph->fAdvance.fX;
1074         // Break when overwidth, the glyph has a visual representation, and some space is used.
1075         if (width < currentWidth + glyphWidth && glyph->fHasVisual && candidateGraphemeBreakWidth > 0){
1076             if (candidateLineBreak != beginning) {
1077                 beginning = candidateLineBreak;
1078                 currentWidth -= candidateLineBreakWidth;
1079                 candidateGraphemeBreakWidth -= candidateLineBreakWidth;
1080                 candidateLineBreakWidth = 0;
1081             } else if (candidateGraphemeBreak != beginning) {
1082                 beginning = candidateGraphemeBreak;
1083                 candidateLineBreak = beginning;
1084                 currentWidth -= candidateGraphemeBreakWidth;
1085                 candidateGraphemeBreakWidth = 0;
1086                 candidateLineBreakWidth = 0;
1087             } else {
1088                 SK_ABORT("");
1089             }
1090 
1091             if (width < currentWidth) {
1092                 if (width < candidateGraphemeBreakWidth) {
1093                     candidateGraphemeBreak = candidateLineBreak;
1094                     candidateGraphemeBreakWidth = candidateLineBreakWidth;
1095                 }
1096                 current = candidateGraphemeBreak;
1097                 currentWidth = candidateGraphemeBreakWidth;
1098             }
1099 
1100             glyph = beginning.current();
1101             if (glyph) {
1102                 glyph->fMustLineBreakBefore = true;
1103             }
1104 
1105         } else {
1106             current.next();
1107             currentWidth += glyphWidth;
1108         }
1109     }
1110 }
1111 
1112 // Reorder the runs and glyphs per line and write them out.
1113 {
1114     ShapedRunGlyphIterator previousBreak(runs);
1115     ShapedRunGlyphIterator glyphIterator(runs);
1116     int previousRunIndex = -1;
1117     while (glyphIterator.current()) {
1118         const ShapedRunGlyphIterator current = glyphIterator;
1119         ShapedGlyph* nextGlyph = glyphIterator.next();
1120 
1121         if (previousRunIndex != current.fRunIndex) {
1122             SkFontMetrics metrics;
1123             runs[current.fRunIndex].fFont.getMetrics(&metrics);
1124             previousRunIndex = current.fRunIndex;
1125         }
1126 
1127         // Nothing can be written until the baseline is known.
1128         if (!(nextGlyph == nullptr || nextGlyph->fMustLineBreakBefore)) {
1129             continue;
1130         }
1131 
1132         int numRuns = current.fRunIndex - previousBreak.fRunIndex + 1;
1133         AutoSTMalloc<4, SkBidiIterator::Level> runLevels(numRuns);
1134         for (int i = 0; i < numRuns; ++i) {
1135             runLevels[i] = runs[previousBreak.fRunIndex + i].fLevel;
1136         }
1137         AutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
1138         fUnicode->reorderVisual(runLevels, numRuns, logicalFromVisual);
1139 
1140         // step through the runs in reverse visual order and the glyphs in reverse logical order
1141         // until a visible glyph is found and force them to the end of the visual line.
1142 
1143         handler->beginLine();
1144 
1145         struct SubRun { const ShapedRun& run; size_t startGlyphIndex; size_t endGlyphIndex; };
1146         auto makeSubRun = [&runs, &previousBreak, &current, &logicalFromVisual](size_t visualIndex){
1147             int logicalIndex = previousBreak.fRunIndex + logicalFromVisual[visualIndex];
1148             const auto& run = runs[logicalIndex];
1149             size_t startGlyphIndex = (logicalIndex == previousBreak.fRunIndex)
1150                                    ? previousBreak.fGlyphIndex
1151                                    : 0;
1152             size_t endGlyphIndex = (logicalIndex == current.fRunIndex)
1153                                  ? current.fGlyphIndex + 1
1154                                  : run.fNumGlyphs;
1155             return SubRun{ run, startGlyphIndex, endGlyphIndex };
1156         };
1157         auto makeRunInfo = [](const SubRun& sub) {
1158             uint32_t startUtf8 = sub.run.fGlyphs[sub.startGlyphIndex].fCluster;
1159             uint32_t endUtf8 = (sub.endGlyphIndex < sub.run.fNumGlyphs)
1160                              ? sub.run.fGlyphs[sub.endGlyphIndex].fCluster
1161                              : sub.run.fUtf8Range.end();
1162 
1163             SkVector advance = SkVector::Make(0, 0);
1164             for (size_t i = sub.startGlyphIndex; i < sub.endGlyphIndex; ++i) {
1165                 advance += sub.run.fGlyphs[i].fAdvance;
1166             }
1167 
1168             return RunHandler::RunInfo{
1169                 sub.run.fFont,
1170                 sub.run.fLevel,
1171                 advance,
1172                 sub.endGlyphIndex - sub.startGlyphIndex,
1173                 RunHandler::Range(startUtf8, endUtf8 - startUtf8)
1174             };
1175         };
1176 
1177         for (int i = 0; i < numRuns; ++i) {
1178             handler->runInfo(makeRunInfo(makeSubRun(i)));
1179         }
1180         handler->commitRunInfo();
1181         for (int i = 0; i < numRuns; ++i) {
1182             SubRun sub = makeSubRun(i);
1183             append(handler, makeRunInfo(sub), sub.run, sub.startGlyphIndex, sub.endGlyphIndex);
1184         }
1185 
1186         handler->commitLine();
1187 
1188         previousRunIndex = -1;
1189         previousBreak = glyphIterator;
1190     }
1191 }
1192 }
1193 
wrap(char const * const utf8,size_t utf8Bytes,const BiDiRunIterator & bidi,const LanguageRunIterator & language,const ScriptRunIterator & script,const FontRunIterator & font,RunIteratorQueue & runSegmenter,const Feature * features,size_t featuresSize,SkScalar width,RunHandler * handler) const1194 void ShapeDontWrapOrReorder::wrap(char const * const utf8, size_t utf8Bytes,
1195                                   const BiDiRunIterator& bidi,
1196                                   const LanguageRunIterator& language,
1197                                   const ScriptRunIterator& script,
1198                                   const FontRunIterator& font,
1199                                   RunIteratorQueue& runSegmenter,
1200                                   const Feature* features, size_t featuresSize,
1201                                   SkScalar width,
1202                                   RunHandler* handler) const
1203 {
1204     sk_ignore_unused_variable(width);
1205     TArray<ShapedRun> runs;
1206 
1207     const char* utf8Start = nullptr;
1208     const char* utf8End = utf8;
1209     while (runSegmenter.advanceRuns()) {
1210         utf8Start = utf8End;
1211         utf8End = utf8 + runSegmenter.endOfCurrentRun();
1212 
1213         runs.emplace_back(shape(utf8, utf8Bytes,
1214                                 utf8Start, utf8End,
1215                                 bidi, language, script, font,
1216                                 features, featuresSize));
1217     }
1218 
1219     handler->beginLine();
1220     for (const auto& run : runs) {
1221         const RunHandler::RunInfo info = {
1222             run.fFont,
1223             run.fLevel,
1224             run.fAdvance,
1225             run.fNumGlyphs,
1226             run.fUtf8Range
1227         };
1228         handler->runInfo(info);
1229     }
1230     handler->commitRunInfo();
1231     for (const auto& run : runs) {
1232         const RunHandler::RunInfo info = {
1233             run.fFont,
1234             run.fLevel,
1235             run.fAdvance,
1236             run.fNumGlyphs,
1237             run.fUtf8Range
1238         };
1239         append(handler, info, run, 0, run.fNumGlyphs);
1240     }
1241     handler->commitLine();
1242 }
1243 
1244 class HBLockedFaceCache {
1245 public:
HBLockedFaceCache(SkLRUCache<SkTypefaceID,HBFont> & lruCache,SkMutex & mutex)1246     HBLockedFaceCache(SkLRUCache<SkTypefaceID, HBFont>& lruCache, SkMutex& mutex)
1247         : fLRUCache(lruCache), fMutex(mutex)
1248     {
1249         fMutex.acquire();
1250     }
1251     HBLockedFaceCache(const HBLockedFaceCache&) = delete;
1252     HBLockedFaceCache& operator=(const HBLockedFaceCache&) = delete;
1253     HBLockedFaceCache& operator=(HBLockedFaceCache&&) = delete;
1254 
~HBLockedFaceCache()1255     ~HBLockedFaceCache() {
1256         fMutex.release();
1257     }
1258 
find(SkTypefaceID fontId)1259     HBFont* find(SkTypefaceID fontId) {
1260         return fLRUCache.find(fontId);
1261     }
insert(SkTypefaceID fontId,HBFont hbFont)1262     HBFont* insert(SkTypefaceID fontId, HBFont hbFont) {
1263         return fLRUCache.insert(fontId, std::move(hbFont));
1264     }
reset()1265     void reset() {
1266         fLRUCache.reset();
1267     }
1268 private:
1269     SkLRUCache<SkTypefaceID, HBFont>& fLRUCache;
1270     SkMutex& fMutex;
1271 };
get_hbFace_cache()1272 static HBLockedFaceCache get_hbFace_cache() {
1273     static SkMutex gHBFaceCacheMutex;
1274     static SkLRUCache<SkTypefaceID, HBFont> gHBFaceCache(100);
1275     return HBLockedFaceCache(gHBFaceCache, gHBFaceCacheMutex);
1276 }
1277 
shape(char const * const utf8,size_t const utf8Bytes,char const * const utf8Start,char const * const utf8End,const BiDiRunIterator & bidi,const LanguageRunIterator & language,const ScriptRunIterator & script,const FontRunIterator & font,Feature const * const features,size_t const featuresSize) const1278 ShapedRun ShaperHarfBuzz::shape(char const * const utf8,
1279                                   size_t const utf8Bytes,
1280                                   char const * const utf8Start,
1281                                   char const * const utf8End,
1282                                   const BiDiRunIterator& bidi,
1283                                   const LanguageRunIterator& language,
1284                                   const ScriptRunIterator& script,
1285                                   const FontRunIterator& font,
1286                                   Feature const * const features, size_t const featuresSize) const
1287 {
1288     size_t utf8runLength = utf8End - utf8Start;
1289     ShapedRun run(RunHandler::Range(utf8Start - utf8, utf8runLength),
1290                   font.currentFont(), bidi.currentLevel(), nullptr, 0);
1291 
1292     hb_buffer_t* buffer = fBuffer.get();
1293     SkAutoTCallVProc<hb_buffer_t, hb_buffer_clear_contents> autoClearBuffer(buffer);
1294     hb_buffer_set_content_type(buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
1295     hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
1296 
1297     // Documentation for HB_BUFFER_FLAG_BOT/EOT at 763e5466c0a03a7c27020e1e2598e488612529a7.
1298     // Currently BOT forces a dotted circle when first codepoint is a mark; EOT has no effect.
1299     // Avoid adding dotted circle, re-evaluate if BOT/EOT change. See https://skbug.com/9618.
1300     // hb_buffer_set_flags(buffer, HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT);
1301 
1302     // Add precontext.
1303     hb_buffer_add_utf8(buffer, utf8, utf8Start - utf8, utf8Start - utf8, 0);
1304 
1305     // Populate the hb_buffer directly with utf8 cluster indexes.
1306     const char* utf8Current = utf8Start;
1307     while (utf8Current < utf8End) {
1308         unsigned int cluster = utf8Current - utf8;
1309         hb_codepoint_t u = utf8_next(&utf8Current, utf8End);
1310         hb_buffer_add(buffer, u, cluster);
1311     }
1312 
1313     // Add postcontext.
1314     hb_buffer_add_utf8(buffer, utf8Current, utf8 + utf8Bytes - utf8Current, 0, 0);
1315 
1316     hb_direction_t direction = is_LTR(bidi.currentLevel()) ? HB_DIRECTION_LTR:HB_DIRECTION_RTL;
1317     hb_buffer_set_direction(buffer, direction);
1318     hb_buffer_set_script(buffer, hb_script_from_iso15924_tag((hb_tag_t)script.currentScript()));
1319     // Buffers with HB_LANGUAGE_INVALID race since hb_language_get_default is not thread safe.
1320     // The user must provide a language, but may provide data hb_language_from_string cannot use.
1321     // Use "und" for the undefined language in this case (RFC5646 4.1 5).
1322     hb_language_t hbLanguage = hb_language_from_string(language.currentLanguage(), -1);
1323     if (hbLanguage == HB_LANGUAGE_INVALID) {
1324         hbLanguage = fUndefinedLanguage;
1325     }
1326     hb_buffer_set_language(buffer, hbLanguage);
1327     hb_buffer_guess_segment_properties(buffer);
1328 
1329     // TODO: better cache HBFace (data) / hbfont (typeface)
1330     // An HBFace is expensive (it sanitizes the bits).
1331     // An HBFont is fairly inexpensive.
1332     // An HBFace is actually tied to the data, not the typeface.
1333     // The size of 100 here is completely arbitrary and used to match libtxt.
1334     HBFont hbFont;
1335     {
1336         HBLockedFaceCache cache = get_hbFace_cache();
1337         SkTypefaceID dataId = font.currentFont().getTypeface()->uniqueID();
1338         HBFont* typefaceFontCached = cache.find(dataId);
1339         if (!typefaceFontCached) {
1340             HBFont typefaceFont(create_typeface_hb_font(*font.currentFont().getTypeface()));
1341             typefaceFontCached = cache.insert(dataId, std::move(typefaceFont));
1342         }
1343         hbFont = create_sub_hb_font(font.currentFont(), *typefaceFontCached);
1344     }
1345     if (!hbFont) {
1346         return run;
1347     }
1348 
1349     STArray<32, hb_feature_t> hbFeatures;
1350     for (const auto& feature : SkSpan(features, featuresSize)) {
1351         if (feature.end < SkTo<size_t>(utf8Start - utf8) ||
1352                           SkTo<size_t>(utf8End   - utf8)  <= feature.start)
1353         {
1354             continue;
1355         }
1356         if (feature.start <= SkTo<size_t>(utf8Start - utf8) &&
1357                              SkTo<size_t>(utf8End   - utf8) <= feature.end)
1358         {
1359             hbFeatures.push_back({ (hb_tag_t)feature.tag, feature.value,
1360                                    HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END});
1361         } else {
1362             hbFeatures.push_back({ (hb_tag_t)feature.tag, feature.value,
1363                                    SkTo<unsigned>(feature.start), SkTo<unsigned>(feature.end)});
1364         }
1365     }
1366 
1367     hb_shape(hbFont.get(), buffer, hbFeatures.data(), hbFeatures.size());
1368     unsigned len = hb_buffer_get_length(buffer);
1369     if (len == 0) {
1370         return run;
1371     }
1372 
1373     if (direction == HB_DIRECTION_RTL) {
1374         // Put the clusters back in logical order.
1375         // Note that the advances remain ltr.
1376         hb_buffer_reverse(buffer);
1377     }
1378     hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, nullptr);
1379     hb_glyph_position_t* pos = hb_buffer_get_glyph_positions(buffer, nullptr);
1380 
1381     run = ShapedRun(RunHandler::Range(utf8Start - utf8, utf8runLength),
1382                     font.currentFont(), bidi.currentLevel(),
1383                     std::unique_ptr<ShapedGlyph[]>(new ShapedGlyph[len]), len);
1384 
1385     // Undo skhb_position with (1.0/(1<<16)) and scale as needed.
1386     AutoSTArray<32, SkGlyphID> glyphIDs(len);
1387     for (unsigned i = 0; i < len; i++) {
1388         glyphIDs[i] = info[i].codepoint;
1389     }
1390     AutoSTArray<32, SkRect> glyphBounds(len);
1391     SkPaint p;
1392     run.fFont.getBounds(glyphIDs.get(), len, glyphBounds.get(), &p);
1393 
1394     double SkScalarFromHBPosX = +(1.52587890625e-5) * run.fFont.getScaleX();
1395     double SkScalarFromHBPosY = -(1.52587890625e-5);  // HarfBuzz y-up, Skia y-down
1396     SkVector runAdvance = { 0, 0 };
1397     for (unsigned i = 0; i < len; i++) {
1398         ShapedGlyph& glyph = run.fGlyphs[i];
1399         glyph.fID = info[i].codepoint;
1400         glyph.fCluster = info[i].cluster;
1401         glyph.fOffset.fX = pos[i].x_offset * SkScalarFromHBPosX;
1402         glyph.fOffset.fY = pos[i].y_offset * SkScalarFromHBPosY;
1403         glyph.fAdvance.fX = pos[i].x_advance * SkScalarFromHBPosX;
1404         glyph.fAdvance.fY = pos[i].y_advance * SkScalarFromHBPosY;
1405 
1406         glyph.fHasVisual = !glyphBounds[i].isEmpty(); //!font->currentTypeface()->glyphBoundsAreZero(glyph.fID);
1407 #if SK_HB_VERSION_CHECK(1, 5, 0)
1408         glyph.fUnsafeToBreak = info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
1409 #else
1410         glyph.fUnsafeToBreak = false;
1411 #endif
1412         glyph.fMustLineBreakBefore = false;
1413 
1414         runAdvance += glyph.fAdvance;
1415     }
1416     run.fAdvance = runAdvance;
1417 
1418     return run;
1419 }
1420 }  // namespace
1421 
1422 #if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
1423 
1424 #if defined(SK_UNICODE_ICU_IMPLEMENTATION)
1425 #include "modules/skunicode/include/SkUnicode_icu.h"
1426 #endif
1427 
1428 #if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
1429 #include "modules/skunicode/include/SkUnicode_libgrapheme.h"
1430 #endif
1431 
1432 #if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
1433 #include "modules/skunicode/include/SkUnicode_icu4x.h"
1434 #endif
1435 
get_unicode()1436 static sk_sp<SkUnicode> get_unicode() {
1437 #if defined(SK_UNICODE_ICU_IMPLEMENTATION)
1438     if (auto unicode = SkUnicodes::ICU::Make()) {
1439         return unicode;
1440     }
1441 #endif  // defined(SK_UNICODE_ICU_IMPLEMENTATION)
1442 #if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
1443     if (auto unicode = SkUnicodes::Libgrapheme::Make()) {
1444         return unicode;
1445     }
1446 #endif
1447 #if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
1448     if (auto unicode = SkUnicodes::ICU4X::Make()) {
1449         return unicode;
1450     }
1451 #endif
1452     return nullptr;
1453 }
1454 
1455 std::unique_ptr<SkShaper::ScriptRunIterator>
MakeHbIcuScriptRunIterator(const char * utf8,size_t utf8Bytes)1456 SkShaper::MakeHbIcuScriptRunIterator(const char* utf8, size_t utf8Bytes) {
1457     return SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes);
1458 }
1459 
1460 std::unique_ptr<SkShaper::ScriptRunIterator>
MakeSkUnicodeHbScriptRunIterator(const char * utf8,size_t utf8Bytes)1461 SkShaper::MakeSkUnicodeHbScriptRunIterator(const char* utf8, size_t utf8Bytes) {
1462     return SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes);
1463 }
1464 
MakeSkUnicodeHbScriptRunIterator(const char * utf8,size_t utf8Bytes,SkFourByteTag script)1465 std::unique_ptr<SkShaper::ScriptRunIterator> SkShaper::MakeSkUnicodeHbScriptRunIterator(
1466         const char* utf8, size_t utf8Bytes, SkFourByteTag script) {
1467     return SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes, script);
1468 }
1469 
MakeShaperDrivenWrapper(sk_sp<SkFontMgr> fontmgr)1470 std::unique_ptr<SkShaper> SkShaper::MakeShaperDrivenWrapper(sk_sp<SkFontMgr> fontmgr) {
1471     return SkShapers::HB::ShaperDrivenWrapper(get_unicode(), fontmgr);
1472 }
1473 
MakeShapeThenWrap(sk_sp<SkFontMgr> fontmgr)1474 std::unique_ptr<SkShaper> SkShaper::MakeShapeThenWrap(sk_sp<SkFontMgr> fontmgr) {
1475     return SkShapers::HB::ShapeThenWrap(get_unicode(), fontmgr);
1476 }
1477 
PurgeHarfBuzzCache()1478 void SkShaper::PurgeHarfBuzzCache() { SkShapers::HB::PurgeCaches(); }
1479 #endif  // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
1480 
1481 namespace SkShapers::HB {
ShaperDrivenWrapper(sk_sp<SkUnicode> unicode,sk_sp<SkFontMgr> fallback)1482 std::unique_ptr<SkShaper> ShaperDrivenWrapper(sk_sp<SkUnicode> unicode,
1483                                               sk_sp<SkFontMgr> fallback) {
1484     if (!unicode) {
1485         return nullptr;
1486     }
1487     HBBuffer buffer(hb_buffer_create());
1488     if (!buffer) {
1489         SkDEBUGF("Could not create hb_buffer");
1490         return nullptr;
1491     }
1492     return std::make_unique<::ShaperDrivenWrapper>(
1493             unicode, std::move(buffer), std::move(fallback));
1494 }
1495 
ShapeThenWrap(sk_sp<SkUnicode> unicode,sk_sp<SkFontMgr> fallback)1496 std::unique_ptr<SkShaper> ShapeThenWrap(sk_sp<SkUnicode> unicode,
1497                                         sk_sp<SkFontMgr> fallback) {
1498     if (!unicode) {
1499         return nullptr;
1500     }
1501     HBBuffer buffer(hb_buffer_create());
1502     if (!buffer) {
1503         SkDEBUGF("Could not create hb_buffer");
1504         return nullptr;
1505     }
1506     return std::make_unique<::ShapeThenWrap>(
1507             unicode, std::move(buffer), std::move(fallback));
1508 }
1509 
ShapeDontWrapOrReorder(sk_sp<SkUnicode> unicode,sk_sp<SkFontMgr> fallback)1510 std::unique_ptr<SkShaper> ShapeDontWrapOrReorder(sk_sp<SkUnicode> unicode,
1511                                                  sk_sp<SkFontMgr> fallback) {
1512     if (!unicode) {
1513         return nullptr;
1514     }
1515     HBBuffer buffer(hb_buffer_create());
1516     if (!buffer) {
1517         SkDEBUGF("Could not create hb_buffer");
1518         return nullptr;
1519     }
1520     return std::make_unique<::ShapeDontWrapOrReorder>(
1521             unicode, std::move(buffer), std::move(fallback));
1522 }
1523 
ScriptRunIterator(const char * utf8,size_t utf8Bytes)1524 std::unique_ptr<SkShaper::ScriptRunIterator> ScriptRunIterator(const char* utf8, size_t utf8Bytes) {
1525     return std::make_unique<SkUnicodeHbScriptRunIterator>(utf8, utf8Bytes, HB_SCRIPT_UNKNOWN);
1526 }
ScriptRunIterator(const char * utf8,size_t utf8Bytes,SkFourByteTag script)1527 std::unique_ptr<SkShaper::ScriptRunIterator> ScriptRunIterator(const char* utf8,
1528                                                                size_t utf8Bytes,
1529                                                                SkFourByteTag script) {
1530     return std::make_unique<SkUnicodeHbScriptRunIterator>(
1531             utf8, utf8Bytes, hb_script_from_iso15924_tag((hb_tag_t)script));
1532 }
1533 
PurgeCaches()1534 void PurgeCaches() {
1535     HBLockedFaceCache cache = get_hbFace_cache();
1536     cache.reset();
1537 }
1538 }  // namespace SkShapers::HB
1539