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