Coverage Report

Created: 2024-05-20 07:14

/src/skia/modules/skshaper/src/SkShaper_harfbuzz.cpp
Line
Count
Source (jump to first uncovered line)
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
71
0
hb_position_t skhb_position(SkScalar value) {
72
    // Treat HarfBuzz hb_position_t as 16.16 fixed-point.
73
0
    constexpr int kHbPosition1 = 1 << 16;
74
0
    return SkScalarRoundToInt(value * kHbPosition1);
75
0
}
76
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
0
                     void* user_data) {
83
0
    SkFont& font = *reinterpret_cast<SkFont*>(font_data);
84
85
0
    *glyph = font.unicharToGlyph(unicode);
86
0
    return *glyph != 0;
87
0
}
88
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
0
                             void* user_data) {
94
0
  return skhb_glyph(hb_font, font_data, unicode, 0, glyph, user_data);
95
0
}
96
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
0
                             void *user_data) {
104
0
    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
0
    AutoSTMalloc<256, SkUnichar> unicode(count);
109
0
    for (unsigned i = 0; i < count; i++) {
110
0
        unicode[i] = *unicodes;
111
0
        unicodes = SkTAddOffset<const hb_codepoint_t>(unicodes, unicode_stride);
112
0
    }
113
0
    AutoSTMalloc<256, SkGlyphID> glyph(count);
114
0
    font.textToGlyphs(unicode.get(), count * sizeof(SkUnichar), SkTextEncoding::kUTF32,
115
0
                        glyph.get(), count);
116
117
    // Copy the results back to the sparse array.
118
0
    unsigned int done;
119
0
    for (done = 0; done < count && glyph[done] != 0; done++) {
120
0
        *glyphs = glyph[done];
121
0
        glyphs = SkTAddOffset<hb_codepoint_t>(glyphs, glyph_stride);
122
0
    }
123
    // return 'done' to allow HarfBuzz to synthesize with NFC and spaces, return 'count' to avoid
124
0
    return done;
125
0
}
126
127
hb_position_t skhb_glyph_h_advance(hb_font_t* hb_font,
128
                                   void* font_data,
129
                                   hb_codepoint_t hbGlyph,
130
0
                                   void* user_data) {
131
0
    SkFont& font = *reinterpret_cast<SkFont*>(font_data);
132
133
0
    SkScalar advance;
134
0
    SkGlyphID skGlyph = SkTo<SkGlyphID>(hbGlyph);
135
136
0
    font.getWidths(&skGlyph, 1, &advance);
137
0
    if (!font.isSubpixel()) {
138
0
        advance = SkScalarRoundToInt(advance);
139
0
    }
140
0
    return skhb_position(advance);
141
0
}
142
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
0
                           void* user_data) {
151
0
    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
0
    AutoSTMalloc<256, SkGlyphID> glyph(count);
156
0
    for (unsigned i = 0; i < count; i++) {
157
0
        glyph[i] = *glyphs;
158
0
        glyphs = SkTAddOffset<const hb_codepoint_t>(glyphs, glyph_stride);
159
0
    }
160
0
    AutoSTMalloc<256, SkScalar> advance(count);
161
0
    font.getWidths(glyph.get(), count, advance.get());
162
163
0
    if (!font.isSubpixel()) {
164
0
        for (unsigned i = 0; i < count; i++) {
165
0
            advance[i] = SkScalarRoundToInt(advance[i]);
166
0
        }
167
0
    }
168
169
    // Copy the results back to the sparse array.
170
0
    for (unsigned i = 0; i < count; i++) {
171
0
        *advances = skhb_position(advance[i]);
172
0
        advances = SkTAddOffset<hb_position_t>(advances, advance_stride);
173
0
    }
174
0
}
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.
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
0
                             void* user_data) {
187
0
    SkFont& font = *reinterpret_cast<SkFont*>(font_data);
188
0
    SkASSERT(extents);
189
190
0
    SkRect sk_bounds;
191
0
    SkGlyphID skGlyph = SkTo<SkGlyphID>(hbGlyph);
192
193
0
    font.getWidths(&skGlyph, 1, nullptr, &sk_bounds);
194
0
    if (!font.isSubpixel()) {
195
0
        sk_bounds.set(sk_bounds.roundOut());
196
0
    }
197
198
    // Skia is y-down but HarfBuzz is y-up.
199
0
    extents->x_bearing = skhb_position(sk_bounds.fLeft);
200
0
    extents->y_bearing = skhb_position(-sk_bounds.fTop);
201
0
    extents->width = skhb_position(sk_bounds.width());
202
0
    extents->height = skhb_position(-sk_bounds.height());
203
0
    return true;
204
0
}
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::skhb_glyph_extents(hb_font_t*, void*, unsigned int, hb_glyph_extents_t*, void*)
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::skhb_glyph_extents(hb_font_t*, void*, unsigned int, hb_glyph_extents_t*, void*)
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
211
0
hb_font_funcs_t* skhb_get_font_funcs() {
212
0
    static hb_font_funcs_t* const funcs = []{
213
        // HarfBuzz will use the default (parent) implementation if they aren't set.
214
0
        hb_font_funcs_t* const funcs = hb_font_funcs_create();
215
0
        hb_font_funcs_set_variation_glyph_func(funcs, skhb_glyph, nullptr, nullptr);
216
0
        hb_font_funcs_set_nominal_glyph_func(funcs, skhb_nominal_glyph, nullptr, nullptr);
217
0
#if SK_HB_VERSION_CHECK(2, 0, 0)
218
0
        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
0
        hb_font_funcs_set_glyph_h_advance_func(funcs, skhb_glyph_h_advance, nullptr, nullptr);
223
0
#if SK_HB_VERSION_CHECK(1, 8, 6)
224
0
        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
0
        hb_font_funcs_set_glyph_extents_func(funcs, skhb_glyph_extents, nullptr, nullptr);
229
0
        hb_font_funcs_make_immutable(funcs);
230
0
        return funcs;
231
0
    }();
232
0
    SkASSERT(funcs);
233
0
    return funcs;
234
0
}
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::skhb_get_font_funcs()
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::skhb_get_font_funcs()
235
236
0
hb_blob_t* skhb_get_table(hb_face_t* face, hb_tag_t tag, void* user_data) {
237
0
    SkTypeface& typeface = *reinterpret_cast<SkTypeface*>(user_data);
238
239
0
    auto data = typeface.copyTableData(tag);
240
0
    if (!data) {
241
0
        return nullptr;
242
0
    }
243
0
    SkData* rawData = data.release();
244
0
    return hb_blob_create(reinterpret_cast<char*>(rawData->writable_data()), rawData->size(),
245
0
                          HB_MEMORY_MODE_READONLY, rawData, [](void* ctx) {
246
0
                              SkSafeUnref(((SkData*)ctx));
247
0
                          });
248
0
}
249
250
0
HBBlob stream_to_blob(std::unique_ptr<SkStreamAsset> asset) {
251
0
    size_t size = asset->getLength();
252
0
    HBBlob blob;
253
0
    if (const void* base = asset->getMemoryBase()) {
254
0
        blob.reset(hb_blob_create((const char*)base, SkToUInt(size),
255
0
                                  HB_MEMORY_MODE_READONLY, asset.release(),
256
0
                                  [](void* p) { delete (SkStreamAsset*)p; }));
257
0
    } else {
258
        // SkDebugf("Extra SkStreamAsset copy\n");
259
0
        void* ptr = size ? sk_malloc_throw(size) : nullptr;
260
0
        asset->read(ptr, size);
261
0
        blob.reset(hb_blob_create((char*)ptr, SkToUInt(size),
262
0
                                  HB_MEMORY_MODE_READONLY, ptr, sk_free));
263
0
    }
264
0
    SkASSERT(blob);
265
0
    hb_blob_make_immutable(blob.get());
266
0
    return blob;
267
0
}
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::stream_to_blob(std::__1::unique_ptr<SkStreamAsset, std::__1::default_delete<SkStreamAsset> >)
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::stream_to_blob(std::__1::unique_ptr<SkStreamAsset, std::__1::default_delete<SkStreamAsset> >)
268
269
SkDEBUGCODE(static hb_user_data_key_t gDataIdKey;)
270
271
0
HBFace create_hb_face(const SkTypeface& typeface) {
272
0
    int index = 0;
273
0
    std::unique_ptr<SkStreamAsset> typefaceAsset = typeface.openExistingStream(&index);
274
0
    HBFace face;
275
0
    if (typefaceAsset && typefaceAsset->getMemoryBase()) {
276
0
        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
0
        unsigned int num_hb_faces = hb_face_count(blob.get());
281
0
        if (0 < num_hb_faces && (unsigned)index < num_hb_faces) {
282
0
            face.reset(hb_face_create(blob.get(), (unsigned)index));
283
            // Check the number of glyphs as a basic sanitization step.
284
0
            if (face && hb_face_get_glyph_count(face.get()) == 0) {
285
0
                face.reset();
286
0
            }
287
0
        }
288
0
    }
289
0
    if (!face) {
290
0
        face.reset(hb_face_create_for_tables(
291
0
            skhb_get_table,
292
0
            const_cast<SkTypeface*>(SkRef(&typeface)),
293
0
            [](void* user_data){ SkSafeUnref(reinterpret_cast<SkTypeface*>(user_data)); }));
294
0
        hb_face_set_index(face.get(), (unsigned)index);
295
0
    }
296
0
    SkASSERT(face);
297
0
    if (!face) {
298
0
        return nullptr;
299
0
    }
300
0
    hb_face_set_upem(face.get(), typeface.getUnitsPerEm());
301
302
0
    SkDEBUGCODE(
303
0
        hb_face_set_user_data(face.get(), &gDataIdKey, const_cast<SkTypeface*>(&typeface),
304
0
                              nullptr, false);
305
0
    )
306
307
0
    return face;
308
0
}
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::create_hb_face(SkTypeface const&)
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::create_hb_face(SkTypeface const&)
309
310
0
HBFont create_typeface_hb_font(const SkTypeface& typeface) {
311
0
    HBFace face(create_hb_face(typeface));
312
0
    if (!face) {
313
0
        return nullptr;
314
0
    }
315
316
0
    HBFont otFont(hb_font_create(face.get()));
317
0
    SkASSERT(otFont);
318
0
    if (!otFont) {
319
0
        return nullptr;
320
0
    }
321
0
    hb_ot_font_set_funcs(otFont.get());
322
0
    int axis_count = typeface.getVariationDesignPosition(nullptr, 0);
323
0
    if (axis_count > 0) {
324
0
        AutoSTMalloc<4, SkFontArguments::VariationPosition::Coordinate> axis_values(axis_count);
325
0
        if (typeface.getVariationDesignPosition(axis_values, axis_count) == axis_count) {
326
0
            hb_font_set_variations(otFont.get(),
327
0
                                   reinterpret_cast<hb_variation_t*>(axis_values.get()),
328
0
                                   axis_count);
329
0
        }
330
0
    }
331
332
0
    return otFont;
333
0
}
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::create_typeface_hb_font(SkTypeface const&)
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::create_typeface_hb_font(SkTypeface const&)
334
335
0
HBFont create_sub_hb_font(const SkFont& font, const HBFont& typefaceFont) {
336
0
    SkDEBUGCODE(
337
0
        hb_face_t* face = hb_font_get_face(typefaceFont.get());
338
0
        void* dataId = hb_face_get_user_data(face, &gDataIdKey);
339
0
        SkASSERT(dataId == font.getTypeface());
340
0
    )
341
342
    // Creating a sub font means that non-available functions
343
    // are found from the parent.
344
0
    HBFont skFont(hb_font_create_sub_font(typefaceFont.get()));
345
0
    hb_font_set_funcs(skFont.get(), skhb_get_font_funcs(),
346
0
                      reinterpret_cast<void *>(new SkFont(font)),
347
0
                      [](void* user_data){ delete reinterpret_cast<SkFont*>(user_data); });
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::create_sub_hb_font(SkFont const&, std::__1::unique_ptr<hb_font_t, SkOverloadedFunctionObject<void (hb_font_t*), &hb_font_destroy> > const&)::$_0::operator()(void*) const
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::create_sub_hb_font(SkFont const&, std::__1::unique_ptr<hb_font_t, SkOverloadedFunctionObject<void (hb_font_t*), &hb_font_destroy> > const&)::$_1::operator()(void*) const
348
0
    int scale = skhb_position(font.getSize());
349
0
    hb_font_set_scale(skFont.get(), scale, scale);
350
351
0
    return skFont;
352
0
}
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::create_sub_hb_font(SkFont const&, std::__1::unique_ptr<hb_font_t, SkOverloadedFunctionObject<void (hb_font_t*), &hb_font_destroy> > const&)
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::create_sub_hb_font(SkFont const&, std::__1::unique_ptr<hb_font_t, SkOverloadedFunctionObject<void (hb_font_t*), &hb_font_destroy> > const&)
353
354
/** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */
355
0
static inline SkUnichar utf8_next(const char** ptr, const char* end) {
356
0
    SkUnichar val = SkUTF::NextUTF8(ptr, end);
357
0
    return val < 0 ? 0xFFFD : val;
358
0
}
359
360
class SkUnicodeHbScriptRunIterator final: public SkShaper::ScriptRunIterator {
361
public:
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
0
            , fCurrentScript(defaultScript) {}
369
0
    hb_script_t hb_script_for_unichar(SkUnichar u) {
370
0
         return hb_unicode_script(hb_unicode_funcs_get_default(), u);
371
0
    }
372
0
    void consume() override {
373
0
        SkASSERT(fCurrent < fEnd);
374
0
        SkUnichar u = utf8_next(&fCurrent, fEnd);
375
0
        fCurrentScript = hb_script_for_unichar(u);
376
0
        while (fCurrent < fEnd) {
377
0
            const char* prev = fCurrent;
378
0
            u = utf8_next(&fCurrent, fEnd);
379
0
            const hb_script_t script = hb_script_for_unichar(u);
380
0
            if (script != fCurrentScript) {
381
0
                if (fCurrentScript == HB_SCRIPT_INHERITED || fCurrentScript == HB_SCRIPT_COMMON) {
382
0
                    fCurrentScript = script;
383
0
                } else if (script == HB_SCRIPT_INHERITED || script == HB_SCRIPT_COMMON) {
384
0
                    continue;
385
0
                } else {
386
0
                    fCurrent = prev;
387
0
                    break;
388
0
                }
389
0
            }
390
0
        }
391
0
        if (fCurrentScript == HB_SCRIPT_INHERITED) {
392
0
            fCurrentScript = HB_SCRIPT_COMMON;
393
0
        }
394
0
    }
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::SkUnicodeHbScriptRunIterator::consume()
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::SkUnicodeHbScriptRunIterator::consume()
395
0
    size_t endOfCurrentRun() const override {
396
0
        return fCurrent - fBegin;
397
0
    }
398
0
    bool atEnd() const override {
399
0
        return fCurrent == fEnd;
400
0
    }
401
402
0
    SkFourByteTag currentScript() const override {
403
0
        return SkSetFourByteTag(HB_UNTAG(fCurrentScript));
404
0
    }
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:
414
0
    void insert(SkShaper::RunIterator* runIterator, int priority) {
415
0
        fEntries.insert({runIterator, priority});
416
0
    }
417
418
0
    bool advanceRuns() {
419
0
        const SkShaper::RunIterator* leastRun = fEntries.peek().runIterator;
420
0
        if (leastRun->atEnd()) {
421
0
            SkASSERT(this->allRunsAreAtEnd());
422
0
            return false;
423
0
        }
424
0
        const size_t leastEnd = leastRun->endOfCurrentRun();
425
0
        SkShaper::RunIterator* currentRun = nullptr;
426
0
        SkDEBUGCODE(size_t previousEndOfCurrentRun);
427
0
        while ((currentRun = fEntries.peek().runIterator)->endOfCurrentRun() <= leastEnd) {
428
0
            int priority = fEntries.peek().priority;
429
0
            fEntries.pop();
430
0
            SkDEBUGCODE(previousEndOfCurrentRun = currentRun->endOfCurrentRun());
431
0
            currentRun->consume();
432
0
            SkASSERT(previousEndOfCurrentRun < currentRun->endOfCurrentRun());
433
0
            fEntries.insert({currentRun, priority});
434
0
        }
435
0
        return true;
436
0
    }
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::RunIteratorQueue::advanceRuns()
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::RunIteratorQueue::advanceRuns()
437
438
0
    size_t endOfCurrentRun() const {
439
0
        return fEntries.peek().runIterator->endOfCurrentRun();
440
0
    }
441
442
private:
443
0
    bool allRunsAreAtEnd() const {
444
0
        for (int i = 0; i < fEntries.count(); ++i) {
445
0
            if (!fEntries.at(i).runIterator->atEnd()) {
446
0
                return false;
447
0
            }
448
0
        }
449
0
        return true;
450
0
    }
451
452
    struct Entry {
453
        SkShaper::RunIterator* runIterator;
454
        int priority;
455
    };
456
0
    static bool CompareEntry(Entry const& a, Entry const& b) {
457
0
        size_t aEnd = a.runIterator->endOfCurrentRun();
458
0
        size_t bEnd = b.runIterator->endOfCurrentRun();
459
0
        return aEnd  < bEnd || (aEnd == bEnd && a.priority < b.priority);
460
0
    }
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 {
476
    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
0
    {}
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
502
0
constexpr bool is_LTR(SkBidiIterator::Level level) {
503
0
    return (level & 1) == 0;
504
0
}
505
506
void append(SkShaper::RunHandler* handler, const SkShaper::RunHandler::RunInfo& runInfo,
507
0
                   const ShapedRun& run, size_t startGlyphIndex, size_t endGlyphIndex) {
508
0
    SkASSERT(startGlyphIndex <= endGlyphIndex);
509
0
    const size_t glyphLen = endGlyphIndex - startGlyphIndex;
510
511
0
    const auto buffer = handler->runBuffer(runInfo);
512
0
    SkASSERT(buffer.glyphs);
513
0
    SkASSERT(buffer.positions);
514
515
0
    SkVector advance = {0,0};
516
0
    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
0
        const ShapedGlyph& glyph = run.fGlyphs[is_LTR(run.fLevel) ? startGlyphIndex + i
519
0
                                                                  : endGlyphIndex - 1 - i];
520
0
        buffer.glyphs[i] = glyph.fID;
521
0
        if (buffer.offsets) {
522
0
            buffer.positions[i] = advance + buffer.point;
523
0
            buffer.offsets[i] = glyph.fOffset;
524
0
        } else {
525
0
            buffer.positions[i] = advance + buffer.point + glyph.fOffset;
526
0
        }
527
0
        if (buffer.clusters) {
528
0
            buffer.clusters[i] = glyph.fCluster;
529
0
        }
530
0
        advance += glyph.fAdvance;
531
0
    }
532
0
    handler->commitRunBuffer(runInfo);
533
0
}
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::append(SkShaper::RunHandler*, SkShaper::RunHandler::RunInfo const&, (anonymous namespace)::ShapedRun const&, unsigned long, unsigned long)
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::append(SkShaper::RunHandler*, SkShaper::RunHandler::RunInfo const&, (anonymous namespace)::ShapedRun const&, unsigned long, unsigned long)
534
535
0
void emit(SkUnicode* unicode, const ShapedLine& line, SkShaper::RunHandler* handler) {
536
    // Reorder the runs and glyphs per line and write them out.
537
0
    handler->beginLine();
538
539
0
    int numRuns = line.runs.size();
540
0
    AutoSTMalloc<4, SkBidiIterator::Level> runLevels(numRuns);
541
0
    for (int i = 0; i < numRuns; ++i) {
542
0
        runLevels[i] = line.runs[i].fLevel;
543
0
    }
544
0
    AutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
545
0
    unicode->reorderVisual(runLevels, numRuns, logicalFromVisual);
546
547
0
    for (int i = 0; i < numRuns; ++i) {
548
0
        int logicalIndex = logicalFromVisual[i];
549
550
0
        const auto& run = line.runs[logicalIndex];
551
0
        const SkShaper::RunHandler::RunInfo info = {
552
0
            run.fFont,
553
0
            run.fLevel,
554
0
            run.fAdvance,
555
0
            run.fNumGlyphs,
556
0
            run.fUtf8Range
557
0
        };
558
0
        handler->runInfo(info);
559
0
    }
560
0
    handler->commitRunInfo();
561
0
    for (int i = 0; i < numRuns; ++i) {
562
0
        int logicalIndex = logicalFromVisual[i];
563
564
0
        const auto& run = line.runs[logicalIndex];
565
0
        const SkShaper::RunHandler::RunInfo info = {
566
0
            run.fFont,
567
0
            run.fLevel,
568
0
            run.fAdvance,
569
0
            run.fNumGlyphs,
570
0
            run.fUtf8Range
571
0
        };
572
0
        append(handler, info, run, 0, run.fNumGlyphs);
573
0
    }
574
575
0
    handler->commitLine();
576
0
}
577
578
struct ShapedRunGlyphIterator {
579
    ShapedRunGlyphIterator(const TArray<ShapedRun>& origRuns)
580
        : fRuns(&origRuns), fRunIndex(0), fGlyphIndex(0)
581
0
    { }
582
583
    ShapedRunGlyphIterator(const ShapedRunGlyphIterator& that) = default;
584
    ShapedRunGlyphIterator& operator=(const ShapedRunGlyphIterator& that) = default;
585
0
    bool operator==(const ShapedRunGlyphIterator& that) const {
586
0
        return fRuns == that.fRuns &&
587
0
               fRunIndex == that.fRunIndex &&
588
0
               fGlyphIndex == that.fGlyphIndex;
589
0
    }
590
0
    bool operator!=(const ShapedRunGlyphIterator& that) const {
591
0
        return fRuns != that.fRuns ||
592
0
               fRunIndex != that.fRunIndex ||
593
0
               fGlyphIndex != that.fGlyphIndex;
594
0
    }
595
596
0
    ShapedGlyph* next() {
597
0
        const TArray<ShapedRun>& runs = *fRuns;
598
0
        SkASSERT(fRunIndex < runs.size());
599
0
        SkASSERT(fGlyphIndex < runs[fRunIndex].fNumGlyphs);
600
601
0
        ++fGlyphIndex;
602
0
        if (fGlyphIndex == runs[fRunIndex].fNumGlyphs) {
603
0
            fGlyphIndex = 0;
604
0
            ++fRunIndex;
605
0
            if (fRunIndex >= runs.size()) {
606
0
                return nullptr;
607
0
            }
608
0
        }
609
0
        return &runs[fRunIndex].fGlyphs[fGlyphIndex];
610
0
    }
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::ShapedRunGlyphIterator::next()
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::ShapedRunGlyphIterator::next()
611
612
0
    ShapedGlyph* current() {
613
0
        const TArray<ShapedRun>& runs = *fRuns;
614
0
        if (fRunIndex >= runs.size()) {
615
0
            return nullptr;
616
0
        }
617
0
        return &runs[fRunIndex].fGlyphs[fGlyphIndex];
618
0
    }
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
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
0
    , fUndefinedLanguage(hb_language_from_string("und", -1)) {
735
#if defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
736
    SkASSERT(fUnicode);
737
#endif
738
0
}
739
740
#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
741
void ShaperHarfBuzz::shape(const char* utf8,
742
                           size_t utf8Bytes,
743
                           const SkFont& srcFont,
744
                           bool leftToRight,
745
                           SkScalar width,
746
0
                           RunHandler* handler) const {
747
0
    SkBidiIterator::Level defaultLevel = leftToRight ? SkBidiIterator::kLTR : SkBidiIterator::kRTL;
748
0
    std::unique_ptr<BiDiRunIterator> bidi(
749
0
            SkShapers::unicode::BidiRunIterator(fUnicode, utf8, utf8Bytes, defaultLevel));
750
751
0
    if (!bidi) {
752
0
        return;
753
0
    }
754
755
0
    std::unique_ptr<LanguageRunIterator> language(MakeStdLanguageRunIterator(utf8, utf8Bytes));
756
0
    if (!language) {
757
0
        return;
758
0
    }
759
760
0
    std::unique_ptr<ScriptRunIterator> script(SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes));
761
0
    if (!script) {
762
0
        return;
763
0
    }
764
765
0
    std::unique_ptr<FontRunIterator> font(
766
0
                MakeFontMgrRunIterator(utf8, utf8Bytes, srcFont, fFontMgr));
767
0
    if (!font) {
768
0
        return;
769
0
    }
770
771
0
    this->shape(utf8, utf8Bytes, *font, *bidi, *script, *language, width, handler);
772
0
}
773
774
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
0
                           RunHandler* handler) const {
782
0
    this->shape(utf8, utf8Bytes, font, bidi, script, language, nullptr, 0, width, handler);
783
0
}
784
#endif  // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
785
786
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
0
                           RunHandler* handler) const {
796
0
    SkASSERT(handler);
797
0
    RunIteratorQueue runSegmenter;
798
0
    runSegmenter.insert(&font,     3); // The font iterator is always run last in case of tie.
799
0
    runSegmenter.insert(&bidi,     2);
800
0
    runSegmenter.insert(&script,   1);
801
0
    runSegmenter.insert(&language, 0);
802
803
0
    this->wrap(utf8, utf8Bytes, bidi, language, script, font, runSegmenter,
804
0
               features, featuresSize, width, handler);
805
0
}
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::ShaperHarfBuzz::shape(char const*, unsigned long, SkShaper::FontRunIterator&, SkShaper::BiDiRunIterator&, SkShaper::ScriptRunIterator&, SkShaper::LanguageRunIterator&, SkShaper::Feature const*, unsigned long, float, SkShaper::RunHandler*) const
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::ShaperHarfBuzz::shape(char const*, unsigned long, SkShaper::FontRunIterator&, SkShaper::BiDiRunIterator&, SkShaper::ScriptRunIterator&, SkShaper::LanguageRunIterator&, SkShaper::Feature const*, unsigned long, float, SkShaper::RunHandler*) const
806
807
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
0
{
817
0
    ShapedLine line;
818
819
0
    const char* utf8Start = nullptr;
820
0
    const char* utf8End = utf8;
821
0
    SkUnicodeBreak lineBreakIterator;
822
0
    SkString currentLanguage;
823
0
    while (runSegmenter.advanceRuns()) {  // For each item
824
0
        utf8Start = utf8End;
825
0
        utf8End = utf8 + runSegmenter.endOfCurrentRun();
826
827
0
        ShapedRun model(RunHandler::Range(), SkFont(), 0, nullptr, 0);
828
0
        bool modelNeedsRegenerated = true;
829
0
        int modelGlyphOffset = 0;
830
831
0
        struct TextProps {
832
0
            int glyphLen = 0;
833
0
            SkVector advance = {0, 0};
834
0
        };
835
        // map from character position to [safe to break, glyph position, advance]
836
0
        std::unique_ptr<TextProps[]> modelText;
837
0
        int modelTextOffset = 0;
838
0
        SkVector modelAdvanceOffset = {0, 0};
839
840
0
        while (utf8Start < utf8End) {  // While there are still code points left in this item
841
0
            size_t utf8runLength = utf8End - utf8Start;
842
0
            if (modelNeedsRegenerated) {
843
0
                model = shape(utf8, utf8Bytes,
844
0
                              utf8Start, utf8End,
845
0
                              bidi, language, script, font,
846
0
                              features, featuresSize);
847
0
                modelGlyphOffset = 0;
848
849
0
                SkVector advance = {0, 0};
850
0
                modelText = std::make_unique<TextProps[]>(utf8runLength + 1);
851
0
                size_t modelStartCluster = utf8Start - utf8;
852
0
                size_t previousCluster = 0;
853
0
                for (size_t i = 0; i < model.fNumGlyphs; ++i) {
854
0
                    SkASSERT(modelStartCluster <= model.fGlyphs[i].fCluster);
855
0
                    SkASSERT(                     model.fGlyphs[i].fCluster < (size_t)(utf8End - utf8));
856
0
                    if (!model.fGlyphs[i].fUnsafeToBreak) {
857
                        // Store up to the first glyph in the cluster.
858
0
                        size_t currentCluster = model.fGlyphs[i].fCluster - modelStartCluster;
859
0
                        if (previousCluster != currentCluster) {
860
0
                            previousCluster  = currentCluster;
861
0
                            modelText[currentCluster].glyphLen = i;
862
0
                            modelText[currentCluster].advance = advance;
863
0
                        }
864
0
                    }
865
0
                    advance += model.fGlyphs[i].fAdvance;
866
0
                }
867
                // Assume it is always safe to break after the end of an item
868
0
                modelText[utf8runLength].glyphLen = model.fNumGlyphs;
869
0
                modelText[utf8runLength].advance = model.fAdvance;
870
0
                modelTextOffset = 0;
871
0
                modelAdvanceOffset = {0, 0};
872
0
                modelNeedsRegenerated = false;
873
0
            }
874
875
            // TODO: break iterator per item, but just reset position if needed?
876
            // Maybe break iterator with model?
877
0
            if (!lineBreakIterator || !currentLanguage.equals(language.currentLanguage())) {
878
0
                currentLanguage = language.currentLanguage();
879
0
                lineBreakIterator = fUnicode->makeBreakIterator(currentLanguage.c_str(),
880
0
                                                                SkUnicode::BreakType::kLines);
881
0
                if (!lineBreakIterator) {
882
0
                    return;
883
0
                }
884
0
            }
885
0
            if (!lineBreakIterator->setText(utf8Start, utf8runLength)) {
886
0
                return;
887
0
            }
888
0
            SkBreakIterator& breakIterator = *lineBreakIterator;
889
890
0
            ShapedRun best(RunHandler::Range(), SkFont(), 0, nullptr, 0,
891
0
                           { SK_ScalarNegativeInfinity, SK_ScalarNegativeInfinity });
892
0
            bool bestIsInvalid = true;
893
0
            bool bestUsesModelForGlyphs = false;
894
0
            SkScalar widthLeft = width - line.fAdvance.fX;
895
896
0
            for (int32_t breakIteratorCurrent = breakIterator.next();
897
0
                 !breakIterator.isDone();
898
0
                 breakIteratorCurrent = breakIterator.next())
899
0
            {
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
0
                bool candidateUsesModelForGlyphs = false;
904
0
                ShapedRun candidate = [&](const TextProps& props){
905
0
                    if (props.glyphLen) {
906
0
                        candidateUsesModelForGlyphs = true;
907
0
                        return ShapedRun(RunHandler::Range(utf8Start - utf8, breakIteratorCurrent),
908
0
                                         font.currentFont(), bidi.currentLevel(),
909
0
                                         std::unique_ptr<ShapedGlyph[]>(),
910
0
                                         props.glyphLen - modelGlyphOffset,
911
0
                                         props.advance - modelAdvanceOffset);
912
0
                    } else {
913
0
                        return shape(utf8, utf8Bytes,
914
0
                                     utf8Start, utf8Start + breakIteratorCurrent,
915
0
                                     bidi, language, script, font,
916
0
                                     features, featuresSize);
917
0
                    }
918
0
                }(modelText[breakIteratorCurrent + modelTextOffset]);
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::ShaperDrivenWrapper::wrap(char const*, unsigned long, SkShaper::BiDiRunIterator const&, SkShaper::LanguageRunIterator const&, SkShaper::ScriptRunIterator const&, SkShaper::FontRunIterator const&, (anonymous namespace)::RunIteratorQueue&, SkShaper::Feature const*, unsigned long, float, SkShaper::RunHandler*) const::$_0::operator()((anonymous namespace)::ShaperDrivenWrapper::wrap(char const*, unsigned long, SkShaper::BiDiRunIterator const&, SkShaper::LanguageRunIterator const&, SkShaper::ScriptRunIterator const&, SkShaper::FontRunIterator const&, (anonymous namespace)::RunIteratorQueue&, SkShaper::Feature const*, unsigned long, float, SkShaper::RunHandler*) const::TextProps const&) const
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::ShaperDrivenWrapper::wrap(char const*, unsigned long, SkShaper::BiDiRunIterator const&, SkShaper::LanguageRunIterator const&, SkShaper::ScriptRunIterator const&, SkShaper::FontRunIterator const&, (anonymous namespace)::RunIteratorQueue&, SkShaper::Feature const*, unsigned long, float, SkShaper::RunHandler*) const::$_2::operator()((anonymous namespace)::ShaperDrivenWrapper::wrap(char const*, unsigned long, SkShaper::BiDiRunIterator const&, SkShaper::LanguageRunIterator const&, SkShaper::ScriptRunIterator const&, SkShaper::FontRunIterator const&, (anonymous namespace)::RunIteratorQueue&, SkShaper::Feature const*, unsigned long, float, SkShaper::RunHandler*) const::TextProps const&) const
919
0
                auto score = [widthLeft](const ShapedRun& run) -> SkScalar {
920
0
                    if (run.fAdvance.fX < widthLeft) {
921
0
                        return run.fUtf8Range.size();
922
0
                    } else {
923
0
                        return widthLeft - run.fAdvance.fX;
924
0
                    }
925
0
                };
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::ShaperDrivenWrapper::wrap(char const*, unsigned long, SkShaper::BiDiRunIterator const&, SkShaper::LanguageRunIterator const&, SkShaper::ScriptRunIterator const&, SkShaper::FontRunIterator const&, (anonymous namespace)::RunIteratorQueue&, SkShaper::Feature const*, unsigned long, float, SkShaper::RunHandler*) const::$_1::operator()((anonymous namespace)::ShapedRun const&) const
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::ShaperDrivenWrapper::wrap(char const*, unsigned long, SkShaper::BiDiRunIterator const&, SkShaper::LanguageRunIterator const&, SkShaper::ScriptRunIterator const&, SkShaper::FontRunIterator const&, (anonymous namespace)::RunIteratorQueue&, SkShaper::Feature const*, unsigned long, float, SkShaper::RunHandler*) const::$_3::operator()((anonymous namespace)::ShapedRun const&) const
926
0
                if (bestIsInvalid || score(best) < score(candidate)) {
927
0
                    best = std::move(candidate);
928
0
                    bestIsInvalid = false;
929
0
                    bestUsesModelForGlyphs = candidateUsesModelForGlyphs;
930
0
                }
931
0
            }
932
933
            // If nothing fit (best score is negative) and the line is not empty
934
0
            if (width < line.fAdvance.fX + best.fAdvance.fX && !line.runs.empty()) {
935
0
                emit(fUnicode.get(), line, handler);
936
0
                line.runs.clear();
937
0
                line.fAdvance = {0, 0};
938
0
            } else {
939
0
                if (bestUsesModelForGlyphs) {
940
0
                    best.fGlyphs = std::make_unique<ShapedGlyph[]>(best.fNumGlyphs);
941
0
                    memcpy(best.fGlyphs.get(), model.fGlyphs.get() + modelGlyphOffset,
942
0
                           best.fNumGlyphs * sizeof(ShapedGlyph));
943
0
                    modelGlyphOffset += best.fNumGlyphs;
944
0
                    modelTextOffset += best.fUtf8Range.size();
945
0
                    modelAdvanceOffset += best.fAdvance;
946
0
                } else {
947
0
                    modelNeedsRegenerated = true;
948
0
                }
949
0
                utf8Start += best.fUtf8Range.size();
950
0
                line.fAdvance += best.fAdvance;
951
0
                line.runs.emplace_back(std::move(best));
952
953
                // If item broken, emit line (prevent remainder from accidentally fitting)
954
0
                if (utf8Start != utf8End) {
955
0
                    emit(fUnicode.get(), line, handler);
956
0
                    line.runs.clear();
957
0
                    line.fAdvance = {0, 0};
958
0
                }
959
0
            }
960
0
        }
961
0
    }
962
0
    emit(fUnicode.get(), line, handler);
963
0
}
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::ShaperDrivenWrapper::wrap(char const*, unsigned long, SkShaper::BiDiRunIterator const&, SkShaper::LanguageRunIterator const&, SkShaper::ScriptRunIterator const&, SkShaper::FontRunIterator const&, (anonymous namespace)::RunIteratorQueue&, SkShaper::Feature const*, unsigned long, float, SkShaper::RunHandler*) const
Unexecuted instantiation: SkShaper_harfbuzz.cpp:(anonymous namespace)::ShaperDrivenWrapper::wrap(char const*, unsigned long, SkShaper::BiDiRunIterator const&, SkShaper::LanguageRunIterator const&, SkShaper::ScriptRunIterator const&, SkShaper::FontRunIterator const&, (anonymous namespace)::RunIteratorQueue&, SkShaper::Feature const*, unsigned long, float, SkShaper::RunHandler*) const
964
965
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
0
{
975
0
    TArray<ShapedRun> runs;
976
0
{
977
0
    SkString currentLanguage;
978
0
    SkUnicodeBreak lineBreakIterator;
979
0
    SkUnicodeBreak graphemeBreakIterator;
980
0
    bool needIteratorInit = true;
981
0
    const char* utf8Start = nullptr;
982
0
    const char* utf8End = utf8;
983
0
    while (runSegmenter.advanceRuns()) {
984
0
        utf8Start = utf8End;
985
0
        utf8End = utf8 + runSegmenter.endOfCurrentRun();
986
987
0
        runs.emplace_back(shape(utf8, utf8Bytes,
988
0
                                utf8Start, utf8End,
989
0
                                bidi, language, script, font,
990
0
                                features, featuresSize));
991
0
        ShapedRun& run = runs.back();
992
993
0
        if (needIteratorInit || !currentLanguage.equals(language.currentLanguage())) {
994
0
            currentLanguage = language.currentLanguage();
995
0
            lineBreakIterator = fUnicode->makeBreakIterator(currentLanguage.c_str(),
996
0
                                                            SkUnicode::BreakType::kLines);
997
0
            if (!lineBreakIterator) {
998
0
                return;
999
0
            }
1000
0
            graphemeBreakIterator = fUnicode->makeBreakIterator(currentLanguage.c_str(),
1001
0
                                                                SkUnicode::BreakType::kGraphemes);
1002
0
            if (!graphemeBreakIterator) {
1003
0
                return;
1004
0
            }
1005
0
            needIteratorInit = false;
1006
0
        }
1007
0
        size_t utf8runLength = utf8End - utf8Start;
1008
0
        if (!lineBreakIterator->setText(utf8Start, utf8runLength)) {
1009
0
            return;
1010
0
        }
1011
0
        if (!graphemeBreakIterator->setText(utf8Start, utf8runLength)) {
1012
0
            return;
1013
0
        }
1014
1015
0
        uint32_t previousCluster = 0xFFFFFFFF;
1016
0
        for (size_t i = 0; i < run.fNumGlyphs; ++i) {
1017
0
            ShapedGlyph& glyph = run.fGlyphs[i];
1018
0
            int32_t glyphCluster = glyph.fCluster;
1019
1020
0
            int32_t lineBreakIteratorCurrent = lineBreakIterator->current();
1021
0
            while (!lineBreakIterator->isDone() && lineBreakIteratorCurrent < glyphCluster)
1022
0
            {
1023
0
                lineBreakIteratorCurrent = lineBreakIterator->next();
1024
0
            }
1025
0
            glyph.fMayLineBreakBefore = glyph.fCluster != previousCluster &&
1026
0
                                        lineBreakIteratorCurrent == glyphCluster;
1027
1028
0
            int32_t graphemeBreakIteratorCurrent = graphemeBreakIterator->current();
1029
0
            while (!graphemeBreakIterator->isDone() && graphemeBreakIteratorCurrent < glyphCluster)
1030
0
            {
1031
0
                graphemeBreakIteratorCurrent = graphemeBreakIterator->next();
1032
0
            }
1033
0
            glyph.fGraphemeBreakBefore = glyph.fCluster != previousCluster &&
1034
0
                                         graphemeBreakIteratorCurrent == glyphCluster;
1035
1036
0
            previousCluster = glyph.fCluster;
1037
0
        }
1038
0
    }
1039
0
}
1040
1041
// Iterate over the glyphs in logical order to find potential line lengths.
1042
0
{
1043
    /** The position of the beginning of the line. */
1044
0
    ShapedRunGlyphIterator beginning(runs);
1045
1046
    /** The position of the candidate line break. */
1047
0
    ShapedRunGlyphIterator candidateLineBreak(runs);
1048
0
    SkScalar candidateLineBreakWidth = 0;
1049
1050
    /** The position of the candidate grapheme break. */
1051
0
    ShapedRunGlyphIterator candidateGraphemeBreak(runs);
1052
0
    SkScalar candidateGraphemeBreakWidth = 0;
1053
1054
    /** The position of the current location. */
1055
0
    ShapedRunGlyphIterator current(runs);
1056
0
    SkScalar currentWidth = 0;
1057
0
    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
0
        if (current != beginning) {
1061
0
            if (glyph->fGraphemeBreakBefore || glyph->fMayLineBreakBefore) {
1062
                // TODO: preserve line breaks <= grapheme breaks
1063
                // and prevent line breaks inside graphemes
1064
0
                candidateGraphemeBreak = current;
1065
0
                candidateGraphemeBreakWidth = currentWidth;
1066
0
                if (glyph->fMayLineBreakBefore) {
1067
0
                    candidateLineBreak = current;
1068
0
                    candidateLineBreakWidth = currentWidth;
1069
0
                }
1070
0
            }
1071
0
        }
1072
1073
0
        SkScalar glyphWidth = glyph->fAdvance.fX;
1074
        // Break when overwidth, the glyph has a visual representation, and some space is used.
1075
0
        if (width < currentWidth + glyphWidth && glyph->fHasVisual && candidateGraphemeBreakWidth > 0){
1076
0
            if (candidateLineBreak != beginning) {
1077
0
                beginning = candidateLineBreak;
1078
0
                currentWidth -= candidateLineBreakWidth;
1079
0
                candidateGraphemeBreakWidth -= candidateLineBreakWidth;
1080
0
                candidateLineBreakWidth = 0;
1081
0
            } else if (candidateGraphemeBreak != beginning) {
1082
0
                beginning = candidateGraphemeBreak;
1083
0
                candidateLineBreak = beginning;
1084
0
                currentWidth -= candidateGraphemeBreakWidth;
1085
0
                candidateGraphemeBreakWidth = 0;
1086
0
                candidateLineBreakWidth = 0;
1087
0
            } else {
1088
0
                SK_ABORT("");
1089
0
            }
1090
1091
0
            if (width < currentWidth) {
1092
0
                if (width < candidateGraphemeBreakWidth) {
1093
0
                    candidateGraphemeBreak = candidateLineBreak;
1094
0
                    candidateGraphemeBreakWidth = candidateLineBreakWidth;
1095
0
                }
1096
0
                current = candidateGraphemeBreak;
1097
0
                currentWidth = candidateGraphemeBreakWidth;
1098
0
            }
1099
1100
0
            glyph = beginning.current();
1101
0
            if (glyph) {
1102
0
                glyph->fMustLineBreakBefore = true;
1103
0
            }
1104
1105
0
        } else {
1106
0
            current.next();
1107
0
            currentWidth += glyphWidth;
1108
0
        }
1109
0
    }
1110
0
}
1111
1112
// Reorder the runs and glyphs per line and write them out.
1113
0
{
1114
0
    ShapedRunGlyphIterator previousBreak(runs);
1115
0
    ShapedRunGlyphIterator glyphIterator(runs);
1116
0
    int previousRunIndex = -1;
1117
0
    while (glyphIterator.current()) {
1118
0
        const ShapedRunGlyphIterator current = glyphIterator;
1119
0
        ShapedGlyph* nextGlyph = glyphIterator.next();
1120
1121
0
        if (previousRunIndex != current.fRunIndex) {
1122
0
            SkFontMetrics metrics;
1123
0
            runs[current.fRunIndex].fFont.getMetrics(&metrics);
1124
0
            previousRunIndex = current.fRunIndex;
1125
0
        }
1126
1127
        // Nothing can be written until the baseline is known.
1128
0
        if (!(nextGlyph == nullptr || nextGlyph->fMustLineBreakBefore)) {
1129
0
            continue;
1130
0
        }
1131
1132
0
        int numRuns = current.fRunIndex - previousBreak.fRunIndex + 1;
1133
0
        AutoSTMalloc<4, SkBidiIterator::Level> runLevels(numRuns);
1134
0
        for (int i = 0; i < numRuns; ++i) {
1135
0
            runLevels[i] = runs[previousBreak.fRunIndex + i].fLevel;
1136
0
        }
1137
0
        AutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
1138
0
        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
0
        handler->beginLine();
1144
1145
0
        struct SubRun { const ShapedRun& run; size_t startGlyphIndex; size_t endGlyphIndex; };
1146
0
        auto makeSubRun = [&runs, &previousBreak, &current, &logicalFromVisual](size_t visualIndex){
1147
0
            int logicalIndex = previousBreak.fRunIndex + logicalFromVisual[visualIndex];
1148
0
            const auto& run = runs[logicalIndex];
1149
0
            size_t startGlyphIndex = (logicalIndex == previousBreak.fRunIndex)
1150
0
                                   ? previousBreak.fGlyphIndex
1151
0
                                   : 0;
1152
0
            size_t endGlyphIndex = (logicalIndex == current.fRunIndex)
1153
0
                                 ? current.fGlyphIndex + 1
1154
0
                                 : run.fNumGlyphs;
1155
0
            return SubRun{ run, startGlyphIndex, endGlyphIndex };
1156
0
        };
1157
0
        auto makeRunInfo = [](const SubRun& sub) {
1158
0
            uint32_t startUtf8 = sub.run.fGlyphs[sub.startGlyphIndex].fCluster;
1159
0
            uint32_t endUtf8 = (sub.endGlyphIndex < sub.run.fNumGlyphs)
1160
0
                             ? sub.run.fGlyphs[sub.endGlyphIndex].fCluster
1161
0
                             : sub.run.fUtf8Range.end();
1162
1163
0
            SkVector advance = SkVector::Make(0, 0);
1164
0
            for (size_t i = sub.startGlyphIndex; i < sub.endGlyphIndex; ++i) {
1165
0
                advance += sub.run.fGlyphs[i].fAdvance;
1166
0
            }
1167
1168
0
            return RunHandler::RunInfo{
1169
0
                sub.run.fFont,
1170
0
                sub.run.fLevel,
1171
0
                advance,
1172
0
                sub.endGlyphIndex - sub.startGlyphIndex,
1173
0
                RunHandler::Range(startUtf8, endUtf8 - startUtf8)
1174
0
            };
1175
0
        };
1176
1177
0
        for (int i = 0; i < numRuns; ++i) {
1178
0
            handler->runInfo(makeRunInfo(makeSubRun(i)));
1179
0
        }
1180
0
        handler->commitRunInfo();
1181
0
        for (int i = 0; i < numRuns; ++i) {
1182
0
            SubRun sub = makeSubRun(i);
1183
0
            append(handler, makeRunInfo(sub), sub.run, sub.startGlyphIndex, sub.endGlyphIndex);
1184
0
        }
1185
1186
0
        handler->commitLine();
1187
1188
0
        previousRunIndex = -1;
1189
0
        previousBreak = glyphIterator;
1190
0
    }
1191
0
}
1192
0
}
1193
1194
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
0
{
1204
0
    sk_ignore_unused_variable(width);
1205
0
    TArray<ShapedRun> runs;
1206
1207
0
    const char* utf8Start = nullptr;
1208
0
    const char* utf8End = utf8;
1209
0
    while (runSegmenter.advanceRuns()) {
1210
0
        utf8Start = utf8End;
1211
0
        utf8End = utf8 + runSegmenter.endOfCurrentRun();
1212
1213
0
        runs.emplace_back(shape(utf8, utf8Bytes,
1214
0
                                utf8Start, utf8End,
1215
0
                                bidi, language, script, font,
1216
0
                                features, featuresSize));
1217
0
    }
1218
1219
0
    handler->beginLine();
1220
0
    for (const auto& run : runs) {
1221
0
        const RunHandler::RunInfo info = {
1222
0
            run.fFont,
1223
0
            run.fLevel,
1224
0
            run.fAdvance,
1225
0
            run.fNumGlyphs,
1226
0
            run.fUtf8Range
1227
0
        };
1228
0
        handler->runInfo(info);
1229
0
    }
1230
0
    handler->commitRunInfo();
1231
0
    for (const auto& run : runs) {
1232
0
        const RunHandler::RunInfo info = {
1233
0
            run.fFont,
1234
0
            run.fLevel,
1235
0
            run.fAdvance,
1236
0
            run.fNumGlyphs,
1237
0
            run.fUtf8Range
1238
0
        };
1239
0
        append(handler, info, run, 0, run.fNumGlyphs);
1240
0
    }
1241
0
    handler->commitLine();
1242
0
}
1243
1244
class HBLockedFaceCache {
1245
public:
1246
    HBLockedFaceCache(SkLRUCache<SkTypefaceID, HBFont>& lruCache, SkMutex& mutex)
1247
        : fLRUCache(lruCache), fMutex(mutex)
1248
0
    {
1249
0
        fMutex.acquire();
1250
0
    }
1251
    HBLockedFaceCache(const HBLockedFaceCache&) = delete;
1252
    HBLockedFaceCache& operator=(const HBLockedFaceCache&) = delete;
1253
    HBLockedFaceCache& operator=(HBLockedFaceCache&&) = delete;
1254
1255
0
    ~HBLockedFaceCache() {
1256
0
        fMutex.release();
1257
0
    }
1258
1259
0
    HBFont* find(SkTypefaceID fontId) {
1260
0
        return fLRUCache.find(fontId);
1261
0
    }
1262
0
    HBFont* insert(SkTypefaceID fontId, HBFont hbFont) {
1263
0
        return fLRUCache.insert(fontId, std::move(hbFont));
1264
0
    }
1265
0
    void reset() {
1266
0
        fLRUCache.reset();
1267
0
    }
1268
private:
1269
    SkLRUCache<SkTypefaceID, HBFont>& fLRUCache;
1270
    SkMutex& fMutex;
1271
};
1272
0
static HBLockedFaceCache get_hbFace_cache() {
1273
0
    static SkMutex gHBFaceCacheMutex;
1274
0
    static SkLRUCache<SkTypefaceID, HBFont> gHBFaceCache(100);
1275
0
    return HBLockedFaceCache(gHBFaceCache, gHBFaceCacheMutex);
1276
0
}
1277
1278
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
0
{
1288
0
    size_t utf8runLength = utf8End - utf8Start;
1289
0
    ShapedRun run(RunHandler::Range(utf8Start - utf8, utf8runLength),
1290
0
                  font.currentFont(), bidi.currentLevel(), nullptr, 0);
1291
1292
0
    hb_buffer_t* buffer = fBuffer.get();
1293
0
    SkAutoTCallVProc<hb_buffer_t, hb_buffer_clear_contents> autoClearBuffer(buffer);
1294
0
    hb_buffer_set_content_type(buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
1295
0
    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
0
    hb_buffer_add_utf8(buffer, utf8, utf8Start - utf8, utf8Start - utf8, 0);
1304
1305
    // Populate the hb_buffer directly with utf8 cluster indexes.
1306
0
    const char* utf8Current = utf8Start;
1307
0
    while (utf8Current < utf8End) {
1308
0
        unsigned int cluster = utf8Current - utf8;
1309
0
        hb_codepoint_t u = utf8_next(&utf8Current, utf8End);
1310
0
        hb_buffer_add(buffer, u, cluster);
1311
0
    }
1312
1313
    // Add postcontext.
1314
0
    hb_buffer_add_utf8(buffer, utf8Current, utf8 + utf8Bytes - utf8Current, 0, 0);
1315
1316
0
    hb_direction_t direction = is_LTR(bidi.currentLevel()) ? HB_DIRECTION_LTR:HB_DIRECTION_RTL;
1317
0
    hb_buffer_set_direction(buffer, direction);
1318
0
    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
0
    hb_language_t hbLanguage = hb_language_from_string(language.currentLanguage(), -1);
1323
0
    if (hbLanguage == HB_LANGUAGE_INVALID) {
1324
0
        hbLanguage = fUndefinedLanguage;
1325
0
    }
1326
0
    hb_buffer_set_language(buffer, hbLanguage);
1327
0
    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
0
    HBFont hbFont;
1335
0
    {
1336
0
        HBLockedFaceCache cache = get_hbFace_cache();
1337
0
        SkTypefaceID dataId = font.currentFont().getTypeface()->uniqueID();
1338
0
        HBFont* typefaceFontCached = cache.find(dataId);
1339
0
        if (!typefaceFontCached) {
1340
0
            HBFont typefaceFont(create_typeface_hb_font(*font.currentFont().getTypeface()));
1341
0
            typefaceFontCached = cache.insert(dataId, std::move(typefaceFont));
1342
0
        }
1343
0
        hbFont = create_sub_hb_font(font.currentFont(), *typefaceFontCached);
1344
0
    }
1345
0
    if (!hbFont) {
1346
0
        return run;
1347
0
    }
1348
1349
0
    STArray<32, hb_feature_t> hbFeatures;
1350
0
    for (const auto& feature : SkSpan(features, featuresSize)) {
1351
0
        if (feature.end < SkTo<size_t>(utf8Start - utf8) ||
1352
0
                          SkTo<size_t>(utf8End   - utf8)  <= feature.start)
1353
0
        {
1354
0
            continue;
1355
0
        }
1356
0
        if (feature.start <= SkTo<size_t>(utf8Start - utf8) &&
1357
0
                             SkTo<size_t>(utf8End   - utf8) <= feature.end)
1358
0
        {
1359
0
            hbFeatures.push_back({ (hb_tag_t)feature.tag, feature.value,
1360
0
                                   HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END});
1361
0
        } else {
1362
0
            hbFeatures.push_back({ (hb_tag_t)feature.tag, feature.value,
1363
0
                                   SkTo<unsigned>(feature.start), SkTo<unsigned>(feature.end)});
1364
0
        }
1365
0
    }
1366
1367
0
    hb_shape(hbFont.get(), buffer, hbFeatures.data(), hbFeatures.size());
1368
0
    unsigned len = hb_buffer_get_length(buffer);
1369
0
    if (len == 0) {
1370
0
        return run;
1371
0
    }
1372
1373
0
    if (direction == HB_DIRECTION_RTL) {
1374
        // Put the clusters back in logical order.
1375
        // Note that the advances remain ltr.
1376
0
        hb_buffer_reverse(buffer);
1377
0
    }
1378
0
    hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, nullptr);
1379
0
    hb_glyph_position_t* pos = hb_buffer_get_glyph_positions(buffer, nullptr);
1380
1381
0
    run = ShapedRun(RunHandler::Range(utf8Start - utf8, utf8runLength),
1382
0
                    font.currentFont(), bidi.currentLevel(),
1383
0
                    std::unique_ptr<ShapedGlyph[]>(new ShapedGlyph[len]), len);
1384
1385
    // Undo skhb_position with (1.0/(1<<16)) and scale as needed.
1386
0
    AutoSTArray<32, SkGlyphID> glyphIDs(len);
1387
0
    for (unsigned i = 0; i < len; i++) {
1388
0
        glyphIDs[i] = info[i].codepoint;
1389
0
    }
1390
0
    AutoSTArray<32, SkRect> glyphBounds(len);
1391
0
    SkPaint p;
1392
0
    run.fFont.getBounds(glyphIDs.get(), len, glyphBounds.get(), &p);
1393
1394
0
    double SkScalarFromHBPosX = +(1.52587890625e-5) * run.fFont.getScaleX();
1395
0
    double SkScalarFromHBPosY = -(1.52587890625e-5);  // HarfBuzz y-up, Skia y-down
1396
0
    SkVector runAdvance = { 0, 0 };
1397
0
    for (unsigned i = 0; i < len; i++) {
1398
0
        ShapedGlyph& glyph = run.fGlyphs[i];
1399
0
        glyph.fID = info[i].codepoint;
1400
0
        glyph.fCluster = info[i].cluster;
1401
0
        glyph.fOffset.fX = pos[i].x_offset * SkScalarFromHBPosX;
1402
0
        glyph.fOffset.fY = pos[i].y_offset * SkScalarFromHBPosY;
1403
0
        glyph.fAdvance.fX = pos[i].x_advance * SkScalarFromHBPosX;
1404
0
        glyph.fAdvance.fY = pos[i].y_advance * SkScalarFromHBPosY;
1405
1406
0
        glyph.fHasVisual = !glyphBounds[i].isEmpty(); //!font->currentTypeface()->glyphBoundsAreZero(glyph.fID);
1407
0
#if SK_HB_VERSION_CHECK(1, 5, 0)
1408
0
        glyph.fUnsafeToBreak = info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
1409
#else
1410
        glyph.fUnsafeToBreak = false;
1411
#endif
1412
0
        glyph.fMustLineBreakBefore = false;
1413
1414
0
        runAdvance += glyph.fAdvance;
1415
0
    }
1416
0
    run.fAdvance = runAdvance;
1417
1418
0
    return run;
1419
0
}
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
1436
0
static sk_sp<SkUnicode> get_unicode() {
1437
0
#if defined(SK_UNICODE_ICU_IMPLEMENTATION)
1438
0
    if (auto unicode = SkUnicodes::ICU::Make()) {
1439
0
        return unicode;
1440
0
    }
1441
0
#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
0
    return nullptr;
1453
0
}
1454
1455
std::unique_ptr<SkShaper::ScriptRunIterator>
1456
0
SkShaper::MakeHbIcuScriptRunIterator(const char* utf8, size_t utf8Bytes) {
1457
0
    return SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes);
