1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkBitmaskEnum.h"
9 #include "SkFont.h"
10 #include "SkFontArguments.h"
11 #include "SkFontMetrics.h"
12 #include "SkFontMgr.h"
13 #include "SkMakeUnique.h"
14 #include "SkMalloc.h"
15 #include "SkPoint.h"
16 #include "SkRefCnt.h"
17 #include "SkScalar.h"
18 #include "SkShaper.h"
19 #include "SkSpan.h"
20 #include "SkStream.h"
21 #include "SkString.h"
22 #include "SkTArray.h"
23 #include "SkTDPQueue.h"
24 #include "SkTFitsIn.h"
25 #include "SkTLazy.h"
26 #include "SkTemplates.h"
27 #include "SkTo.h"
28 #include "SkTypeface.h"
29 #include "SkTypes.h"
30 #include "SkUTF.h"
31
32 #include <hb.h>
33 #include <hb-ot.h>
34 #include <unicode/ubrk.h>
35 #include <unicode/ubidi.h>
36 #include <unicode/ustring.h>
37 #include <unicode/urename.h>
38 #include <unicode/utext.h>
39 #include <unicode/utypes.h>
40
41 #include <cstring>
42 #include <locale>
43 #include <memory>
44 #include <utility>
45
46 #if defined(SK_USING_THIRD_PARTY_ICU)
47 #include "SkLoadICU.h"
48 #endif
49
50 namespace skstd {
51 template <> struct is_bitmask_enum<hb_buffer_flags_t> : std::true_type {};
52 }
53
54 namespace {
55 template <class T, void(*P)(T*)> using resource = std::unique_ptr<T, SkFunctionWrapper<void, T, P>>;
56 using HBBlob = resource<hb_blob_t , hb_blob_destroy >;
57 using HBFace = resource<hb_face_t , hb_face_destroy >;
58 using HBFont = resource<hb_font_t , hb_font_destroy >;
59 using HBBuffer = resource<hb_buffer_t , hb_buffer_destroy>;
60 using ICUBiDi = resource<UBiDi , ubidi_close >;
61 using ICUBrk = resource<UBreakIterator, ubrk_close >;
62
stream_to_blob(std::unique_ptr<SkStreamAsset> asset)63 HBBlob stream_to_blob(std::unique_ptr<SkStreamAsset> asset) {
64 size_t size = asset->getLength();
65 HBBlob blob;
66 if (const void* base = asset->getMemoryBase()) {
67 blob.reset(hb_blob_create((char*)base, SkToUInt(size),
68 HB_MEMORY_MODE_READONLY, asset.release(),
69 [](void* p) { delete (SkStreamAsset*)p; }));
70 } else {
71 // SkDebugf("Extra SkStreamAsset copy\n");
72 void* ptr = size ? sk_malloc_throw(size) : nullptr;
73 asset->read(ptr, size);
74 blob.reset(hb_blob_create((char*)ptr, SkToUInt(size),
75 HB_MEMORY_MODE_READONLY, ptr, sk_free));
76 }
77 SkASSERT(blob);
78 hb_blob_make_immutable(blob.get());
79 return blob;
80 }
81
skhb_position(SkScalar value)82 hb_position_t skhb_position(SkScalar value) {
83 // Treat HarfBuzz hb_position_t as 16.16 fixed-point.
84 constexpr int kHbPosition1 = 1 << 16;
85 return SkScalarRoundToInt(value * kHbPosition1);
86 }
87
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)88 hb_bool_t skhb_glyph(hb_font_t* hb_font,
89 void* font_data,
90 hb_codepoint_t unicode,
91 hb_codepoint_t variation_selector,
92 hb_codepoint_t* glyph,
93 void* user_data) {
94 SkFont& font = *reinterpret_cast<SkFont*>(font_data);
95
96 *glyph = font.unicharToGlyph(unicode);
97 return *glyph != 0;
98 }
99
skhb_nominal_glyph(hb_font_t * hb_font,void * font_data,hb_codepoint_t unicode,hb_codepoint_t * glyph,void * user_data)100 hb_bool_t skhb_nominal_glyph(hb_font_t* hb_font,
101 void* font_data,
102 hb_codepoint_t unicode,
103 hb_codepoint_t* glyph,
104 void* user_data) {
105 return skhb_glyph(hb_font, font_data, unicode, 0, glyph, user_data);
106 }
107
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)108 unsigned skhb_nominal_glyphs(hb_font_t *hb_font, void *font_data,
109 unsigned int count,
110 const hb_codepoint_t *unicodes,
111 unsigned int unicode_stride,
112 hb_codepoint_t *glyphs,
113 unsigned int glyph_stride,
114 void *user_data) {
115 SkFont& font = *reinterpret_cast<SkFont*>(font_data);
116
117 // Batch call textToGlyphs since entry cost is not cheap.
118 // Copy requred because textToGlyphs is dense and hb is strided.
119 SkAutoSTMalloc<256, SkUnichar> unicode(count);
120 for (unsigned i = 0; i < count; i++) {
121 unicode[i] = *unicodes;
122 unicodes = SkTAddOffset<const hb_codepoint_t>(unicodes, unicode_stride);
123 }
124 SkAutoSTMalloc<256, SkGlyphID> glyph(count);
125 font.textToGlyphs(unicode.get(), count * sizeof(SkUnichar), kUTF32_SkTextEncoding,
126 glyph.get(), count);
127
128 // Copy the results back to the sparse array.
129 for (unsigned i = 0; i < count; i++) {
130 *glyphs = glyph[i];
131 glyphs = SkTAddOffset<hb_codepoint_t>(glyphs, glyph_stride);
132 }
133 // TODO: supposed to return index of first 0?
134 return count;
135 }
136
skhb_glyph_h_advance(hb_font_t * hb_font,void * font_data,hb_codepoint_t codepoint,void * user_data)137 hb_position_t skhb_glyph_h_advance(hb_font_t* hb_font,
138 void* font_data,
139 hb_codepoint_t codepoint,
140 void* user_data) {
141 SkFont& font = *reinterpret_cast<SkFont*>(font_data);
142
143 SkScalar advance;
144 SkGlyphID glyph = SkTo<SkGlyphID>(codepoint);
145
146 font.getWidths(&glyph, 1, &advance);
147 if (!font.isSubpixel()) {
148 advance = SkScalarRoundToInt(advance);
149 }
150 return skhb_position(advance);
151 }
152
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)153 void skhb_glyph_h_advances(hb_font_t* hb_font,
154 void* font_data,
155 unsigned count,
156 const hb_codepoint_t* glyphs,
157 unsigned int glyph_stride,
158 hb_position_t* advances,
159 unsigned int advance_stride,
160 void* user_data) {
161 SkFont& font = *reinterpret_cast<SkFont*>(font_data);
162
163 // Batch call getWidths since entry cost is not cheap.
164 // Copy requred because getWidths is dense and hb is strided.
165 SkAutoSTMalloc<256, SkGlyphID> glyph(count);
166 for (unsigned i = 0; i < count; i++) {
167 glyph[i] = *glyphs;
168 glyphs = SkTAddOffset<const hb_codepoint_t>(glyphs, glyph_stride);
169 }
170 SkAutoSTMalloc<256, SkScalar> advance(count);
171 font.getWidths(glyph.get(), count, advance.get());
172
173 if (!font.isSubpixel()) {
174 for (unsigned i = 0; i < count; i++) {
175 advance[i] = SkScalarRoundToInt(advance[i]);
176 }
177 }
178
179 // Copy the results back to the sparse array.
180 for (unsigned i = 0; i < count; i++) {
181 *advances = skhb_position(advance[i]);
182 advances = SkTAddOffset<hb_position_t>(advances, advance_stride);
183 }
184 }
185
186 // HarfBuzz callback to retrieve glyph extents, mainly used by HarfBuzz for
187 // fallback mark positioning, i.e. the situation when the font does not have
188 // mark anchors or other mark positioning rules, but instead HarfBuzz is
189 // supposed to heuristically place combining marks around base glyphs. HarfBuzz
190 // does this by measuring "ink boxes" of glyphs, and placing them according to
191 // 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 codepoint,hb_glyph_extents_t * extents,void * user_data)192 hb_bool_t skhb_glyph_extents(hb_font_t* hb_font,
193 void* font_data,
194 hb_codepoint_t codepoint,
195 hb_glyph_extents_t* extents,
196 void* user_data) {
197 SkFont& font = *reinterpret_cast<SkFont*>(font_data);
198
199 SkASSERT(codepoint < 0xFFFFu);
200 SkASSERT(extents);
201
202 SkRect sk_bounds;
203 SkGlyphID glyph = codepoint;
204
205 font.getWidths(&glyph, 1, nullptr, &sk_bounds);
206 if (!font.isSubpixel()) {
207 sk_bounds.set(sk_bounds.roundOut());
208 }
209
210 // Skia is y-down but HarfBuzz is y-up.
211 extents->x_bearing = skhb_position(sk_bounds.fLeft);
212 extents->y_bearing = skhb_position(-sk_bounds.fTop);
213 extents->width = skhb_position(sk_bounds.width());
214 extents->height = skhb_position(-sk_bounds.height());
215 return true;
216 }
217
218 #define SK_HB_VERSION_CHECK(x, y, z) \
219 (HB_VERSION_MAJOR > (x)) || \
220 (HB_VERSION_MAJOR == (x) && HB_VERSION_MINOR > (y)) || \
221 (HB_VERSION_MAJOR == (x) && HB_VERSION_MINOR == (y) && HB_VERSION_MICRO >= (z))
222
skhb_get_font_funcs()223 hb_font_funcs_t* skhb_get_font_funcs() {
224 static hb_font_funcs_t* const funcs = []{
225 // HarfBuzz will use the default (parent) implementation if they aren't set.
226 hb_font_funcs_t* const funcs = hb_font_funcs_create();
227 hb_font_funcs_set_variation_glyph_func(funcs, skhb_glyph, nullptr, nullptr);
228 hb_font_funcs_set_nominal_glyph_func(funcs, skhb_nominal_glyph, nullptr, nullptr);
229 #if SK_HB_VERSION_CHECK(2, 0, 0)
230 hb_font_funcs_set_nominal_glyphs_func(funcs, skhb_nominal_glyphs, nullptr, nullptr);
231 #else
232 sk_ignore_unused_variable(skhb_nominal_glyphs);
233 #endif
234 hb_font_funcs_set_glyph_h_advance_func(funcs, skhb_glyph_h_advance, nullptr, nullptr);
235 #if SK_HB_VERSION_CHECK(1, 8, 6)
236 hb_font_funcs_set_glyph_h_advances_func(funcs, skhb_glyph_h_advances, nullptr, nullptr);
237 #else
238 sk_ignore_unused_variable(skhb_glyph_h_advances);
239 #endif
240 hb_font_funcs_set_glyph_extents_func(funcs, skhb_glyph_extents, nullptr, nullptr);
241 hb_font_funcs_make_immutable(funcs);
242 return funcs;
243 }();
244 SkASSERT(funcs);
245 return funcs;
246 }
247
skhb_get_table(hb_face_t * face,hb_tag_t tag,void * user_data)248 hb_blob_t* skhb_get_table(hb_face_t* face, hb_tag_t tag, void* user_data) {
249 SkTypeface& typeface = *reinterpret_cast<SkTypeface*>(user_data);
250
251 const size_t tableSize = typeface.getTableSize(tag);
252 if (!tableSize) {
253 return nullptr;
254 }
255
256 void* buffer = sk_malloc_throw(tableSize);
257 if (!buffer) {
258 return nullptr;
259 }
260
261 size_t actualSize = typeface.getTableData(tag, 0, tableSize, buffer);
262 if (tableSize != actualSize) {
263 sk_free(buffer);
264 return nullptr;
265 }
266
267 return hb_blob_create(reinterpret_cast<char*>(buffer), tableSize,
268 HB_MEMORY_MODE_WRITABLE, buffer, sk_free);
269 }
270
create_hb_font(const SkFont & font)271 HBFont create_hb_font(const SkFont& font) {
272 int index;
273 std::unique_ptr<SkStreamAsset> typefaceAsset = font.getTypeface()->openStream(&index);
274 HBFace face;
275 if (!typefaceAsset) {
276 face.reset(hb_face_create_for_tables(
277 skhb_get_table,
278 reinterpret_cast<void *>(font.refTypeface().release()),
279 [](void* user_data){ SkSafeUnref(reinterpret_cast<SkTypeface*>(user_data)); }));
280 } else {
281 HBBlob blob(stream_to_blob(std::move(typefaceAsset)));
282 face.reset(hb_face_create(blob.get(), (unsigned)index));
283 }
284 SkASSERT(face);
285 if (!face) {
286 return nullptr;
287 }
288 hb_face_set_index(face.get(), (unsigned)index);
289 hb_face_set_upem(face.get(), font.getTypeface()->getUnitsPerEm());
290
291 HBFont otFont(hb_font_create(face.get()));
292 SkASSERT(otFont);
293 if (!otFont) {
294 return nullptr;
295 }
296 hb_ot_font_set_funcs(otFont.get());
297 int axis_count = font.getTypeface()->getVariationDesignPosition(nullptr, 0);
298 if (axis_count > 0) {
299 SkAutoSTMalloc<4, SkFontArguments::VariationPosition::Coordinate> axis_values(axis_count);
300 if (font.getTypeface()->getVariationDesignPosition(axis_values, axis_count) == axis_count) {
301 hb_font_set_variations(otFont.get(),
302 reinterpret_cast<hb_variation_t*>(axis_values.get()),
303 axis_count);
304 }
305 }
306
307 // Creating a sub font means that non-available functions
308 // are found from the parent.
309 HBFont skFont(hb_font_create_sub_font(otFont.get()));
310 hb_font_set_funcs(skFont.get(), skhb_get_font_funcs(),
311 reinterpret_cast<void *>(new SkFont(font)),
312 [](void* user_data){ delete reinterpret_cast<SkFont*>(user_data); });
313 int scale = skhb_position(font.getSize());
314 hb_font_set_scale(skFont.get(), scale, scale);
315
316 return skFont;
317 }
318
319 /** this version replaces invalid utf-8 sequences with code point U+FFFD. */
utf8_next(const char ** ptr,const char * end)320 static inline SkUnichar utf8_next(const char** ptr, const char* end) {
321 SkUnichar val = SkUTF::NextUTF8(ptr, end);
322 if (val < 0) {
323 return 0xFFFD; // REPLACEMENT CHARACTER
324 }
325 return val;
326 }
327
328 class RunIterator {
329 public:
~RunIterator()330 virtual ~RunIterator() {}
331 virtual void consume() = 0;
332 // Pointer one past the last (utf8) element in the current run.
333 virtual const char* endOfCurrentRun() const = 0;
334 virtual bool atEnd() const = 0;
operator <(const RunIterator & that) const335 bool operator<(const RunIterator& that) const {
336 return this->endOfCurrentRun() < that.endOfCurrentRun();
337 }
338 };
339
340 class BiDiRunIterator : public RunIterator {
341 public:
Make(const char * utf8,size_t utf8Bytes,UBiDiLevel level)342 static SkTLazy<BiDiRunIterator> Make(const char* utf8, size_t utf8Bytes, UBiDiLevel level) {
343 SkTLazy<BiDiRunIterator> ret;
344
345 // ubidi only accepts utf16 (though internally it basically works on utf32 chars).
346 // We want an ubidi_setPara(UBiDi*, UText*, UBiDiLevel, UBiDiLevel*, UErrorCode*);
347 if (!SkTFitsIn<int32_t>(utf8Bytes)) {
348 SkDebugf("Bidi error: text too long");
349 return ret;
350 }
351
352 UErrorCode status = U_ZERO_ERROR;
353
354 // Getting the length like this seems to always set U_BUFFER_OVERFLOW_ERROR
355 int32_t utf16Units;
356 u_strFromUTF8(nullptr, 0, &utf16Units, utf8, utf8Bytes, &status);
357 status = U_ZERO_ERROR;
358 std::unique_ptr<UChar[]> utf16(new UChar[utf16Units]);
359 u_strFromUTF8(utf16.get(), utf16Units, nullptr, utf8, utf8Bytes, &status);
360 if (U_FAILURE(status)) {
361 SkDebugf("Invalid utf8 input: %s", u_errorName(status));
362 return ret;
363 }
364
365 ICUBiDi bidi(ubidi_openSized(utf16Units, 0, &status));
366 if (U_FAILURE(status)) {
367 SkDebugf("Bidi error: %s", u_errorName(status));
368 return ret;
369 }
370 SkASSERT(bidi);
371
372 // The required lifetime of utf16 isn't well documented.
373 // It appears it isn't used after ubidi_setPara except through ubidi_getText.
374 ubidi_setPara(bidi.get(), utf16.get(), utf16Units, level, nullptr, &status);
375 if (U_FAILURE(status)) {
376 SkDebugf("Bidi error: %s", u_errorName(status));
377 return ret;
378 }
379
380 ret.init(utf8, utf8 + utf8Bytes, std::move(bidi));
381 return ret;
382 }
BiDiRunIterator(const char * utf8,const char * end,ICUBiDi bidi)383 BiDiRunIterator(const char* utf8, const char* end, ICUBiDi bidi)
384 : fBidi(std::move(bidi))
385 , fEndOfCurrentRun(utf8)
386 , fEndOfAllRuns(end)
387 , fUTF16LogicalPosition(0)
388 , fLevel(UBIDI_DEFAULT_LTR)
389 {}
consume()390 void consume() override {
391 SkASSERT(fUTF16LogicalPosition < ubidi_getLength(fBidi.get()));
392 int32_t endPosition = ubidi_getLength(fBidi.get());
393 fLevel = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
394 SkUnichar u = utf8_next(&fEndOfCurrentRun, fEndOfAllRuns);
395 fUTF16LogicalPosition += SkUTF::ToUTF16(u);
396 UBiDiLevel level;
397 while (fUTF16LogicalPosition < endPosition) {
398 level = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
399 if (level != fLevel) {
400 break;
401 }
402 u = utf8_next(&fEndOfCurrentRun, fEndOfAllRuns);
403 fUTF16LogicalPosition += SkUTF::ToUTF16(u);
404 }
405 }
endOfCurrentRun() const406 const char* endOfCurrentRun() const override {
407 return fEndOfCurrentRun;
408 }
atEnd() const409 bool atEnd() const override {
410 return fUTF16LogicalPosition == ubidi_getLength(fBidi.get());
411 }
412
currentLevel() const413 UBiDiLevel currentLevel() const {
414 return fLevel;
415 }
416 private:
417 ICUBiDi fBidi;
418 const char* fEndOfCurrentRun;
419 const char* fEndOfAllRuns;
420 int32_t fUTF16LogicalPosition;
421 UBiDiLevel fLevel;
422 };
423
424 class ScriptRunIterator : public RunIterator {
425 public:
Make(const char * utf8,size_t utf8Bytes,hb_unicode_funcs_t * hbUnicode)426 static SkTLazy<ScriptRunIterator> Make(const char* utf8, size_t utf8Bytes,
427 hb_unicode_funcs_t* hbUnicode)
428 {
429 SkTLazy<ScriptRunIterator> ret;
430 ret.init(utf8, utf8Bytes, hbUnicode);
431 return ret;
432 }
ScriptRunIterator(const char * utf8,size_t utf8Bytes,hb_unicode_funcs_t * hbUnicode)433 ScriptRunIterator(const char* utf8, size_t utf8Bytes, hb_unicode_funcs_t* hbUnicode)
434 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
435 , fHBUnicode(hbUnicode)
436 , fCurrentScript(HB_SCRIPT_UNKNOWN)
437 {}
consume()438 void consume() override {
439 SkASSERT(fCurrent < fEnd);
440 SkUnichar u = utf8_next(&fCurrent, fEnd);
441 fCurrentScript = hb_unicode_script(fHBUnicode, u);
442 while (fCurrent < fEnd) {
443 const char* prev = fCurrent;
444 u = utf8_next(&fCurrent, fEnd);
445 const hb_script_t script = hb_unicode_script(fHBUnicode, u);
446 if (script != fCurrentScript) {
447 if (fCurrentScript == HB_SCRIPT_INHERITED || fCurrentScript == HB_SCRIPT_COMMON) {
448 fCurrentScript = script;
449 } else if (script == HB_SCRIPT_INHERITED || script == HB_SCRIPT_COMMON) {
450 continue;
451 } else {
452 fCurrent = prev;
453 break;
454 }
455 }
456 }
457 if (fCurrentScript == HB_SCRIPT_INHERITED) {
458 fCurrentScript = HB_SCRIPT_COMMON;
459 }
460 }
endOfCurrentRun() const461 const char* endOfCurrentRun() const override {
462 return fCurrent;
463 }
atEnd() const464 bool atEnd() const override {
465 return fCurrent == fEnd;
466 }
467
currentScript() const468 hb_script_t currentScript() const {
469 return fCurrentScript;
470 }
471 private:
472 const char* fCurrent;
473 const char* fEnd;
474 hb_unicode_funcs_t* fHBUnicode;
475 hb_script_t fCurrentScript;
476 };
477
478 class FontRunIterator : public RunIterator {
479 public:
Make(const char * utf8,size_t utf8Bytes,SkFont font,sk_sp<SkFontMgr> fallbackMgr)480 static SkTLazy<FontRunIterator> Make(const char* utf8, size_t utf8Bytes,
481 SkFont font,
482 sk_sp<SkFontMgr> fallbackMgr)
483 {
484 SkTLazy<FontRunIterator> ret;
485 font.setTypeface(font.refTypefaceOrDefault());
486 HBFont hbFont = create_hb_font(font);
487 if (!hbFont) {
488 SkDebugf("create_hb_font failed!\n");
489 return ret;
490 }
491 ret.init(utf8, utf8Bytes, std::move(font), std::move(hbFont), std::move(fallbackMgr));
492 return ret;
493 }
FontRunIterator(const char * utf8,size_t utf8Bytes,SkFont font,HBFont hbFont,sk_sp<SkFontMgr> fallbackMgr)494 FontRunIterator(const char* utf8, size_t utf8Bytes, SkFont font,
495 HBFont hbFont, sk_sp<SkFontMgr> fallbackMgr)
496 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
497 , fFallbackMgr(std::move(fallbackMgr))
498 , fHBFont(std::move(hbFont)), fFont(std::move(font))
499 , fFallbackHBFont(nullptr), fFallbackFont(fFont)
500 , fCurrentHBFont(fHBFont.get()), fCurrentFont(&fFont)
501 {
502 fFallbackFont.setTypeface(nullptr);
503 }
consume()504 void consume() override {
505 SkASSERT(fCurrent < fEnd);
506 SkUnichar u = utf8_next(&fCurrent, fEnd);
507 // If the starting typeface can handle this character, use it.
508 if (fFont.unicharToGlyph(u)) {
509 fCurrentFont = &fFont;
510 fCurrentHBFont = fHBFont.get();
511 // If the current fallback can handle this character, use it.
512 } else if (fFallbackFont.getTypeface() && fFallbackFont.unicharToGlyph(u)) {
513 fCurrentFont = &fFallbackFont;
514 fCurrentHBFont = fFallbackHBFont.get();
515 // If not, try to find a fallback typeface
516 } else {
517 sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter(
518 nullptr, fFont.getTypeface()->fontStyle(), nullptr, 0, u));
519 if (candidate) {
520 fFallbackFont.setTypeface(std::move(candidate));
521 fFallbackHBFont = create_hb_font(fFallbackFont);
522 fCurrentFont = &fFallbackFont;
523 fCurrentHBFont = fFallbackHBFont.get();
524 } else {
525 fCurrentFont = &fFont;
526 fCurrentHBFont = fHBFont.get();
527 }
528 }
529
530 while (fCurrent < fEnd) {
531 const char* prev = fCurrent;
532 u = utf8_next(&fCurrent, fEnd);
533
534 // End run if not using initial typeface and initial typeface has this character.
535 if (fCurrentFont->getTypeface() != fFont.getTypeface() && fFont.unicharToGlyph(u)) {
536 fCurrent = prev;
537 return;
538 }
539
540 // End run if current typeface does not have this character and some other font does.
541 if (!fCurrentFont->unicharToGlyph(u)) {
542 sk_sp<SkTypeface> candidate(fFallbackMgr->matchFamilyStyleCharacter(
543 nullptr, fFont.getTypeface()->fontStyle(), nullptr, 0, u));
544 if (candidate) {
545 fCurrent = prev;
546 return;
547 }
548 }
549 }
550 }
endOfCurrentRun() const551 const char* endOfCurrentRun() const override {
552 return fCurrent;
553 }
atEnd() const554 bool atEnd() const override {
555 return fCurrent == fEnd;
556 }
557
currentFont() const558 SkFont* currentFont() const {
559 return fCurrentFont;
560 }
currentHBFont() const561 hb_font_t* currentHBFont() const {
562 return fCurrentHBFont;
563 }
564 private:
565 const char* fCurrent;
566 const char* fEnd;
567 sk_sp<SkFontMgr> fFallbackMgr;
568 HBFont fHBFont;
569 SkFont fFont;
570 HBFont fFallbackHBFont;
571 SkFont fFallbackFont;
572 hb_font_t* fCurrentHBFont;
573 SkFont* fCurrentFont;
574 };
575
576 class LanguageRunIterator : public RunIterator {
577 public:
Make(const char * utf8,size_t utf8Bytes)578 static SkTLazy<LanguageRunIterator> Make(const char* utf8, size_t utf8Bytes) {
579 SkTLazy<LanguageRunIterator> ret;
580 ret.init(utf8, utf8Bytes);
581 return ret;
582 }
LanguageRunIterator(const char * utf8,size_t utf8Bytes)583 LanguageRunIterator(const char* utf8, size_t utf8Bytes)
584 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
585 , fLanguage(hb_language_from_string(std::locale().name().c_str(), -1))
586 { }
consume()587 void consume() override {
588 // Ideally something like cld2/3 could be used, or user signals.
589 SkASSERT(fCurrent < fEnd);
590 fCurrent = fEnd;
591 }
endOfCurrentRun() const592 const char* endOfCurrentRun() const override {
593 return fCurrent;
594 }
atEnd() const595 bool atEnd() const override {
596 return fCurrent == fEnd;
597 }
598
currentLanguage() const599 hb_language_t currentLanguage() const {
600 return fLanguage;
601 }
602 private:
603 const char* fCurrent;
604 const char* fEnd;
605 hb_language_t fLanguage;
606 };
607
608 class RunIteratorQueue {
609 public:
insert(RunIterator * runIterator)610 void insert(RunIterator* runIterator) {
611 fRunIterators.insert(runIterator);
612 }
613
advanceRuns()614 bool advanceRuns() {
615 const RunIterator* leastRun = fRunIterators.peek();
616 if (leastRun->atEnd()) {
617 SkASSERT(this->allRunsAreAtEnd());
618 return false;
619 }
620 const char* leastEnd = leastRun->endOfCurrentRun();
621 RunIterator* currentRun = nullptr;
622 SkDEBUGCODE(const char* previousEndOfCurrentRun);
623 while ((currentRun = fRunIterators.peek())->endOfCurrentRun() <= leastEnd) {
624 fRunIterators.pop();
625 SkDEBUGCODE(previousEndOfCurrentRun = currentRun->endOfCurrentRun());
626 currentRun->consume();
627 SkASSERT(previousEndOfCurrentRun < currentRun->endOfCurrentRun());
628 fRunIterators.insert(currentRun);
629 }
630 return true;
631 }
632
endOfCurrentRun() const633 const char* endOfCurrentRun() const {
634 return fRunIterators.peek()->endOfCurrentRun();
635 }
636
637 private:
allRunsAreAtEnd() const638 bool allRunsAreAtEnd() const {
639 for (int i = 0; i < fRunIterators.count(); ++i) {
640 if (!fRunIterators.at(i)->atEnd()) {
641 return false;
642 }
643 }
644 return true;
645 }
646
CompareRunIterator(RunIterator * const & a,RunIterator * const & b)647 static bool CompareRunIterator(RunIterator* const& a, RunIterator* const& b) {
648 return *a < *b;
649 }
650 SkTDPQueue<RunIterator*, CompareRunIterator> fRunIterators;
651 };
652
653 struct ShapedGlyph {
654 SkGlyphID fID;
655 uint32_t fCluster;
656 SkPoint fOffset;
657 SkVector fAdvance;
658 bool fMayLineBreakBefore;
659 bool fMustLineBreakBefore;
660 bool fHasVisual;
661 bool fGraphemeBreakBefore;
662 bool fUnsafeToBreak;
663 };
664 struct ShapedRun {
ShapedRun__anona3885cf40111::ShapedRun665 ShapedRun(SkSpan<const char> utf8, const SkFont& font, UBiDiLevel level,
666 std::unique_ptr<ShapedGlyph[]> glyphs, int numGlyphs)
667 : fUtf8(utf8), fFont(font), fLevel(level)
668 , fGlyphs(std::move(glyphs)), fNumGlyphs(numGlyphs)
669 {}
670
671 SkSpan<const char> fUtf8;
672 SkFont fFont;
673 UBiDiLevel fLevel;
674 std::unique_ptr<ShapedGlyph[]> fGlyphs;
675 int fNumGlyphs;
676 SkVector fAdvance = { 0, 0 };
677 };
678 struct ShapedLine {
679 SkTArray<ShapedRun> runs;
680 SkVector fAdvance = { 0, 0 };
681 };
682
is_LTR(UBiDiLevel level)683 static constexpr bool is_LTR(UBiDiLevel level) {
684 return (level & 1) == 0;
685 }
686
append(SkShaper::RunHandler * handler,const SkShaper::RunHandler::RunInfo & runInfo,const ShapedRun & run,int start,int end,SkPoint * p)687 static void append(SkShaper::RunHandler* handler, const SkShaper::RunHandler::RunInfo& runInfo,
688 const ShapedRun& run, int start, int end,
689 SkPoint* p) {
690 const unsigned len = end - start;
691
692 const auto buffer = handler->newRunBuffer(runInfo, run.fFont, len, run.fUtf8);
693 SkASSERT(buffer.glyphs);
694 SkASSERT(buffer.positions);
695
696 for (unsigned i = 0; i < len; i++) {
697 // Glyphs are in logical order, but output ltr since PDF readers seem to expect that.
698 const ShapedGlyph& glyph = run.fGlyphs[is_LTR(run.fLevel) ? start + i : end - 1 - i];
699 buffer.glyphs[i] = glyph.fID;
700 buffer.positions[i] = SkPoint::Make(p->fX + glyph.fOffset.fX, p->fY - glyph.fOffset.fY);
701 if (buffer.clusters) {
702 buffer.clusters[i] = glyph.fCluster;
703 }
704 p->fX += glyph.fAdvance.fX;
705 p->fY += glyph.fAdvance.fY;
706 }
707 handler->commitRun();
708 }
709
emit(const ShapedLine & line,SkShaper::RunHandler * handler,SkPoint point,SkPoint & currentPoint)710 static void emit(const ShapedLine& line, SkShaper::RunHandler* handler,
711 SkPoint point, SkPoint& currentPoint)
712 {
713 // Reorder the runs and glyphs per line and write them out.
714 SkScalar maxAscent = 0;
715 SkScalar maxDescent = 0;
716 SkScalar maxLeading = 0;
717 for (const ShapedRun& run : line.runs) {
718 SkFontMetrics metrics;
719 run.fFont.getMetrics(&metrics);
720 maxAscent = SkTMin(maxAscent, metrics.fAscent);
721 maxDescent = SkTMax(maxDescent, metrics.fDescent);
722 maxLeading = SkTMax(maxLeading, metrics.fLeading);
723 }
724
725 int numRuns = line.runs.size();
726 SkAutoSTMalloc<4, UBiDiLevel> runLevels(numRuns);
727 for (int i = 0; i < numRuns; ++i) {
728 runLevels[i] = line.runs[i].fLevel;
729 }
730 SkAutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
731 ubidi_reorderVisual(runLevels, numRuns, logicalFromVisual);
732
733 currentPoint.fY -= maxAscent;
734
735 for (int i = 0; i < numRuns; ++i) {
736 int logicalIndex = logicalFromVisual[i];
737
738 const auto& run = line.runs[logicalIndex];
739 const SkShaper::RunHandler::RunInfo info = {
740 run.fAdvance,
741 maxAscent,
742 maxDescent,
743 maxLeading,
744 };
745 append(handler, info, run, 0, run.fNumGlyphs, ¤tPoint);
746 }
747
748 currentPoint.fY += maxDescent + maxLeading;
749 currentPoint.fX = point.fX;
750
751 handler->commitLine();
752 }
753
754 struct ShapedRunGlyphIterator {
ShapedRunGlyphIterator__anona3885cf40111::ShapedRunGlyphIterator755 ShapedRunGlyphIterator(const SkTArray<ShapedRun>& origRuns)
756 : fRuns(&origRuns), fRunIndex(0), fGlyphIndex(0)
757 { }
758
759 ShapedRunGlyphIterator(const ShapedRunGlyphIterator& that) = default;
760 ShapedRunGlyphIterator& operator=(const ShapedRunGlyphIterator& that) = default;
operator ==__anona3885cf40111::ShapedRunGlyphIterator761 bool operator==(const ShapedRunGlyphIterator& that) const {
762 return fRuns == that.fRuns &&
763 fRunIndex == that.fRunIndex &&
764 fGlyphIndex == that.fGlyphIndex;
765 }
operator !=__anona3885cf40111::ShapedRunGlyphIterator766 bool operator!=(const ShapedRunGlyphIterator& that) const {
767 return fRuns != that.fRuns ||
768 fRunIndex != that.fRunIndex ||
769 fGlyphIndex != that.fGlyphIndex;
770 }
771
next__anona3885cf40111::ShapedRunGlyphIterator772 ShapedGlyph* next() {
773 const SkTArray<ShapedRun>& runs = *fRuns;
774 SkASSERT(fRunIndex < runs.count());
775 SkASSERT(fGlyphIndex < runs[fRunIndex].fNumGlyphs);
776
777 ++fGlyphIndex;
778 if (fGlyphIndex == runs[fRunIndex].fNumGlyphs) {
779 fGlyphIndex = 0;
780 ++fRunIndex;
781 if (fRunIndex >= runs.count()) {
782 return nullptr;
783 }
784 }
785 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
786 }
787
current__anona3885cf40111::ShapedRunGlyphIterator788 ShapedGlyph* current() {
789 const SkTArray<ShapedRun>& runs = *fRuns;
790 if (fRunIndex >= runs.count()) {
791 return nullptr;
792 }
793 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
794 }
795
796 const SkTArray<ShapedRun>* fRuns;
797 int fRunIndex;
798 int fGlyphIndex;
799 };
800
801 } // namespace
802
803 class SkShaperHarfBuzz : public SkShaper {
804 public:
805 SkShaperHarfBuzz();
806 bool good() const;
807 private:
808 HBBuffer fBuffer;
809 ICUBrk fLineBreakIterator;
810 ICUBrk fGraphemeBreakIterator;
811
812 SkPoint shape(SkShaper::RunHandler* handler,
813 const SkFont& srcFont,
814 const char* utf8text,
815 size_t textBytes,
816 bool leftToRight,
817 SkPoint point,
818 SkScalar width) const override;
819
820 SkPoint shapeCorrect(SkShaper::RunHandler* handler,
821 const char* utf8,
822 size_t utf8Bytes,
823 SkPoint point,
824 SkScalar width,
825 RunIteratorQueue& runSegmenter,
826 const BiDiRunIterator* bidi,
827 const LanguageRunIterator* language,
828 const ScriptRunIterator* script,
829 const FontRunIterator* font) const;
830
831 SkPoint shapeOk(SkShaper::RunHandler* handler,
832 const char* utf8,
833 size_t utf8Bytes,
834 SkPoint point,
835 SkScalar width,
836 RunIteratorQueue& runSegmenter,
837 const BiDiRunIterator* bidi,
838 const LanguageRunIterator* language,
839 const ScriptRunIterator* script,
840 const FontRunIterator* font) const;
841
842 ShapedRun shape(const char* utf8,
843 size_t utf8Bytes,
844 const char* utf8Start,
845 const char* utf8End,
846 const BiDiRunIterator* bidi,
847 const LanguageRunIterator* language,
848 const ScriptRunIterator* script,
849 const FontRunIterator* font) const;
850 };
851
MakeHarfBuzz()852 std::unique_ptr<SkShaper> SkShaper::MakeHarfBuzz() {
853 auto hb = skstd::make_unique<SkShaperHarfBuzz>();
854 return hb->good() ? std::move(hb) : nullptr;
855 }
856
SkShaperHarfBuzz()857 SkShaperHarfBuzz::SkShaperHarfBuzz() {
858 #if defined(SK_USING_THIRD_PARTY_ICU)
859 if (!SkLoadICU()) {
860 SkDebugf("SkLoadICU() failed!\n");
861 return;
862 }
863 #endif
864 fBuffer.reset(hb_buffer_create());
865 SkASSERT(fBuffer);
866
867 UErrorCode status = U_ZERO_ERROR;
868 fLineBreakIterator.reset(ubrk_open(UBRK_LINE, "th", nullptr, 0, &status));
869 if (U_FAILURE(status)) {
870 SkDebugf("Could not create line break iterator: %s", u_errorName(status));
871 SK_ABORT("");
872 }
873
874 fGraphemeBreakIterator.reset(ubrk_open(UBRK_CHARACTER, "th", nullptr, 0, &status));
875 if (U_FAILURE(status)) {
876 SkDebugf("Could not create grapheme break iterator: %s", u_errorName(status));
877 SK_ABORT("");
878 }
879
880 }
881
good() const882 bool SkShaperHarfBuzz::good() const {
883 return fBuffer &&
884 fLineBreakIterator &&
885 fGraphemeBreakIterator;
886 }
887
shape(SkShaper::RunHandler * handler,const SkFont & srcFont,const char * utf8,size_t utf8Bytes,bool leftToRight,SkPoint point,SkScalar width) const888 SkPoint SkShaperHarfBuzz::shape(SkShaper::RunHandler* handler,
889 const SkFont& srcFont,
890 const char* utf8,
891 size_t utf8Bytes,
892 bool leftToRight,
893 SkPoint point,
894 SkScalar width) const
895 {
896 SkASSERT(handler);
897 sk_sp<SkFontMgr> fontMgr = SkFontMgr::RefDefault();
898 UBiDiLevel defaultLevel = leftToRight ? UBIDI_DEFAULT_LTR : UBIDI_DEFAULT_RTL;
899
900 RunIteratorQueue runSegmenter;
901
902 SkTLazy<BiDiRunIterator> maybeBidi(BiDiRunIterator::Make(utf8, utf8Bytes, defaultLevel));
903 BiDiRunIterator* bidi = maybeBidi.getMaybeNull();
904 if (!bidi) {
905 return point;
906 }
907 runSegmenter.insert(bidi);
908
909 SkTLazy<LanguageRunIterator> maybeLanguage(LanguageRunIterator::Make(utf8, utf8Bytes));
910 LanguageRunIterator* language = maybeLanguage.getMaybeNull();
911 if (!language) {
912 return point;
913 }
914 runSegmenter.insert(language);
915
916 hb_unicode_funcs_t* hbUnicode = hb_buffer_get_unicode_funcs(fBuffer.get());
917 SkTLazy<ScriptRunIterator> maybeScript(ScriptRunIterator::Make(utf8, utf8Bytes, hbUnicode));
918 ScriptRunIterator* script = maybeScript.getMaybeNull();
919 if (!script) {
920 return point;
921 }
922 runSegmenter.insert(script);
923
924 SkTLazy<FontRunIterator> maybeFont(FontRunIterator::Make(utf8, utf8Bytes,
925 srcFont, std::move(fontMgr)));
926 FontRunIterator* font = maybeFont.getMaybeNull();
927 if (!font) {
928 return point;
929 }
930 runSegmenter.insert(font);
931
932 if (true) {
933 return shapeCorrect(handler, utf8, utf8Bytes, point, width,
934 runSegmenter, bidi, language, script, font);
935 } else {
936 return shapeOk(handler, utf8, utf8Bytes, point, width,
937 runSegmenter, bidi, language, script, font);
938 }
939 }
940
shapeCorrect(RunHandler * handler,const char * utf8,size_t utf8Bytes,SkPoint point,SkScalar width,RunIteratorQueue & runSegmenter,const BiDiRunIterator * bidi,const LanguageRunIterator * language,const ScriptRunIterator * script,const FontRunIterator * font) const941 SkPoint SkShaperHarfBuzz::shapeCorrect(RunHandler* handler,
942 const char* utf8,
943 size_t utf8Bytes,
944 SkPoint point,
945 SkScalar width,
946 RunIteratorQueue& runSegmenter,
947 const BiDiRunIterator* bidi,
948 const LanguageRunIterator* language,
949 const ScriptRunIterator* script,
950 const FontRunIterator* font) const
951 {
952 ShapedLine line;
953 SkPoint currentPoint = point;
954
955 const char* utf8Start = nullptr;
956 const char* utf8End = utf8;
957 while (runSegmenter.advanceRuns()) { // For each item
958 utf8Start = utf8End;
959 utf8End = runSegmenter.endOfCurrentRun();
960
961 ShapedRun model(SkSpan<const char>(), SkFont(), 0, nullptr, 0);
962 bool modelNeedsRegenerated = true;
963 int modelOffset = 0;
964
965 struct TextProps {
966 int glyphLen = 0;
967 SkVector advance = {0, 0};
968 };
969 // map from character position to [safe to break, glyph position, advance]
970 std::unique_ptr<TextProps[]> modelText;
971 int modelTextOffset = 0;
972 SkVector modelTextAdvanceOffset = {0, 0};
973
974 while (utf8Start < utf8End) { // While there are still code points left in this item
975 size_t utf8runLength = utf8End - utf8Start;
976 if (modelNeedsRegenerated) {
977 model = shape(utf8, utf8Bytes,
978 utf8Start, utf8End,
979 bidi, language, script, font);
980 modelOffset = 0;
981
982 SkVector advance = {0, 0};
983 modelText.reset(new TextProps[utf8runLength + 1]());
984 size_t modelStartCluster = utf8Start - utf8;
985 for (int i = 0; i < model.fNumGlyphs; ++i) {
986 SkASSERT(modelStartCluster <= model.fGlyphs[i].fCluster);
987 SkASSERT( model.fGlyphs[i].fCluster < (size_t)(utf8End - utf8));
988 if (!model.fGlyphs[i].fUnsafeToBreak) {
989 modelText[model.fGlyphs[i].fCluster - modelStartCluster].glyphLen = i;
990 modelText[model.fGlyphs[i].fCluster - modelStartCluster].advance = advance;
991 }
992 advance += model.fGlyphs[i].fAdvance;
993 }
994 // Assume it is always safe to break after the end of an item
995 modelText[utf8runLength].glyphLen = model.fNumGlyphs;
996 modelText[utf8runLength].advance = model.fAdvance;
997 modelTextOffset = 0;
998 modelTextAdvanceOffset = {0, 0};
999 modelNeedsRegenerated = false;
1000 }
1001
1002 // TODO: break iterator per item, but just reset position if needed?
1003 // Maybe break iterator with model?
1004 UBreakIterator& breakIterator = *fLineBreakIterator;
1005 {
1006 UErrorCode status = U_ZERO_ERROR;
1007 UText utf8UText = UTEXT_INITIALIZER;
1008 utext_openUTF8(&utf8UText, utf8Start, utf8runLength, &status);
1009 std::unique_ptr<UText, SkFunctionWrapper<UText*, UText, utext_close>> autoClose(&utf8UText);
1010 if (U_FAILURE(status)) {
1011 SkDebugf("Could not create utf8UText: %s", u_errorName(status));
1012 return point;
1013 }
1014 ubrk_setUText(&breakIterator, &utf8UText, &status);
1015 if (U_FAILURE(status)) {
1016 SkDebugf("Could not setText on break iterator: %s", u_errorName(status));
1017 return point;
1018 }
1019 }
1020
1021 ShapedRun best(SkSpan<const char>(), SkFont(), 0, nullptr, 0);
1022 best.fAdvance = { SK_ScalarNegativeInfinity, SK_ScalarNegativeInfinity };
1023 SkScalar widthLeft = width - line.fAdvance.fX;
1024
1025 for (int32_t breakIteratorCurrent = ubrk_next(&breakIterator);
1026 breakIteratorCurrent != UBRK_DONE;
1027 breakIteratorCurrent = ubrk_next(&breakIterator))
1028 {
1029 // TODO: if past a safe to break, future safe to break will be at least as long
1030
1031 // TODO: adjust breakIteratorCurrent by ignorable whitespace
1032 ShapedRun candidate = modelText[breakIteratorCurrent + modelTextOffset].glyphLen
1033 ? ShapedRun(SkSpan<const char>(utf8Start, breakIteratorCurrent),
1034 *font->currentFont(), bidi->currentLevel(),
1035 std::unique_ptr<ShapedGlyph[]>(),
1036 modelText[breakIteratorCurrent + modelTextOffset].glyphLen - modelOffset)
1037 : shape(utf8, utf8Bytes,
1038 utf8Start, utf8Start + breakIteratorCurrent,
1039 bidi, language, script, font);
1040 if (!candidate.fUtf8.data()) {
1041 //report error
1042 return point;
1043 }
1044 if (!candidate.fGlyphs) {
1045 candidate.fAdvance = modelText[breakIteratorCurrent + modelTextOffset].advance - modelTextAdvanceOffset;
1046 }
1047 auto score = [widthLeft](const ShapedRun& run) -> SkScalar {
1048 if (run.fAdvance.fX < widthLeft) {
1049 if (run.fUtf8.data() == nullptr) {
1050 return SK_ScalarNegativeInfinity;
1051 } else {
1052 return run.fUtf8.size();
1053 }
1054 } else {
1055 return widthLeft - run.fAdvance.fX;
1056 }
1057 };
1058 if (score(best) < score(candidate)) {
1059 best = std::move(candidate);
1060 }
1061 }
1062
1063 // If nothing fit (best score is negative) and the line is not empty
1064 if (width < line.fAdvance.fX + best.fAdvance.fX && !line.runs.empty()) {
1065 emit(line, handler, point, currentPoint);
1066 line.runs.reset();
1067 line.fAdvance = {0, 0};
1068 } else {
1069 if (!best.fGlyphs) {
1070 best.fGlyphs.reset(new ShapedGlyph[best.fNumGlyphs]);
1071 memcpy(best.fGlyphs.get(), model.fGlyphs.get() + modelOffset,
1072 best.fNumGlyphs * sizeof(ShapedGlyph));
1073 modelOffset += best.fNumGlyphs;
1074 modelTextOffset += best.fUtf8.size();
1075 modelTextAdvanceOffset += best.fAdvance;
1076 } else {
1077 modelNeedsRegenerated = true;
1078 }
1079 utf8Start = best.fUtf8.end();
1080 line.fAdvance += best.fAdvance;
1081 line.runs.emplace_back(std::move(best));
1082
1083 // If item broken, emit line (prevent remainder from accidentally fitting)
1084 if (utf8Start != utf8End) {
1085 emit(line, handler, point, currentPoint);
1086 line.runs.reset();
1087 line.fAdvance = {0, 0};
1088 }
1089 }
1090 }
1091 }
1092 emit(line, handler, point, currentPoint);
1093 return currentPoint;
1094 }
1095
shapeOk(RunHandler * handler,const char * utf8,size_t utf8Bytes,SkPoint point,SkScalar width,RunIteratorQueue & runSegmenter,const BiDiRunIterator * bidi,const LanguageRunIterator * language,const ScriptRunIterator * script,const FontRunIterator * font) const1096 SkPoint SkShaperHarfBuzz::shapeOk(RunHandler* handler,
1097 const char* utf8,
1098 size_t utf8Bytes,
1099 SkPoint point,
1100 SkScalar width,
1101 RunIteratorQueue& runSegmenter,
1102 const BiDiRunIterator* bidi,
1103 const LanguageRunIterator* language,
1104 const ScriptRunIterator* script,
1105 const FontRunIterator* font) const
1106 {
1107 SkTArray<ShapedRun> runs;
1108 {
1109 UBreakIterator& lineBreakIterator = *fLineBreakIterator;
1110 UBreakIterator& graphemeBreakIterator = *fGraphemeBreakIterator;
1111 {
1112 UErrorCode status = U_ZERO_ERROR;
1113 UText utf8UText = UTEXT_INITIALIZER;
1114 utext_openUTF8(&utf8UText, utf8, utf8Bytes, &status);
1115 std::unique_ptr<UText, SkFunctionWrapper<UText*, UText, utext_close>> autoClose(&utf8UText);
1116 if (U_FAILURE(status)) {
1117 SkDebugf("Could not create utf8UText: %s", u_errorName(status));
1118 return point;
1119 }
1120
1121 ubrk_setUText(&lineBreakIterator, &utf8UText, &status);
1122 if (U_FAILURE(status)) {
1123 SkDebugf("Could not setText on line break iterator: %s", u_errorName(status));
1124 return point;
1125 }
1126 ubrk_setUText(&graphemeBreakIterator, &utf8UText, &status);
1127 if (U_FAILURE(status)) {
1128 SkDebugf("Could not setText on grapheme break iterator: %s", u_errorName(status));
1129 return point;
1130 }
1131 }
1132
1133 const char* utf8Start = nullptr;
1134 const char* utf8End = utf8;
1135 while (runSegmenter.advanceRuns()) {
1136 utf8Start = utf8End;
1137 utf8End = runSegmenter.endOfCurrentRun();
1138
1139 runs.emplace_back(shape(utf8, utf8Bytes,
1140 utf8Start, utf8End,
1141 bidi, language, script, font));
1142 ShapedRun& run = runs.back();
1143
1144 uint32_t previousCluster = 0xFFFFFFFF;
1145 for (int i = 0; i < run.fNumGlyphs; ++i) {
1146 ShapedGlyph& glyph = run.fGlyphs[i];
1147 int32_t glyphCluster = glyph.fCluster;
1148
1149 int32_t lineBreakIteratorCurrent = ubrk_current(&lineBreakIterator);
1150 while (lineBreakIteratorCurrent != UBRK_DONE &&
1151 lineBreakIteratorCurrent < glyphCluster)
1152 {
1153 lineBreakIteratorCurrent = ubrk_next(&lineBreakIterator);
1154 }
1155 glyph.fMayLineBreakBefore = glyph.fCluster != previousCluster &&
1156 lineBreakIteratorCurrent == glyphCluster;
1157
1158 int32_t graphemeBreakIteratorCurrent = ubrk_current(&graphemeBreakIterator);
1159 while (graphemeBreakIteratorCurrent != UBRK_DONE &&
1160 graphemeBreakIteratorCurrent < glyphCluster)
1161 {
1162 graphemeBreakIteratorCurrent = ubrk_next(&graphemeBreakIterator);
1163 }
1164 glyph.fGraphemeBreakBefore = glyph.fCluster != previousCluster &&
1165 graphemeBreakIteratorCurrent == glyphCluster;
1166
1167 previousCluster = glyph.fCluster;
1168 }
1169 }
1170 }
1171
1172 // Iterate over the glyphs in logical order to find potential line lengths.
1173 {
1174 /** The position of the beginning of the line. */
1175 ShapedRunGlyphIterator beginning(runs);
1176
1177 /** The position of the candidate line break. */
1178 ShapedRunGlyphIterator candidateLineBreak(runs);
1179 SkScalar candidateLineBreakWidth = 0;
1180
1181 /** The position of the candidate grapheme break. */
1182 ShapedRunGlyphIterator candidateGraphemeBreak(runs);
1183 SkScalar candidateGraphemeBreakWidth = 0;
1184
1185 /** The position of the current location. */
1186 ShapedRunGlyphIterator current(runs);
1187 SkScalar currentWidth = 0;
1188 while (ShapedGlyph* glyph = current.current()) {
1189 // 'Break' at graphemes until a line boundary, then only at line boundaries.
1190 // Only break at graphemes if no line boundary is valid.
1191 if (current != beginning) {
1192 if (glyph->fGraphemeBreakBefore || glyph->fMayLineBreakBefore) {
1193 // TODO: preserve line breaks <= grapheme breaks
1194 // and prevent line breaks inside graphemes
1195 candidateGraphemeBreak = current;
1196 candidateGraphemeBreakWidth = currentWidth;
1197 if (glyph->fMayLineBreakBefore) {
1198 candidateLineBreak = current;
1199 candidateLineBreakWidth = currentWidth;
1200 }
1201 }
1202 }
1203
1204 SkScalar glyphWidth = glyph->fAdvance.fX;
1205 // Break when overwidth, the glyph has a visual representation, and some space is used.
1206 if (width < currentWidth + glyphWidth && glyph->fHasVisual && candidateGraphemeBreakWidth > 0){
1207 if (candidateLineBreak != beginning) {
1208 beginning = candidateLineBreak;
1209 currentWidth -= candidateLineBreakWidth;
1210 candidateGraphemeBreakWidth -= candidateLineBreakWidth;
1211 candidateLineBreakWidth = 0;
1212 } else if (candidateGraphemeBreak != beginning) {
1213 beginning = candidateGraphemeBreak;
1214 candidateLineBreak = beginning;
1215 currentWidth -= candidateGraphemeBreakWidth;
1216 candidateGraphemeBreakWidth = 0;
1217 candidateLineBreakWidth = 0;
1218 } else {
1219 SK_ABORT("");
1220 }
1221
1222 if (width < currentWidth) {
1223 if (width < candidateGraphemeBreakWidth) {
1224 candidateGraphemeBreak = candidateLineBreak;
1225 candidateGraphemeBreakWidth = candidateLineBreakWidth;
1226 }
1227 current = candidateGraphemeBreak;
1228 currentWidth = candidateGraphemeBreakWidth;
1229 }
1230
1231 glyph = beginning.current();
1232 if (glyph) {
1233 glyph->fMustLineBreakBefore = true;
1234 }
1235
1236 } else {
1237 current.next();
1238 currentWidth += glyphWidth;
1239 }
1240 }
1241 }
1242
1243 // Reorder the runs and glyphs per line and write them out.
1244 SkPoint currentPoint = point;
1245 {
1246 ShapedRunGlyphIterator previousBreak(runs);
1247 ShapedRunGlyphIterator glyphIterator(runs);
1248 SkScalar maxAscent = 0;
1249 SkScalar maxDescent = 0;
1250 SkScalar maxLeading = 0;
1251 int previousRunIndex = -1;
1252 while (glyphIterator.current()) {
1253 int runIndex = glyphIterator.fRunIndex;
1254 int glyphIndex = glyphIterator.fGlyphIndex;
1255 ShapedGlyph* nextGlyph = glyphIterator.next();
1256
1257 if (previousRunIndex != runIndex) {
1258 SkFontMetrics metrics;
1259 runs[runIndex].fFont.getMetrics(&metrics);
1260 maxAscent = SkTMin(maxAscent, metrics.fAscent);
1261 maxDescent = SkTMax(maxDescent, metrics.fDescent);
1262 maxLeading = SkTMax(maxLeading, metrics.fLeading);
1263 previousRunIndex = runIndex;
1264 }
1265
1266 // Nothing can be written until the baseline is known.
1267 if (!(nextGlyph == nullptr || nextGlyph->fMustLineBreakBefore)) {
1268 continue;
1269 }
1270
1271 currentPoint.fY -= maxAscent;
1272
1273 int numRuns = runIndex - previousBreak.fRunIndex + 1;
1274 SkAutoSTMalloc<4, UBiDiLevel> runLevels(numRuns);
1275 for (int i = 0; i < numRuns; ++i) {
1276 runLevels[i] = runs[previousBreak.fRunIndex + i].fLevel;
1277 }
1278 SkAutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
1279 ubidi_reorderVisual(runLevels, numRuns, logicalFromVisual);
1280
1281 // step through the runs in reverse visual order and the glyphs in reverse logical order
1282 // until a visible glyph is found and force them to the end of the visual line.
1283
1284 for (int i = 0; i < numRuns; ++i) {
1285 int logicalIndex = previousBreak.fRunIndex + logicalFromVisual[i];
1286
1287 int startGlyphIndex = (logicalIndex == previousBreak.fRunIndex)
1288 ? previousBreak.fGlyphIndex
1289 : 0;
1290 int endGlyphIndex = (logicalIndex == runIndex)
1291 ? glyphIndex + 1
1292 : runs[logicalIndex].fNumGlyphs;
1293
1294 const auto& run = runs[logicalIndex];
1295 const RunHandler::RunInfo info = {
1296 run.fAdvance,
1297 maxAscent,
1298 maxDescent,
1299 maxLeading,
1300 };
1301 append(handler, info, run, startGlyphIndex, endGlyphIndex, ¤tPoint);
1302 }
1303
1304 handler->commitLine();
1305
1306 currentPoint.fY += maxDescent + maxLeading;
1307 currentPoint.fX = point.fX;
1308 maxAscent = 0;
1309 maxDescent = 0;
1310 maxLeading = 0;
1311 previousRunIndex = -1;
1312 previousBreak = glyphIterator;
1313 }
1314 }
1315
1316 return currentPoint;
1317 }
1318
1319
shape(const char * utf8,const size_t utf8Bytes,const char * utf8Start,const char * utf8End,const BiDiRunIterator * bidi,const LanguageRunIterator * language,const ScriptRunIterator * script,const FontRunIterator * font) const1320 ShapedRun SkShaperHarfBuzz::shape(const char* utf8,
1321 const size_t utf8Bytes,
1322 const char* utf8Start,
1323 const char* utf8End,
1324 const BiDiRunIterator* bidi,
1325 const LanguageRunIterator* language,
1326 const ScriptRunIterator* script,
1327 const FontRunIterator* font) const
1328 {
1329 ShapedRun run(SkSpan<const char>(), SkFont(), 0, nullptr, 0);
1330
1331 hb_buffer_t* buffer = fBuffer.get();
1332 SkAutoTCallVProc<hb_buffer_t, hb_buffer_clear_contents> autoClearBuffer(buffer);
1333 hb_buffer_set_content_type(buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
1334 hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
1335
1336 // See 763e5466c0a03a7c27020e1e2598e488612529a7 for documentation.
1337 hb_buffer_set_flags(buffer, HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT);
1338
1339 // Add precontext.
1340 hb_buffer_add_utf8(buffer, utf8, utf8Start - utf8, utf8Start - utf8, 0);
1341
1342 // Populate the hb_buffer directly with utf8 cluster indexes.
1343 const char* utf8Current = utf8Start;
1344 while (utf8Current < utf8End) {
1345 unsigned int cluster = utf8Current - utf8;
1346 hb_codepoint_t u = utf8_next(&utf8Current, utf8End);
1347 hb_buffer_add(buffer, u, cluster);
1348 }
1349
1350 // Add postcontext.
1351 hb_buffer_add_utf8(buffer, utf8Current, utf8 + utf8Bytes - utf8Current, 0, 0);
1352
1353 size_t utf8runLength = utf8End - utf8Start;
1354 if (!SkTFitsIn<int>(utf8runLength)) {
1355 SkDebugf("Shaping error: utf8 too long");
1356 return run;
1357 }
1358 hb_direction_t direction = is_LTR(bidi->currentLevel()) ? HB_DIRECTION_LTR:HB_DIRECTION_RTL;
1359 hb_buffer_set_direction(buffer, direction);
1360 hb_buffer_set_script(buffer, script->currentScript());
1361 hb_buffer_set_language(buffer, language->currentLanguage());
1362 hb_buffer_guess_segment_properties(buffer);
1363 // TODO: features
1364 if (!font->currentHBFont()) {
1365 return run;
1366 }
1367 hb_shape(font->currentHBFont(), buffer, nullptr, 0);
1368 unsigned len = hb_buffer_get_length(buffer);
1369 if (len == 0) {
1370 // TODO: this isn't an error, make it look different
1371 return run;
1372 }
1373
1374 if (direction == HB_DIRECTION_RTL) {
1375 // Put the clusters back in logical order.
1376 // Note that the advances remain ltr.
1377 hb_buffer_reverse(buffer);
1378 }
1379 hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, nullptr);
1380 hb_glyph_position_t* pos = hb_buffer_get_glyph_positions(buffer, nullptr);
1381
1382 if (!SkTFitsIn<int>(len)) {
1383 SkDebugf("Shaping error: too many glyphs");
1384 return run;
1385 }
1386
1387 run = ShapedRun(SkSpan<const char>(utf8Start, utf8runLength),
1388 *font->currentFont(), bidi->currentLevel(),
1389 std::unique_ptr<ShapedGlyph[]>(new ShapedGlyph[len]), len);
1390 int scaleX, scaleY;
1391 hb_font_get_scale(font->currentHBFont(), &scaleX, &scaleY);
1392 double textSizeY = run.fFont.getSize() / scaleY;
1393 double textSizeX = run.fFont.getSize() / scaleX * run.fFont.getScaleX();
1394 SkVector runAdvance = { 0, 0 };
1395 for (unsigned i = 0; i < len; i++) {
1396 ShapedGlyph& glyph = run.fGlyphs[i];
1397 glyph.fID = info[i].codepoint;
1398 glyph.fCluster = info[i].cluster;
1399 glyph.fOffset.fX = pos[i].x_offset * textSizeX;
1400 glyph.fOffset.fY = pos[i].y_offset * textSizeY;
1401 glyph.fAdvance.fX = pos[i].x_advance * textSizeX;
1402 glyph.fAdvance.fY = pos[i].y_advance * textSizeY;
1403
1404 SkRect bounds;
1405 SkScalar advance;
1406 SkPaint p;
1407 run.fFont.getWidthsBounds(&glyph.fID, 1, &advance, &bounds, &p);
1408 glyph.fHasVisual = !bounds.isEmpty(); //!font->currentTypeface()->glyphBoundsAreZero(glyph.fID);
1409 #if SK_HB_VERSION_CHECK(1, 5, 0)
1410 glyph.fUnsafeToBreak = info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
1411 #else
1412 glyph.fUnsafeToBreak = false;
1413 #endif
1414 glyph.fMustLineBreakBefore = false;
1415
1416 runAdvance += glyph.fAdvance;
1417 }
1418 run.fAdvance = runAdvance;
1419
1420 return run;
1421 }
1422