blob: 93acec8e5e510d71fad3456ec6529673c20f7061 [file] [log] [blame]
Ben Wagnera25fbef2017-08-30 13:56:19 -04001/*
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
Ben Wagner17774242018-08-07 14:31:33 -04008#include "SkFontArguments.h"
Ben Wagner67e3a302017-09-05 14:46:19 -04009#include "SkFontMgr.h"
Hal Canary0e07ad72018-02-08 13:06:56 -050010#include "SkLoadICU.h"
Ben Wagner17774242018-08-07 14:31:33 -040011#include "SkMalloc.h"
Hal Canary0e07ad72018-02-08 13:06:56 -050012#include "SkOnce.h"
Hal Canary2a1848d2018-11-26 17:23:24 -050013#include "SkFont.h"
Ben Wagner17774242018-08-07 14:31:33 -040014#include "SkPoint.h"
15#include "SkRefCnt.h"
16#include "SkScalar.h"
Ben Wagnera25fbef2017-08-30 13:56:19 -040017#include "SkShaper.h"
18#include "SkStream.h"
Ben Wagner17774242018-08-07 14:31:33 -040019#include "SkString.h"
20#include "SkTArray.h"
Ben Wagner8d45a382017-11-16 10:08:28 -050021#include "SkTDPQueue.h"
Ben Wagner17774242018-08-07 14:31:33 -040022#include "SkTFitsIn.h"
Ben Wagner8d45a382017-11-16 10:08:28 -050023#include "SkTLazy.h"
Ben Wagnere0001732017-08-31 16:26:26 -040024#include "SkTemplates.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040025#include "SkTo.h"
Ben Wagnera25fbef2017-08-30 13:56:19 -040026#include "SkTypeface.h"
Ben Wagner17774242018-08-07 14:31:33 -040027#include "SkTypes.h"
28#include "SkUTF.h"
29
30#include <hb.h>
31#include <hb-ot.h>
32#include <unicode/brkiter.h>
33#include <unicode/locid.h>
34#include <unicode/stringpiece.h>
35#include <unicode/ubidi.h>
36#include <unicode/unistr.h>
37#include <unicode/urename.h>
38#include <unicode/utext.h>
39#include <unicode/utypes.h>
40
41#include <memory>
42#include <utility>
43#include <cstring>
Ben Wagnera25fbef2017-08-30 13:56:19 -040044
Ben Wagnera25fbef2017-08-30 13:56:19 -040045namespace {
46template <class T, void(*P)(T*)> using resource = std::unique_ptr<T, SkFunctionWrapper<void, T, P>>;
47using HBBlob = resource<hb_blob_t , hb_blob_destroy >;
48using HBFace = resource<hb_face_t , hb_face_destroy >;
49using HBFont = resource<hb_font_t , hb_font_destroy >;
50using HBBuffer = resource<hb_buffer_t, hb_buffer_destroy>;
51using ICUBiDi = resource<UBiDi , ubidi_close >;
52
53HBBlob stream_to_blob(std::unique_ptr<SkStreamAsset> asset) {
54 size_t size = asset->getLength();
55 HBBlob blob;
56 if (const void* base = asset->getMemoryBase()) {
57 blob.reset(hb_blob_create((char*)base, SkToUInt(size),
58 HB_MEMORY_MODE_READONLY, asset.release(),
59 [](void* p) { delete (SkStreamAsset*)p; }));
60 } else {
61 // SkDebugf("Extra SkStreamAsset copy\n");
62 void* ptr = size ? sk_malloc_throw(size) : nullptr;
63 asset->read(ptr, size);
64 blob.reset(hb_blob_create((char*)ptr, SkToUInt(size),
65 HB_MEMORY_MODE_READONLY, ptr, sk_free));
66 }
67 SkASSERT(blob);
68 hb_blob_make_immutable(blob.get());
69 return blob;
70}
Ben Wagnera25fbef2017-08-30 13:56:19 -040071
Ben Wagner8d45a382017-11-16 10:08:28 -050072HBFont create_hb_font(SkTypeface* tf) {
Hal Canary0dfa2082018-10-31 13:02:49 -040073 if (!tf) {
74 return nullptr;
75 }
Ben Wagnera25fbef2017-08-30 13:56:19 -040076 int index;
Hal Canaryddef43f2018-11-16 10:53:51 -050077 std::unique_ptr<SkStreamAsset> typefaceAsset(tf->openStream(&index));
78 if (!typefaceAsset) {
79 SkString name;
80 tf->getFamilyName(&name);
81 SkDebugf("Typeface '%s' has no data :(\n", name.c_str());
82 return nullptr;
83 }
84 HBBlob blob(stream_to_blob(std::move(typefaceAsset)));
Ben Wagnera25fbef2017-08-30 13:56:19 -040085 HBFace face(hb_face_create(blob.get(), (unsigned)index));
86 SkASSERT(face);
87 if (!face) {
Ben Wagnere0001732017-08-31 16:26:26 -040088 return nullptr;
Ben Wagnera25fbef2017-08-30 13:56:19 -040089 }
90 hb_face_set_index(face.get(), (unsigned)index);
Ben Wagnere0001732017-08-31 16:26:26 -040091 hb_face_set_upem(face.get(), tf->getUnitsPerEm());
Ben Wagnera25fbef2017-08-30 13:56:19 -040092
Ben Wagnere0001732017-08-31 16:26:26 -040093 HBFont font(hb_font_create(face.get()));
94 SkASSERT(font);
95 if (!font) {
96 return nullptr;
97 }
Ben Wagnere0001732017-08-31 16:26:26 -040098 hb_ot_font_set_funcs(font.get());
99 int axis_count = tf->getVariationDesignPosition(nullptr, 0);
100 if (axis_count > 0) {
101 SkAutoSTMalloc<4, SkFontArguments::VariationPosition::Coordinate> axis_values(axis_count);
102 if (tf->getVariationDesignPosition(axis_values, axis_count) == axis_count) {
103 hb_font_set_variations(font.get(),
104 reinterpret_cast<hb_variation_t*>(axis_values.get()),
105 axis_count);
106 }
107 }
108 return font;
109}
110
Hal Canaryf107a2f2018-07-25 16:52:48 -0400111/** this version replaces invalid utf-8 sequences with code point U+FFFD. */
112static inline SkUnichar utf8_next(const char** ptr, const char* end) {
113 SkUnichar val = SkUTF::NextUTF8(ptr, end);
114 if (val < 0) {
115 return 0xFFFD; // REPLACEMENT CHARACTER
116 }
117 return val;
118}
119
Ben Wagner8d45a382017-11-16 10:08:28 -0500120class RunIterator {
121public:
122 virtual ~RunIterator() {}
123 virtual void consume() = 0;
124 // Pointer one past the last (utf8) element in the current run.
125 virtual const char* endOfCurrentRun() const = 0;
126 virtual bool atEnd() const = 0;
127 bool operator<(const RunIterator& that) const {
128 return this->endOfCurrentRun() < that.endOfCurrentRun();
129 }
130};
131
132class BiDiRunIterator : public RunIterator {
133public:
134 static SkTLazy<BiDiRunIterator> Make(const char* utf8, size_t utf8Bytes, UBiDiLevel level) {
135 SkTLazy<BiDiRunIterator> ret;
136
137 // ubidi only accepts utf16 (though internally it basically works on utf32 chars).
138 // We want an ubidi_setPara(UBiDi*, UText*, UBiDiLevel, UBiDiLevel*, UErrorCode*);
139 if (!SkTFitsIn<int32_t>(utf8Bytes)) {
140 SkDebugf("Bidi error: text too long");
141 return ret;
142 }
143 icu::UnicodeString utf16 = icu::UnicodeString::fromUTF8(icu::StringPiece(utf8, utf8Bytes));
144
145 UErrorCode status = U_ZERO_ERROR;
146 ICUBiDi bidi(ubidi_openSized(utf16.length(), 0, &status));
147 if (U_FAILURE(status)) {
148 SkDebugf("Bidi error: %s", u_errorName(status));
149 return ret;
150 }
151 SkASSERT(bidi);
152
153 // The required lifetime of utf16 isn't well documented.
154 // It appears it isn't used after ubidi_setPara except through ubidi_getText.
Florin Malita6d415bc2019-01-17 16:42:15 -0500155 ubidi_setPara(bidi.get(),
156 reinterpret_cast<const UChar*>(utf16.getBuffer()),
157 utf16.length(), level, nullptr, &status);
Ben Wagner8d45a382017-11-16 10:08:28 -0500158 if (U_FAILURE(status)) {
159 SkDebugf("Bidi error: %s", u_errorName(status));
160 return ret;
161 }
162
Hal Canary4014ba62018-07-24 11:33:21 -0400163 ret.init(utf8, utf8 + utf8Bytes, std::move(bidi));
Ben Wagner8d45a382017-11-16 10:08:28 -0500164 return ret;
165 }
Hal Canary4014ba62018-07-24 11:33:21 -0400166 BiDiRunIterator(const char* utf8, const char* end, ICUBiDi bidi)
Ben Wagner8d45a382017-11-16 10:08:28 -0500167 : fBidi(std::move(bidi))
168 , fEndOfCurrentRun(utf8)
Hal Canary4014ba62018-07-24 11:33:21 -0400169 , fEndOfAllRuns(end)
Ben Wagner8d45a382017-11-16 10:08:28 -0500170 , fUTF16LogicalPosition(0)
171 , fLevel(UBIDI_DEFAULT_LTR)
172 {}
173 void consume() override {
174 SkASSERT(fUTF16LogicalPosition < ubidi_getLength(fBidi.get()));
175 int32_t endPosition = ubidi_getLength(fBidi.get());
176 fLevel = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400177 SkUnichar u = utf8_next(&fEndOfCurrentRun, fEndOfAllRuns);
178 fUTF16LogicalPosition += SkUTF::ToUTF16(u);
Ben Wagner8d45a382017-11-16 10:08:28 -0500179 UBiDiLevel level;
180 while (fUTF16LogicalPosition < endPosition) {
181 level = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
182 if (level != fLevel) {
183 break;
184 }
Hal Canaryf107a2f2018-07-25 16:52:48 -0400185 u = utf8_next(&fEndOfCurrentRun, fEndOfAllRuns);
186 fUTF16LogicalPosition += SkUTF::ToUTF16(u);
Ben Wagner8d45a382017-11-16 10:08:28 -0500187 }
188 }
189 const char* endOfCurrentRun() const override {
190 return fEndOfCurrentRun;
191 }
192 bool atEnd() const override {
193 return fUTF16LogicalPosition == ubidi_getLength(fBidi.get());
194 }
195
196 UBiDiLevel currentLevel() const {
197 return fLevel;
198 }
199private:
200 ICUBiDi fBidi;
201 const char* fEndOfCurrentRun;
Hal Canary4014ba62018-07-24 11:33:21 -0400202 const char* fEndOfAllRuns;
Ben Wagner8d45a382017-11-16 10:08:28 -0500203 int32_t fUTF16LogicalPosition;
204 UBiDiLevel fLevel;
205};
206
207class ScriptRunIterator : public RunIterator {
208public:
209 static SkTLazy<ScriptRunIterator> Make(const char* utf8, size_t utf8Bytes,
210 hb_unicode_funcs_t* hbUnicode)
211 {
212 SkTLazy<ScriptRunIterator> ret;
213 ret.init(utf8, utf8Bytes, hbUnicode);
214 return ret;
215 }
216 ScriptRunIterator(const char* utf8, size_t utf8Bytes, hb_unicode_funcs_t* hbUnicode)
217 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
218 , fHBUnicode(hbUnicode)
219 , fCurrentScript(HB_SCRIPT_UNKNOWN)
220 {}
221 void consume() override {
222 SkASSERT(fCurrent < fEnd);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400223 SkUnichar u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500224 fCurrentScript = hb_unicode_script(fHBUnicode, u);
225 while (fCurrent < fEnd) {
226 const char* prev = fCurrent;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400227 u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500228 const hb_script_t script = hb_unicode_script(fHBUnicode, u);
229 if (script != fCurrentScript) {
230 if (fCurrentScript == HB_SCRIPT_INHERITED || fCurrentScript == HB_SCRIPT_COMMON) {
231 fCurrentScript = script;
232 } else if (script == HB_SCRIPT_INHERITED || script == HB_SCRIPT_COMMON) {
233 continue;
234 } else {
235 fCurrent = prev;
236 break;
237 }
238 }
239 }
240 if (fCurrentScript == HB_SCRIPT_INHERITED) {
241 fCurrentScript = HB_SCRIPT_COMMON;
242 }
243 }
244 const char* endOfCurrentRun() const override {
245 return fCurrent;
246 }
247 bool atEnd() const override {
248 return fCurrent == fEnd;
249 }
250
251 hb_script_t currentScript() const {
252 return fCurrentScript;
253 }
254private:
255 const char* fCurrent;
256 const char* fEnd;
257 hb_unicode_funcs_t* fHBUnicode;
258 hb_script_t fCurrentScript;
259};
260
261class FontRunIterator : public RunIterator {
262public:
263 static SkTLazy<FontRunIterator> Make(const char* utf8, size_t utf8Bytes,
264 sk_sp<SkTypeface> typeface,
265 hb_font_t* hbFace,
266 sk_sp<SkFontMgr> fallbackMgr)
267 {
268 SkTLazy<FontRunIterator> ret;
269 ret.init(utf8, utf8Bytes, std::move(typeface), hbFace, std::move(fallbackMgr));
270 return ret;
271 }
272 FontRunIterator(const char* utf8, size_t utf8Bytes, sk_sp<SkTypeface> typeface,
273 hb_font_t* hbFace, sk_sp<SkFontMgr> fallbackMgr)
274 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
275 , fFallbackMgr(std::move(fallbackMgr))
276 , fHBFont(hbFace), fTypeface(std::move(typeface))
277 , fFallbackHBFont(nullptr), fFallbackTypeface(nullptr)
278 , fCurrentHBFont(fHBFont), fCurrentTypeface(fTypeface.get())
279 {}
280 void consume() override {
281 SkASSERT(fCurrent < fEnd);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400282 SkUnichar u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500283 // If the starting typeface can handle this character, use it.
284 if (fTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1)) {
Ben Wagnera900ad52018-08-31 17:48:19 -0400285 fCurrentTypeface = fTypeface.get();
286 fCurrentHBFont = fHBFont;
287 // If the current fallback can handle this character, use it.
288 } else if (fFallbackTypeface &&
289 fFallbackTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1))
290 {
291 fCurrentTypeface = fFallbackTypeface.get();
292 fCurrentHBFont = fFallbackHBFont.get();
Ben Wagner8d45a382017-11-16 10:08:28 -0500293 // If not, try to find a fallback typeface
294 } else {
295 fFallbackTypeface.reset(fFallbackMgr->matchFamilyStyleCharacter(
296 nullptr, fTypeface->fontStyle(), nullptr, 0, u));
Ben Wagner8d45a382017-11-16 10:08:28 -0500297 fFallbackHBFont = create_hb_font(fFallbackTypeface.get());
298 fCurrentTypeface = fFallbackTypeface.get();
299 fCurrentHBFont = fFallbackHBFont.get();
Ben Wagner8d45a382017-11-16 10:08:28 -0500300 }
301
302 while (fCurrent < fEnd) {
303 const char* prev = fCurrent;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400304 u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500305
Ben Wagnera900ad52018-08-31 17:48:19 -0400306 // If not using initial typeface and initial typeface has this character, stop fallback.
307 if (fCurrentTypeface != fTypeface.get() &&
Ben Wagner8d45a382017-11-16 10:08:28 -0500308 fTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1))
309 {
310 fCurrent = prev;
311 return;
312 }
313 // If the current typeface cannot handle this character, stop using it.
314 if (!fCurrentTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1)) {
315 fCurrent = prev;
316 return;
317 }
318 }
319 }
320 const char* endOfCurrentRun() const override {
321 return fCurrent;
322 }
323 bool atEnd() const override {
324 return fCurrent == fEnd;
325 }
326
327 SkTypeface* currentTypeface() const {
328 return fCurrentTypeface;
329 }
330 hb_font_t* currentHBFont() const {
331 return fCurrentHBFont;
332 }
333private:
334 const char* fCurrent;
335 const char* fEnd;
336 sk_sp<SkFontMgr> fFallbackMgr;
337 hb_font_t* fHBFont;
338 sk_sp<SkTypeface> fTypeface;
339 HBFont fFallbackHBFont;
340 sk_sp<SkTypeface> fFallbackTypeface;
341 hb_font_t* fCurrentHBFont;
342 SkTypeface* fCurrentTypeface;
343};
344
345class RunIteratorQueue {
346public:
347 void insert(RunIterator* runIterator) {
348 fRunIterators.insert(runIterator);
349 }
350
351 bool advanceRuns() {
352 const RunIterator* leastRun = fRunIterators.peek();
353 if (leastRun->atEnd()) {
354 SkASSERT(this->allRunsAreAtEnd());
355 return false;
356 }
357 const char* leastEnd = leastRun->endOfCurrentRun();
358 RunIterator* currentRun = nullptr;
359 SkDEBUGCODE(const char* previousEndOfCurrentRun);
360 while ((currentRun = fRunIterators.peek())->endOfCurrentRun() <= leastEnd) {
361 fRunIterators.pop();
362 SkDEBUGCODE(previousEndOfCurrentRun = currentRun->endOfCurrentRun());
363 currentRun->consume();
364 SkASSERT(previousEndOfCurrentRun < currentRun->endOfCurrentRun());
365 fRunIterators.insert(currentRun);
366 }
367 return true;
368 }
369
370 const char* endOfCurrentRun() const {
371 return fRunIterators.peek()->endOfCurrentRun();
372 }
373
374private:
375 bool allRunsAreAtEnd() const {
376 for (int i = 0; i < fRunIterators.count(); ++i) {
377 if (!fRunIterators.at(i)->atEnd()) {
378 return false;
379 }
380 }
381 return true;
382 }
383
384 static bool CompareRunIterator(RunIterator* const& a, RunIterator* const& b) {
385 return *a < *b;
386 }
387 SkTDPQueue<RunIterator*, CompareRunIterator> fRunIterators;
388};
389
390struct ShapedGlyph {
391 SkGlyphID fID;
392 uint32_t fCluster;
393 SkPoint fOffset;
394 SkVector fAdvance;
395 bool fMayLineBreakBefore;
396 bool fMustLineBreakBefore;
397 bool fHasVisual;
398};
399struct ShapedRun {
Mike Reed6d595682018-12-05 17:28:14 -0500400 ShapedRun(const char* utf8Start, const char* utf8End, int numGlyphs, const SkFont& font,
Ben Wagner8d45a382017-11-16 10:08:28 -0500401 UBiDiLevel level, std::unique_ptr<ShapedGlyph[]> glyphs)
Mike Reed6d595682018-12-05 17:28:14 -0500402 : fUtf8Start(utf8Start), fUtf8End(utf8End), fNumGlyphs(numGlyphs), fFont(font)
Ben Wagner8d45a382017-11-16 10:08:28 -0500403 , fLevel(level), fGlyphs(std::move(glyphs))
404 {}
405
406 const char* fUtf8Start;
407 const char* fUtf8End;
408 int fNumGlyphs;
Mike Reed6d595682018-12-05 17:28:14 -0500409 SkFont fFont;
Ben Wagner8d45a382017-11-16 10:08:28 -0500410 UBiDiLevel fLevel;
411 std::unique_ptr<ShapedGlyph[]> fGlyphs;
Florin Malita950243d2019-01-11 11:08:35 -0500412 SkVector fAdvance = { 0, 0 };
Ben Wagner8d45a382017-11-16 10:08:28 -0500413};
414
415static constexpr bool is_LTR(UBiDiLevel level) {
416 return (level & 1) == 0;
417}
418
Florin Malita950243d2019-01-11 11:08:35 -0500419static void append(SkShaper::RunHandler* handler, const SkShaper::RunHandler::RunInfo& runInfo,
420 const ShapedRun& run, int start, int end,
Florin Malita9867f612018-12-12 10:54:49 -0500421 SkPoint* p) {
Ben Wagner8d45a382017-11-16 10:08:28 -0500422 unsigned len = end - start;
Florin Malita9867f612018-12-12 10:54:49 -0500423
Florin Malita950243d2019-01-11 11:08:35 -0500424 const auto buffer = handler->newRunBuffer(runInfo, run.fFont, len, run.fUtf8End - run.fUtf8Start);
Florin Malita9867f612018-12-12 10:54:49 -0500425 SkASSERT(buffer.glyphs);
426 SkASSERT(buffer.positions);
427
428 if (buffer.utf8text) {
429 memcpy(buffer.utf8text, run.fUtf8Start, run.fUtf8End - run.fUtf8Start);
430 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500431
432 for (unsigned i = 0; i < len; i++) {
433 // Glyphs are in logical order, but output ltr since PDF readers seem to expect that.
434 const ShapedGlyph& glyph = run.fGlyphs[is_LTR(run.fLevel) ? start + i : end - 1 - i];
Florin Malita9867f612018-12-12 10:54:49 -0500435 buffer.glyphs[i] = glyph.fID;
436 buffer.positions[i] = SkPoint::Make(p->fX + glyph.fOffset.fX, p->fY - glyph.fOffset.fY);
437 if (buffer.clusters) {
438 buffer.clusters[i] = glyph.fCluster;
439 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500440 p->fX += glyph.fAdvance.fX;
441 p->fY += glyph.fAdvance.fY;
442 }
443}
444
445struct ShapedRunGlyphIterator {
446 ShapedRunGlyphIterator(const SkTArray<ShapedRun>& origRuns)
447 : fRuns(&origRuns), fRunIndex(0), fGlyphIndex(0)
448 { }
449
450 ShapedRunGlyphIterator(const ShapedRunGlyphIterator& that) = default;
451 ShapedRunGlyphIterator& operator=(const ShapedRunGlyphIterator& that) = default;
452 bool operator==(const ShapedRunGlyphIterator& that) const {
453 return fRuns == that.fRuns &&
454 fRunIndex == that.fRunIndex &&
455 fGlyphIndex == that.fGlyphIndex;
456 }
457 bool operator!=(const ShapedRunGlyphIterator& that) const {
458 return fRuns != that.fRuns ||
459 fRunIndex != that.fRunIndex ||
460 fGlyphIndex != that.fGlyphIndex;
461 }
462
463 ShapedGlyph* next() {
464 const SkTArray<ShapedRun>& runs = *fRuns;
465 SkASSERT(fRunIndex < runs.count());
466 SkASSERT(fGlyphIndex < runs[fRunIndex].fNumGlyphs);
467
468 ++fGlyphIndex;
469 if (fGlyphIndex == runs[fRunIndex].fNumGlyphs) {
470 fGlyphIndex = 0;
471 ++fRunIndex;
472 if (fRunIndex >= runs.count()) {
473 return nullptr;
474 }
475 }
476 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
477 }
478
479 ShapedGlyph* current() {
480 const SkTArray<ShapedRun>& runs = *fRuns;
481 if (fRunIndex >= runs.count()) {
482 return nullptr;
483 }
484 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
485 }
486
487 const SkTArray<ShapedRun>* fRuns;
488 int fRunIndex;
489 int fGlyphIndex;
490};
491
492} // namespace
493
494struct SkShaper::Impl {
495 HBFont fHarfBuzzFont;
496 HBBuffer fBuffer;
497 sk_sp<SkTypeface> fTypeface;
498 std::unique_ptr<icu::BreakIterator> fBreakIterator;
499};
500
Ben Wagnere0001732017-08-31 16:26:26 -0400501SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
Hal Canary0e07ad72018-02-08 13:06:56 -0500502 SkOnce once;
503 once([] { SkLoadICU(); });
504
Ben Wagnere0001732017-08-31 16:26:26 -0400505 fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
506 fImpl->fHarfBuzzFont = create_hb_font(fImpl->fTypeface.get());
Ben Wagnera25fbef2017-08-30 13:56:19 -0400507 SkASSERT(fImpl->fHarfBuzzFont);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400508 fImpl->fBuffer.reset(hb_buffer_create());
Ben Wagner8d45a382017-11-16 10:08:28 -0500509 SkASSERT(fImpl->fBuffer);
510
511 icu::Locale thai("th");
512 UErrorCode status = U_ZERO_ERROR;
513 fImpl->fBreakIterator.reset(icu::BreakIterator::createLineInstance(thai, status));
514 if (U_FAILURE(status)) {
515 SkDebugf("Could not create break iterator: %s", u_errorName(status));
516 SK_ABORT("");
517 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400518}
519
520SkShaper::~SkShaper() {}
521
Ben Wagner8d45a382017-11-16 10:08:28 -0500522bool SkShaper::good() const {
523 return fImpl->fHarfBuzzFont &&
524 fImpl->fBuffer &&
525 fImpl->fTypeface &&
526 fImpl->fBreakIterator;
527}
Ben Wagnera25fbef2017-08-30 13:56:19 -0400528
Florin Malita950243d2019-01-11 11:08:35 -0500529SkPoint SkShaper::shape(RunHandler* handler,
Hal Canary2a1848d2018-11-26 17:23:24 -0500530 const SkFont& srcPaint,
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500531 const char* utf8,
532 size_t utf8Bytes,
533 bool leftToRight,
534 SkPoint point,
535 SkScalar width) const {
Ben Wagner67e3a302017-09-05 14:46:19 -0400536 sk_sp<SkFontMgr> fontMgr = SkFontMgr::RefDefault();
Florin Malita9867f612018-12-12 10:54:49 -0500537 SkASSERT(handler);
Ben Wagner8d45a382017-11-16 10:08:28 -0500538 UBiDiLevel defaultLevel = leftToRight ? UBIDI_DEFAULT_LTR : UBIDI_DEFAULT_RTL;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400539 //hb_script_t script = ...
Ben Wagnera25fbef2017-08-30 13:56:19 -0400540
Ben Wagner8d45a382017-11-16 10:08:28 -0500541 SkTArray<ShapedRun> runs;
542{
543 RunIteratorQueue runSegmenter;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400544
Ben Wagner8d45a382017-11-16 10:08:28 -0500545 SkTLazy<BiDiRunIterator> maybeBidi(BiDiRunIterator::Make(utf8, utf8Bytes, defaultLevel));
546 BiDiRunIterator* bidi = maybeBidi.getMaybeNull();
547 if (!bidi) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500548 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400549 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500550 runSegmenter.insert(bidi);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400551
Ben Wagner8d45a382017-11-16 10:08:28 -0500552 hb_unicode_funcs_t* hbUnicode = hb_buffer_get_unicode_funcs(fImpl->fBuffer.get());
553 SkTLazy<ScriptRunIterator> maybeScript(ScriptRunIterator::Make(utf8, utf8Bytes, hbUnicode));
554 ScriptRunIterator* script = maybeScript.getMaybeNull();
555 if (!script) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500556 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400557 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500558 runSegmenter.insert(script);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400559
Ben Wagner8d45a382017-11-16 10:08:28 -0500560 SkTLazy<FontRunIterator> maybeFont(FontRunIterator::Make(utf8, utf8Bytes,
561 fImpl->fTypeface,
562 fImpl->fHarfBuzzFont.get(),
563 std::move(fontMgr)));
564 FontRunIterator* font = maybeFont.getMaybeNull();
565 if (!font) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500566 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400567 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500568 runSegmenter.insert(font);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400569
Ben Wagner8d45a382017-11-16 10:08:28 -0500570 icu::BreakIterator& breakIterator = *fImpl->fBreakIterator;
571 {
572 UErrorCode status = U_ZERO_ERROR;
573 UText utf8UText = UTEXT_INITIALIZER;
574 utext_openUTF8(&utf8UText, utf8, utf8Bytes, &status);
575 std::unique_ptr<UText, SkFunctionWrapper<UText*, UText, utext_close>> autoClose(&utf8UText);
576 if (U_FAILURE(status)) {
577 SkDebugf("Could not create utf8UText: %s", u_errorName(status));
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500578 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500579 }
580 breakIterator.setText(&utf8UText, status);
581 //utext_close(&utf8UText);
582 if (U_FAILURE(status)) {
583 SkDebugf("Could not setText on break iterator: %s", u_errorName(status));
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500584 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500585 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400586 }
587
Ben Wagner8d45a382017-11-16 10:08:28 -0500588 const char* utf8Start = nullptr;
589 const char* utf8End = utf8;
590 while (runSegmenter.advanceRuns()) {
591 utf8Start = utf8End;
592 utf8End = runSegmenter.endOfCurrentRun();
593
594 hb_buffer_t* buffer = fImpl->fBuffer.get();
595 SkAutoTCallVProc<hb_buffer_t, hb_buffer_clear_contents> autoClearBuffer(buffer);
596 hb_buffer_set_content_type(buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
597 hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
598
Ben Wagnerc0c99b32018-08-07 10:14:18 -0400599 // Add precontext.
600 hb_buffer_add_utf8(buffer, utf8, utf8Start - utf8, utf8Start - utf8, 0);
601
Ben Wagner8d45a382017-11-16 10:08:28 -0500602 // Populate the hb_buffer directly with utf8 cluster indexes.
603 const char* utf8Current = utf8Start;
604 while (utf8Current < utf8End) {
605 unsigned int cluster = utf8Current - utf8Start;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400606 hb_codepoint_t u = utf8_next(&utf8Current, utf8End);
Ben Wagner8d45a382017-11-16 10:08:28 -0500607 hb_buffer_add(buffer, u, cluster);
608 }
609
Ben Wagnerc0c99b32018-08-07 10:14:18 -0400610 // Add postcontext.
611 hb_buffer_add_utf8(buffer, utf8Current, utf8 + utf8Bytes - utf8Current, 0, 0);
612
Ben Wagner8d45a382017-11-16 10:08:28 -0500613 size_t utf8runLength = utf8End - utf8Start;
614 if (!SkTFitsIn<int>(utf8runLength)) {
615 SkDebugf("Shaping error: utf8 too long");
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500616 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500617 }
618 hb_buffer_set_script(buffer, script->currentScript());
619 hb_direction_t direction = is_LTR(bidi->currentLevel()) ? HB_DIRECTION_LTR:HB_DIRECTION_RTL;
620 hb_buffer_set_direction(buffer, direction);
621 // TODO: language
622 hb_buffer_guess_segment_properties(buffer);
623 // TODO: features
Hal Canary0dfa2082018-10-31 13:02:49 -0400624 if (!font->currentHBFont()) {
625 continue;
626 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500627 hb_shape(font->currentHBFont(), buffer, nullptr, 0);
628 unsigned len = hb_buffer_get_length(buffer);
629 if (len == 0) {
630 continue;
631 }
632
633 if (direction == HB_DIRECTION_RTL) {
634 // Put the clusters back in logical order.
635 // Note that the advances remain ltr.
636 hb_buffer_reverse(buffer);
637 }
638 hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, nullptr);
639 hb_glyph_position_t* pos = hb_buffer_get_glyph_positions(buffer, nullptr);
640
641 if (!SkTFitsIn<int>(len)) {
642 SkDebugf("Shaping error: too many glyphs");
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500643 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500644 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400645
Hal Canary2a1848d2018-11-26 17:23:24 -0500646 SkFont paint(srcPaint);
Ben Wagner8d45a382017-11-16 10:08:28 -0500647 paint.setTypeface(sk_ref_sp(font->currentTypeface()));
648 ShapedRun& run = runs.emplace_back(utf8Start, utf8End, len, paint, bidi->currentLevel(),
649 std::unique_ptr<ShapedGlyph[]>(new ShapedGlyph[len]));
650 int scaleX, scaleY;
651 hb_font_get_scale(font->currentHBFont(), &scaleX, &scaleY);
Mike Reed6d595682018-12-05 17:28:14 -0500652 double textSizeY = run.fFont.getSize() / scaleY;
653 double textSizeX = run.fFont.getSize() / scaleX * run.fFont.getScaleX();
Florin Malita950243d2019-01-11 11:08:35 -0500654 SkVector runAdvance = { 0, 0 };
Ben Wagner8d45a382017-11-16 10:08:28 -0500655 for (unsigned i = 0; i < len; i++) {
656 ShapedGlyph& glyph = run.fGlyphs[i];
657 glyph.fID = info[i].codepoint;
658 glyph.fCluster = info[i].cluster;
659 glyph.fOffset.fX = pos[i].x_offset * textSizeX;
660 glyph.fOffset.fY = pos[i].y_offset * textSizeY;
661 glyph.fAdvance.fX = pos[i].x_advance * textSizeX;
662 glyph.fAdvance.fY = pos[i].y_advance * textSizeY;
663 glyph.fHasVisual = true; //!font->currentTypeface()->glyphBoundsAreZero(glyph.fID);
664 //info->mask safe_to_break;
665 glyph.fMustLineBreakBefore = false;
Florin Malita950243d2019-01-11 11:08:35 -0500666
667 runAdvance += glyph.fAdvance;
Ben Wagner8d45a382017-11-16 10:08:28 -0500668 }
Florin Malita950243d2019-01-11 11:08:35 -0500669 run.fAdvance = runAdvance;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400670
Ben Wagner8d45a382017-11-16 10:08:28 -0500671 int32_t clusterOffset = utf8Start - utf8;
672 uint32_t previousCluster = 0xFFFFFFFF;
673 for (unsigned i = 0; i < len; ++i) {
674 ShapedGlyph& glyph = run.fGlyphs[i];
675 int32_t glyphCluster = glyph.fCluster + clusterOffset;
676 int32_t breakIteratorCurrent = breakIterator.current();
677 while (breakIteratorCurrent != icu::BreakIterator::DONE &&
678 breakIteratorCurrent < glyphCluster)
679 {
680 breakIteratorCurrent = breakIterator.next();
Ben Wagner2868b782017-08-31 14:12:27 -0400681 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500682 glyph.fMayLineBreakBefore = glyph.fCluster != previousCluster &&
683 breakIteratorCurrent == glyphCluster;
684 previousCluster = glyph.fCluster;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400685 }
686 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500687}
688
689// Iterate over the glyphs in logical order to mark line endings.
690{
691 SkScalar widthSoFar = 0;
692 bool previousBreakValid = false; // Set when previousBreak is set to a valid candidate break.
693 bool canAddBreakNow = false; // Disallow line breaks before the first glyph of a run.
694 ShapedRunGlyphIterator previousBreak(runs);
695 ShapedRunGlyphIterator glyphIterator(runs);
696 while (ShapedGlyph* glyph = glyphIterator.current()) {
697 if (canAddBreakNow && glyph->fMayLineBreakBefore) {
698 previousBreakValid = true;
699 previousBreak = glyphIterator;
700 }
701 SkScalar glyphWidth = glyph->fAdvance.fX;
Ben Wagnera900ad52018-08-31 17:48:19 -0400702 // TODO: if the glyph is non-visible it can be added.
Ben Wagner8d45a382017-11-16 10:08:28 -0500703 if (widthSoFar + glyphWidth < width) {
704 widthSoFar += glyphWidth;
705 glyphIterator.next();
706 canAddBreakNow = true;
707 continue;
708 }
709
Ben Wagnera900ad52018-08-31 17:48:19 -0400710 // TODO: for both of these emergency break cases
711 // don't break grapheme clusters and pull in any zero width or non-visible
Ben Wagner8d45a382017-11-16 10:08:28 -0500712 if (widthSoFar == 0) {
713 // Adding just this glyph is too much, just break with this glyph
714 glyphIterator.next();
715 previousBreak = glyphIterator;
716 } else if (!previousBreakValid) {
Ben Wagnera900ad52018-08-31 17:48:19 -0400717 // No break opportunity found yet, just break without this glyph
Ben Wagner8d45a382017-11-16 10:08:28 -0500718 previousBreak = glyphIterator;
719 }
720 glyphIterator = previousBreak;
721 glyph = glyphIterator.current();
722 if (glyph) {
723 glyph->fMustLineBreakBefore = true;
724 }
725 widthSoFar = 0;
726 previousBreakValid = false;
727 canAddBreakNow = false;
728 }
729}
730
731// Reorder the runs and glyphs per line and write them out.
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500732 SkPoint currentPoint = point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500733{
734 ShapedRunGlyphIterator previousBreak(runs);
735 ShapedRunGlyphIterator glyphIterator(runs);
736 SkScalar maxAscent = 0;
737 SkScalar maxDescent = 0;
738 SkScalar maxLeading = 0;
739 int previousRunIndex = -1;
Florin Malita950243d2019-01-11 11:08:35 -0500740 size_t lineIndex = 0;
Ben Wagner8d45a382017-11-16 10:08:28 -0500741 while (glyphIterator.current()) {
742 int runIndex = glyphIterator.fRunIndex;
743 int glyphIndex = glyphIterator.fGlyphIndex;
744 ShapedGlyph* nextGlyph = glyphIterator.next();
745
746 if (previousRunIndex != runIndex) {
Mike Reedb5784ac2018-11-12 09:35:15 -0500747 SkFontMetrics metrics;
Mike Reed6d595682018-12-05 17:28:14 -0500748 runs[runIndex].fFont.getMetrics(&metrics);
Ben Wagner8d45a382017-11-16 10:08:28 -0500749 maxAscent = SkTMin(maxAscent, metrics.fAscent);
750 maxDescent = SkTMax(maxDescent, metrics.fDescent);
751 maxLeading = SkTMax(maxLeading, metrics.fLeading);
752 previousRunIndex = runIndex;
753 }
754
755 // Nothing can be written until the baseline is known.
756 if (!(nextGlyph == nullptr || nextGlyph->fMustLineBreakBefore)) {
757 continue;
758 }
759
760 currentPoint.fY -= maxAscent;
761
762 int numRuns = runIndex - previousBreak.fRunIndex + 1;
763 SkAutoSTMalloc<4, UBiDiLevel> runLevels(numRuns);
764 for (int i = 0; i < numRuns; ++i) {
765 runLevels[i] = runs[previousBreak.fRunIndex + i].fLevel;
766 }
767 SkAutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
768 ubidi_reorderVisual(runLevels, numRuns, logicalFromVisual);
769
770 for (int i = 0; i < numRuns; ++i) {
771 int logicalIndex = previousBreak.fRunIndex + logicalFromVisual[i];
772
773 int startGlyphIndex = (logicalIndex == previousBreak.fRunIndex)
774 ? previousBreak.fGlyphIndex
775 : 0;
776 int endGlyphIndex = (logicalIndex == runIndex)
777 ? glyphIndex + 1
778 : runs[logicalIndex].fNumGlyphs;
Florin Malita950243d2019-01-11 11:08:35 -0500779
780 const auto& run = runs[logicalIndex];
781 const RunHandler::RunInfo info = {
782 lineIndex,
783 run.fAdvance,
784 maxAscent,
785 maxDescent,
786 maxLeading,
787 };
788 append(handler, info, run, startGlyphIndex, endGlyphIndex, &currentPoint);
Ben Wagner8d45a382017-11-16 10:08:28 -0500789 }
790
791 currentPoint.fY += maxDescent + maxLeading;
792 currentPoint.fX = point.fX;
793 maxAscent = 0;
794 maxDescent = 0;
795 maxLeading = 0;
796 previousRunIndex = -1;
Florin Malita950243d2019-01-11 11:08:35 -0500797 ++lineIndex;
Ben Wagner8d45a382017-11-16 10:08:28 -0500798 previousBreak = glyphIterator;
799 }
800}
801
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500802 return currentPoint;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400803}