1458
0
}
1459
1460
std::unique_ptr<SkShaper::ScriptRunIterator>
1461
0
SkShaper::MakeSkUnicodeHbScriptRunIterator(const char* utf8, size_t utf8Bytes) {
1462
0
    return SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes);
1463
0
}
1464
1465
std::unique_ptr<SkShaper::ScriptRunIterator> SkShaper::MakeSkUnicodeHbScriptRunIterator(
1466
0
        const char* utf8, size_t utf8Bytes, SkFourByteTag script) {
1467
0
    return SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes, script);
1468
0
}
1469
1470
0
std::unique_ptr<SkShaper> SkShaper::MakeShaperDrivenWrapper(sk_sp<SkFontMgr> fontmgr) {
1471
0
    return SkShapers::HB::ShaperDrivenWrapper(get_unicode(), fontmgr);
1472
0
}
1473
1474
0
std::unique_ptr<SkShaper> SkShaper::MakeShapeThenWrap(sk_sp<SkFontMgr> fontmgr) {
1475
0
    return SkShapers::HB::ShapeThenWrap(get_unicode(), fontmgr);
1476
0
}
1477
1478
0
void SkShaper::PurgeHarfBuzzCache() { SkShapers::HB::PurgeCaches(); }
1479
#endif  // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
1480
1481
namespace SkShapers::HB {
1482
std::unique_ptr<SkShaper> ShaperDrivenWrapper(sk_sp<SkUnicode> unicode,
1483
0
                                              sk_sp<SkFontMgr> fallback) {
1484
0
    if (!unicode) {
1485
0
        return nullptr;
1486
0
    }
1487
0
    HBBuffer buffer(hb_buffer_create());
1488
0
    if (!buffer) {
1489
0
        SkDEBUGF("Could not create hb_buffer");
1490
0
        return nullptr;
1491
0
    }
1492
0
    return std::make_unique<::ShaperDrivenWrapper>(
1493
0
            unicode, std::move(buffer), std::move(fallback));
1494
0
}
Unexecuted instantiation: SkShapers::HB::ShaperDrivenWrapper(sk_sp<SkUnicode>, sk_sp<SkFontMgr>)
Unexecuted instantiation: SkShapers::HB::ShaperDrivenWrapper(sk_sp<SkUnicode>, sk_sp<SkFontMgr>)
1495
1496
std::unique_ptr<SkShaper> ShapeThenWrap(sk_sp<SkUnicode> unicode,
1497
0
                                        sk_sp<SkFontMgr> fallback) {
1498
0
    if (!unicode) {
1499
0
        return nullptr;
1500
0
    }
1501
0
    HBBuffer buffer(hb_buffer_create());
1502
0
    if (!buffer) {
1503
0
        SkDEBUGF("Could not create hb_buffer");
1504
0
        return nullptr;
1505
0
    }
1506
0
    return std::make_unique<::ShapeThenWrap>(
1507
0
            unicode, std::move(buffer), std::move(fallback));
1508
0
}
Unexecuted instantiation: SkShapers::HB::ShapeThenWrap(sk_sp<SkUnicode>, sk_sp<SkFontMgr>)
Unexecuted instantiation: SkShapers::HB::ShapeThenWrap(sk_sp<SkUnicode>, sk_sp<SkFontMgr>)
1509
1510
std::unique_ptr<SkShaper> ShapeDontWrapOrReorder(sk_sp<SkUnicode> unicode,
1511
0
                                                 sk_sp<SkFontMgr> fallback) {
1512
0
    if (!unicode) {
1513
0
        return nullptr;
1514
0
    }
1515
0
    HBBuffer buffer(hb_buffer_create());
1516
0
    if (!buffer) {
1517
0
        SkDEBUGF("Could not create hb_buffer");
1518
0
        return nullptr;
1519
0
    }
1520
0
    return std::make_unique<::ShapeDontWrapOrReorder>(
1521
0
            unicode, std::move(buffer), std::move(fallback));
1522
0
}
Unexecuted instantiation: SkShapers::HB::ShapeDontWrapOrReorder(sk_sp<SkUnicode>, sk_sp<SkFontMgr>)
Unexecuted instantiation: SkShapers::HB::ShapeDontWrapOrReorder(sk_sp<SkUnicode>, sk_sp<SkFontMgr>)
1523
1524
0
std::unique_ptr<SkShaper::ScriptRunIterator> ScriptRunIterator(const char* utf8, size_t utf8Bytes) {
1525
0
    return std::make_unique<SkUnicodeHbScriptRunIterator>(utf8, utf8Bytes, HB_SCRIPT_UNKNOWN);
1526
0
}
1527
std::unique_ptr<SkShaper::ScriptRunIterator> ScriptRunIterator(const char* utf8,
1528
                                                               size_t utf8Bytes,
1529
0
                                                               SkFourByteTag script) {
1530
0
    return std::make_unique<SkUnicodeHbScriptRunIterator>(
1531
0
            utf8, utf8Bytes, hb_script_from_iso15924_tag((hb_tag_t)script));
1532
0
}
1533
1534
0
void PurgeCaches() {
1535
0
    HBLockedFaceCache cache = get_hbFace_cache();
1536
0
    cache.reset();
1537
0
}
1538
}  // namespace SkShapers::HB