blob: a7abe93756fd3ded77f7a95604c8ee13c968dd06 [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
8#include <hb-ot.h>
Ben Wagner8d45a382017-11-16 10:08:28 -05009#include <unicode/brkiter.h>
10#include <unicode/locid.h>
Ben Wagnera25fbef2017-08-30 13:56:19 -040011#include <unicode/stringpiece.h>
12#include <unicode/ubidi.h>
Ben Wagner8d45a382017-11-16 10:08:28 -050013#include <unicode/uchriter.h>
Ben Wagnera25fbef2017-08-30 13:56:19 -040014#include <unicode/unistr.h>
Ben Wagner8d45a382017-11-16 10:08:28 -050015#include <unicode/uscript.h>
Ben Wagnera25fbef2017-08-30 13:56:19 -040016
Ben Wagner67e3a302017-09-05 14:46:19 -040017#include "SkFontMgr.h"
Hal Canary0e07ad72018-02-08 13:06:56 -050018#include "SkLoadICU.h"
19#include "SkOnce.h"
Ben Wagnera25fbef2017-08-30 13:56:19 -040020#include "SkShaper.h"
21#include "SkStream.h"
Ben Wagner8d45a382017-11-16 10:08:28 -050022#include "SkTDPQueue.h"
23#include "SkTLazy.h"
Ben Wagnere0001732017-08-31 16:26:26 -040024#include "SkTemplates.h"
Ben Wagnera25fbef2017-08-30 13:56:19 -040025#include "SkTextBlob.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040026#include "SkTo.h"
Ben Wagnera25fbef2017-08-30 13:56:19 -040027#include "SkTypeface.h"
28#include "SkUtils.h"
29
Ben Wagnera25fbef2017-08-30 13:56:19 -040030namespace {
31template <class T, void(*P)(T*)> using resource = std::unique_ptr<T, SkFunctionWrapper<void, T, P>>;
32using HBBlob = resource<hb_blob_t , hb_blob_destroy >;
33using HBFace = resource<hb_face_t , hb_face_destroy >;
34using HBFont = resource<hb_font_t , hb_font_destroy >;
35using HBBuffer = resource<hb_buffer_t, hb_buffer_destroy>;
36using ICUBiDi = resource<UBiDi , ubidi_close >;
37
38HBBlob stream_to_blob(std::unique_ptr<SkStreamAsset> asset) {
39 size_t size = asset->getLength();
40 HBBlob blob;
41 if (const void* base = asset->getMemoryBase()) {
42 blob.reset(hb_blob_create((char*)base, SkToUInt(size),
43 HB_MEMORY_MODE_READONLY, asset.release(),
44 [](void* p) { delete (SkStreamAsset*)p; }));
45 } else {
46 // SkDebugf("Extra SkStreamAsset copy\n");
47 void* ptr = size ? sk_malloc_throw(size) : nullptr;
48 asset->read(ptr, size);
49 blob.reset(hb_blob_create((char*)ptr, SkToUInt(size),
50 HB_MEMORY_MODE_READONLY, ptr, sk_free));
51 }
52 SkASSERT(blob);
53 hb_blob_make_immutable(blob.get());
54 return blob;
55}
Ben Wagnera25fbef2017-08-30 13:56:19 -040056
Ben Wagner8d45a382017-11-16 10:08:28 -050057HBFont create_hb_font(SkTypeface* tf) {
Ben Wagnera25fbef2017-08-30 13:56:19 -040058 int index;
Ben Wagnere0001732017-08-31 16:26:26 -040059 HBBlob blob(stream_to_blob(std::unique_ptr<SkStreamAsset>(tf->openStream(&index))));
Ben Wagnera25fbef2017-08-30 13:56:19 -040060 HBFace face(hb_face_create(blob.get(), (unsigned)index));
61 SkASSERT(face);
62 if (!face) {
Ben Wagnere0001732017-08-31 16:26:26 -040063 return nullptr;
Ben Wagnera25fbef2017-08-30 13:56:19 -040064 }
65 hb_face_set_index(face.get(), (unsigned)index);
Ben Wagnere0001732017-08-31 16:26:26 -040066 hb_face_set_upem(face.get(), tf->getUnitsPerEm());
Ben Wagnera25fbef2017-08-30 13:56:19 -040067
Ben Wagnere0001732017-08-31 16:26:26 -040068 HBFont font(hb_font_create(face.get()));
69 SkASSERT(font);
70 if (!font) {
71 return nullptr;
72 }
Ben Wagnere0001732017-08-31 16:26:26 -040073 hb_ot_font_set_funcs(font.get());
74 int axis_count = tf->getVariationDesignPosition(nullptr, 0);
75 if (axis_count > 0) {
76 SkAutoSTMalloc<4, SkFontArguments::VariationPosition::Coordinate> axis_values(axis_count);
77 if (tf->getVariationDesignPosition(axis_values, axis_count) == axis_count) {
78 hb_font_set_variations(font.get(),
79 reinterpret_cast<hb_variation_t*>(axis_values.get()),
80 axis_count);
81 }
82 }
83 return font;
84}
85
Hal Canaryf107a2f2018-07-25 16:52:48 -040086/** this version replaces invalid utf-8 sequences with code point U+FFFD. */
87static inline SkUnichar utf8_next(const char** ptr, const char* end) {
88 SkUnichar val = SkUTF::NextUTF8(ptr, end);
89 if (val < 0) {
90 return 0xFFFD; // REPLACEMENT CHARACTER
91 }
92 return val;
93}
94
Ben Wagner8d45a382017-11-16 10:08:28 -050095class RunIterator {
96public:
97 virtual ~RunIterator() {}
98 virtual void consume() = 0;
99 // Pointer one past the last (utf8) element in the current run.
100 virtual const char* endOfCurrentRun() const = 0;
101 virtual bool atEnd() const = 0;
102 bool operator<(const RunIterator& that) const {
103 return this->endOfCurrentRun() < that.endOfCurrentRun();
104 }
105};
106
107class BiDiRunIterator : public RunIterator {
108public:
109 static SkTLazy<BiDiRunIterator> Make(const char* utf8, size_t utf8Bytes, UBiDiLevel level) {
110 SkTLazy<BiDiRunIterator> ret;
111
112 // ubidi only accepts utf16 (though internally it basically works on utf32 chars).
113 // We want an ubidi_setPara(UBiDi*, UText*, UBiDiLevel, UBiDiLevel*, UErrorCode*);
114 if (!SkTFitsIn<int32_t>(utf8Bytes)) {
115 SkDebugf("Bidi error: text too long");
116 return ret;
117 }
118 icu::UnicodeString utf16 = icu::UnicodeString::fromUTF8(icu::StringPiece(utf8, utf8Bytes));
119
120 UErrorCode status = U_ZERO_ERROR;
121 ICUBiDi bidi(ubidi_openSized(utf16.length(), 0, &status));
122 if (U_FAILURE(status)) {
123 SkDebugf("Bidi error: %s", u_errorName(status));
124 return ret;
125 }
126 SkASSERT(bidi);
127
128 // The required lifetime of utf16 isn't well documented.
129 // It appears it isn't used after ubidi_setPara except through ubidi_getText.
130 ubidi_setPara(bidi.get(), utf16.getBuffer(), utf16.length(), level, nullptr, &status);
131 if (U_FAILURE(status)) {
132 SkDebugf("Bidi error: %s", u_errorName(status));
133 return ret;
134 }
135
Hal Canary4014ba62018-07-24 11:33:21 -0400136 ret.init(utf8, utf8 + utf8Bytes, std::move(bidi));
Ben Wagner8d45a382017-11-16 10:08:28 -0500137 return ret;
138 }
Hal Canary4014ba62018-07-24 11:33:21 -0400139 BiDiRunIterator(const char* utf8, const char* end, ICUBiDi bidi)
Ben Wagner8d45a382017-11-16 10:08:28 -0500140 : fBidi(std::move(bidi))
141 , fEndOfCurrentRun(utf8)
Hal Canary4014ba62018-07-24 11:33:21 -0400142 , fEndOfAllRuns(end)
Ben Wagner8d45a382017-11-16 10:08:28 -0500143 , fUTF16LogicalPosition(0)
144 , fLevel(UBIDI_DEFAULT_LTR)
145 {}
146 void consume() override {
147 SkASSERT(fUTF16LogicalPosition < ubidi_getLength(fBidi.get()));
148 int32_t endPosition = ubidi_getLength(fBidi.get());
149 fLevel = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400150 SkUnichar u = utf8_next(&fEndOfCurrentRun, fEndOfAllRuns);
151 fUTF16LogicalPosition += SkUTF::ToUTF16(u);
Ben Wagner8d45a382017-11-16 10:08:28 -0500152 UBiDiLevel level;
153 while (fUTF16LogicalPosition < endPosition) {
154 level = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
155 if (level != fLevel) {
156 break;
157 }
Hal Canaryf107a2f2018-07-25 16:52:48 -0400158 u = utf8_next(&fEndOfCurrentRun, fEndOfAllRuns);
159 fUTF16LogicalPosition += SkUTF::ToUTF16(u);
Ben Wagner8d45a382017-11-16 10:08:28 -0500160 }
161 }
162 const char* endOfCurrentRun() const override {
163 return fEndOfCurrentRun;
164 }
165 bool atEnd() const override {
166 return fUTF16LogicalPosition == ubidi_getLength(fBidi.get());
167 }
168
169 UBiDiLevel currentLevel() const {
170 return fLevel;
171 }
172private:
173 ICUBiDi fBidi;
174 const char* fEndOfCurrentRun;
Hal Canary4014ba62018-07-24 11:33:21 -0400175 const char* fEndOfAllRuns;
Ben Wagner8d45a382017-11-16 10:08:28 -0500176 int32_t fUTF16LogicalPosition;
177 UBiDiLevel fLevel;
178};
179
180class ScriptRunIterator : public RunIterator {
181public:
182 static SkTLazy<ScriptRunIterator> Make(const char* utf8, size_t utf8Bytes,
183 hb_unicode_funcs_t* hbUnicode)
184 {
185 SkTLazy<ScriptRunIterator> ret;
186 ret.init(utf8, utf8Bytes, hbUnicode);
187 return ret;
188 }
189 ScriptRunIterator(const char* utf8, size_t utf8Bytes, hb_unicode_funcs_t* hbUnicode)
190 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
191 , fHBUnicode(hbUnicode)
192 , fCurrentScript(HB_SCRIPT_UNKNOWN)
193 {}
194 void consume() override {
195 SkASSERT(fCurrent < fEnd);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400196 SkUnichar u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500197 fCurrentScript = hb_unicode_script(fHBUnicode, u);
198 while (fCurrent < fEnd) {
199 const char* prev = fCurrent;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400200 u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500201 const hb_script_t script = hb_unicode_script(fHBUnicode, u);
202 if (script != fCurrentScript) {
203 if (fCurrentScript == HB_SCRIPT_INHERITED || fCurrentScript == HB_SCRIPT_COMMON) {
204 fCurrentScript = script;
205 } else if (script == HB_SCRIPT_INHERITED || script == HB_SCRIPT_COMMON) {
206 continue;
207 } else {
208 fCurrent = prev;
209 break;
210 }
211 }
212 }
213 if (fCurrentScript == HB_SCRIPT_INHERITED) {
214 fCurrentScript = HB_SCRIPT_COMMON;
215 }
216 }
217 const char* endOfCurrentRun() const override {
218 return fCurrent;
219 }
220 bool atEnd() const override {
221 return fCurrent == fEnd;
222 }
223
224 hb_script_t currentScript() const {
225 return fCurrentScript;
226 }
227private:
228 const char* fCurrent;
229 const char* fEnd;
230 hb_unicode_funcs_t* fHBUnicode;
231 hb_script_t fCurrentScript;
232};
233
234class FontRunIterator : public RunIterator {
235public:
236 static SkTLazy<FontRunIterator> Make(const char* utf8, size_t utf8Bytes,
237 sk_sp<SkTypeface> typeface,
238 hb_font_t* hbFace,
239 sk_sp<SkFontMgr> fallbackMgr)
240 {
241 SkTLazy<FontRunIterator> ret;
242 ret.init(utf8, utf8Bytes, std::move(typeface), hbFace, std::move(fallbackMgr));
243 return ret;
244 }
245 FontRunIterator(const char* utf8, size_t utf8Bytes, sk_sp<SkTypeface> typeface,
246 hb_font_t* hbFace, sk_sp<SkFontMgr> fallbackMgr)
247 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
248 , fFallbackMgr(std::move(fallbackMgr))
249 , fHBFont(hbFace), fTypeface(std::move(typeface))
250 , fFallbackHBFont(nullptr), fFallbackTypeface(nullptr)
251 , fCurrentHBFont(fHBFont), fCurrentTypeface(fTypeface.get())
252 {}
253 void consume() override {
254 SkASSERT(fCurrent < fEnd);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400255 SkUnichar u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500256 // If the starting typeface can handle this character, use it.
257 if (fTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1)) {
258 fFallbackTypeface.reset();
259 // If not, try to find a fallback typeface
260 } else {
261 fFallbackTypeface.reset(fFallbackMgr->matchFamilyStyleCharacter(
262 nullptr, fTypeface->fontStyle(), nullptr, 0, u));
263 }
264
265 if (fFallbackTypeface) {
266 fFallbackHBFont = create_hb_font(fFallbackTypeface.get());
267 fCurrentTypeface = fFallbackTypeface.get();
268 fCurrentHBFont = fFallbackHBFont.get();
269 } else {
270 fFallbackHBFont.reset();
271 fCurrentTypeface = fTypeface.get();
272 fCurrentHBFont = fHBFont;
273 }
274
275 while (fCurrent < fEnd) {
276 const char* prev = fCurrent;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400277 u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500278
279 // If using a fallback and the initial typeface has this character, stop fallback.
280 if (fFallbackTypeface &&
281 fTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1))
282 {
283 fCurrent = prev;
284 return;
285 }
286 // If the current typeface cannot handle this character, stop using it.
287 if (!fCurrentTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1)) {
288 fCurrent = prev;
289 return;
290 }
291 }
292 }
293 const char* endOfCurrentRun() const override {
294 return fCurrent;
295 }
296 bool atEnd() const override {
297 return fCurrent == fEnd;
298 }
299
300 SkTypeface* currentTypeface() const {
301 return fCurrentTypeface;
302 }
303 hb_font_t* currentHBFont() const {
304 return fCurrentHBFont;
305 }
306private:
307 const char* fCurrent;
308 const char* fEnd;
309 sk_sp<SkFontMgr> fFallbackMgr;
310 hb_font_t* fHBFont;
311 sk_sp<SkTypeface> fTypeface;
312 HBFont fFallbackHBFont;
313 sk_sp<SkTypeface> fFallbackTypeface;
314 hb_font_t* fCurrentHBFont;
315 SkTypeface* fCurrentTypeface;
316};
317
318class RunIteratorQueue {
319public:
320 void insert(RunIterator* runIterator) {
321 fRunIterators.insert(runIterator);
322 }
323
324 bool advanceRuns() {
325 const RunIterator* leastRun = fRunIterators.peek();
326 if (leastRun->atEnd()) {
327 SkASSERT(this->allRunsAreAtEnd());
328 return false;
329 }
330 const char* leastEnd = leastRun->endOfCurrentRun();
331 RunIterator* currentRun = nullptr;
332 SkDEBUGCODE(const char* previousEndOfCurrentRun);
333 while ((currentRun = fRunIterators.peek())->endOfCurrentRun() <= leastEnd) {
334 fRunIterators.pop();
335 SkDEBUGCODE(previousEndOfCurrentRun = currentRun->endOfCurrentRun());
336 currentRun->consume();
337 SkASSERT(previousEndOfCurrentRun < currentRun->endOfCurrentRun());
338 fRunIterators.insert(currentRun);
339 }
340 return true;
341 }
342
343 const char* endOfCurrentRun() const {
344 return fRunIterators.peek()->endOfCurrentRun();
345 }
346
347private:
348 bool allRunsAreAtEnd() const {
349 for (int i = 0; i < fRunIterators.count(); ++i) {
350 if (!fRunIterators.at(i)->atEnd()) {
351 return false;
352 }
353 }
354 return true;
355 }
356
357 static bool CompareRunIterator(RunIterator* const& a, RunIterator* const& b) {
358 return *a < *b;
359 }
360 SkTDPQueue<RunIterator*, CompareRunIterator> fRunIterators;
361};
362
363struct ShapedGlyph {
364 SkGlyphID fID;
365 uint32_t fCluster;
366 SkPoint fOffset;
367 SkVector fAdvance;
368 bool fMayLineBreakBefore;
369 bool fMustLineBreakBefore;
370 bool fHasVisual;
371};
372struct ShapedRun {
373 ShapedRun(const char* utf8Start, const char* utf8End, int numGlyphs, const SkPaint& paint,
374 UBiDiLevel level, std::unique_ptr<ShapedGlyph[]> glyphs)
375 : fUtf8Start(utf8Start), fUtf8End(utf8End), fNumGlyphs(numGlyphs), fPaint(paint)
376 , fLevel(level), fGlyphs(std::move(glyphs))
377 {}
378
379 const char* fUtf8Start;
380 const char* fUtf8End;
381 int fNumGlyphs;
382 SkPaint fPaint;
383 UBiDiLevel fLevel;
384 std::unique_ptr<ShapedGlyph[]> fGlyphs;
385};
386
387static constexpr bool is_LTR(UBiDiLevel level) {
388 return (level & 1) == 0;
389}
390
391static void append(SkTextBlobBuilder* b, const ShapedRun& run, int start, int end, SkPoint* p) {
392 unsigned len = end - start;
393 auto runBuffer = b->allocRunTextPos(run.fPaint, len, run.fUtf8End - run.fUtf8Start, SkString());
394 memcpy(runBuffer.utf8text, run.fUtf8Start, run.fUtf8End - run.fUtf8Start);
395
396 for (unsigned i = 0; i < len; i++) {
397 // Glyphs are in logical order, but output ltr since PDF readers seem to expect that.
398 const ShapedGlyph& glyph = run.fGlyphs[is_LTR(run.fLevel) ? start + i : end - 1 - i];
399 runBuffer.glyphs[i] = glyph.fID;
400 runBuffer.clusters[i] = glyph.fCluster;
401 reinterpret_cast<SkPoint*>(runBuffer.pos)[i] =
402 SkPoint::Make(p->fX + glyph.fOffset.fX, p->fY - glyph.fOffset.fY);
403 p->fX += glyph.fAdvance.fX;
404 p->fY += glyph.fAdvance.fY;
405 }
406}
407
408struct ShapedRunGlyphIterator {
409 ShapedRunGlyphIterator(const SkTArray<ShapedRun>& origRuns)
410 : fRuns(&origRuns), fRunIndex(0), fGlyphIndex(0)
411 { }
412
413 ShapedRunGlyphIterator(const ShapedRunGlyphIterator& that) = default;
414 ShapedRunGlyphIterator& operator=(const ShapedRunGlyphIterator& that) = default;
415 bool operator==(const ShapedRunGlyphIterator& that) const {
416 return fRuns == that.fRuns &&
417 fRunIndex == that.fRunIndex &&
418 fGlyphIndex == that.fGlyphIndex;
419 }
420 bool operator!=(const ShapedRunGlyphIterator& that) const {
421 return fRuns != that.fRuns ||
422 fRunIndex != that.fRunIndex ||
423 fGlyphIndex != that.fGlyphIndex;
424 }
425
426 ShapedGlyph* next() {
427 const SkTArray<ShapedRun>& runs = *fRuns;
428 SkASSERT(fRunIndex < runs.count());
429 SkASSERT(fGlyphIndex < runs[fRunIndex].fNumGlyphs);
430
431 ++fGlyphIndex;
432 if (fGlyphIndex == runs[fRunIndex].fNumGlyphs) {
433 fGlyphIndex = 0;
434 ++fRunIndex;
435 if (fRunIndex >= runs.count()) {
436 return nullptr;
437 }
438 }
439 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
440 }
441
442 ShapedGlyph* current() {
443 const SkTArray<ShapedRun>& runs = *fRuns;
444 if (fRunIndex >= runs.count()) {
445 return nullptr;
446 }
447 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
448 }
449
450 const SkTArray<ShapedRun>* fRuns;
451 int fRunIndex;
452 int fGlyphIndex;
453};
454
455} // namespace
456
457struct SkShaper::Impl {
458 HBFont fHarfBuzzFont;
459 HBBuffer fBuffer;
460 sk_sp<SkTypeface> fTypeface;
461 std::unique_ptr<icu::BreakIterator> fBreakIterator;
462};
463
Ben Wagnere0001732017-08-31 16:26:26 -0400464SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
Hal Canary0e07ad72018-02-08 13:06:56 -0500465 SkOnce once;
466 once([] { SkLoadICU(); });
467
Ben Wagnere0001732017-08-31 16:26:26 -0400468 fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
469 fImpl->fHarfBuzzFont = create_hb_font(fImpl->fTypeface.get());
Ben Wagnera25fbef2017-08-30 13:56:19 -0400470 SkASSERT(fImpl->fHarfBuzzFont);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400471 fImpl->fBuffer.reset(hb_buffer_create());
Ben Wagner8d45a382017-11-16 10:08:28 -0500472 SkASSERT(fImpl->fBuffer);
473
474 icu::Locale thai("th");
475 UErrorCode status = U_ZERO_ERROR;
476 fImpl->fBreakIterator.reset(icu::BreakIterator::createLineInstance(thai, status));
477 if (U_FAILURE(status)) {
478 SkDebugf("Could not create break iterator: %s", u_errorName(status));
479 SK_ABORT("");
480 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400481}
482
483SkShaper::~SkShaper() {}
484
Ben Wagner8d45a382017-11-16 10:08:28 -0500485bool SkShaper::good() const {
486 return fImpl->fHarfBuzzFont &&
487 fImpl->fBuffer &&
488 fImpl->fTypeface &&
489 fImpl->fBreakIterator;
490}
Ben Wagnera25fbef2017-08-30 13:56:19 -0400491
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500492SkPoint SkShaper::shape(SkTextBlobBuilder* builder,
493 const SkPaint& srcPaint,
494 const char* utf8,
495 size_t utf8Bytes,
496 bool leftToRight,
497 SkPoint point,
498 SkScalar width) const {
Ben Wagner67e3a302017-09-05 14:46:19 -0400499 sk_sp<SkFontMgr> fontMgr = SkFontMgr::RefDefault();
Ben Wagnera25fbef2017-08-30 13:56:19 -0400500 SkASSERT(builder);
Ben Wagner8d45a382017-11-16 10:08:28 -0500501 UBiDiLevel defaultLevel = leftToRight ? UBIDI_DEFAULT_LTR : UBIDI_DEFAULT_RTL;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400502 //hb_script_t script = ...
Ben Wagnera25fbef2017-08-30 13:56:19 -0400503
Ben Wagner8d45a382017-11-16 10:08:28 -0500504 SkTArray<ShapedRun> runs;
505{
506 RunIteratorQueue runSegmenter;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400507
Ben Wagner8d45a382017-11-16 10:08:28 -0500508 SkTLazy<BiDiRunIterator> maybeBidi(BiDiRunIterator::Make(utf8, utf8Bytes, defaultLevel));
509 BiDiRunIterator* bidi = maybeBidi.getMaybeNull();
510 if (!bidi) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500511 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400512 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500513 runSegmenter.insert(bidi);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400514
Ben Wagner8d45a382017-11-16 10:08:28 -0500515 hb_unicode_funcs_t* hbUnicode = hb_buffer_get_unicode_funcs(fImpl->fBuffer.get());
516 SkTLazy<ScriptRunIterator> maybeScript(ScriptRunIterator::Make(utf8, utf8Bytes, hbUnicode));
517 ScriptRunIterator* script = maybeScript.getMaybeNull();
518 if (!script) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500519 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400520 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500521 runSegmenter.insert(script);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400522
Ben Wagner8d45a382017-11-16 10:08:28 -0500523 SkTLazy<FontRunIterator> maybeFont(FontRunIterator::Make(utf8, utf8Bytes,
524 fImpl->fTypeface,
525 fImpl->fHarfBuzzFont.get(),
526 std::move(fontMgr)));
527 FontRunIterator* font = maybeFont.getMaybeNull();
528 if (!font) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500529 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400530 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500531 runSegmenter.insert(font);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400532
Ben Wagner8d45a382017-11-16 10:08:28 -0500533 icu::BreakIterator& breakIterator = *fImpl->fBreakIterator;
534 {
535 UErrorCode status = U_ZERO_ERROR;
536 UText utf8UText = UTEXT_INITIALIZER;
537 utext_openUTF8(&utf8UText, utf8, utf8Bytes, &status);
538 std::unique_ptr<UText, SkFunctionWrapper<UText*, UText, utext_close>> autoClose(&utf8UText);
539 if (U_FAILURE(status)) {
540 SkDebugf("Could not create utf8UText: %s", u_errorName(status));
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500541 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500542 }
543 breakIterator.setText(&utf8UText, status);
544 //utext_close(&utf8UText);
545 if (U_FAILURE(status)) {
546 SkDebugf("Could not setText on break iterator: %s", u_errorName(status));
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500547 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500548 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400549 }
550
Ben Wagner8d45a382017-11-16 10:08:28 -0500551 const char* utf8Start = nullptr;
552 const char* utf8End = utf8;
553 while (runSegmenter.advanceRuns()) {
554 utf8Start = utf8End;
555 utf8End = runSegmenter.endOfCurrentRun();
556
557 hb_buffer_t* buffer = fImpl->fBuffer.get();
558 SkAutoTCallVProc<hb_buffer_t, hb_buffer_clear_contents> autoClearBuffer(buffer);
559 hb_buffer_set_content_type(buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
560 hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
561
Ben Wagnerc0c99b32018-08-07 10:14:18 -0400562 // Add precontext.
563 hb_buffer_add_utf8(buffer, utf8, utf8Start - utf8, utf8Start - utf8, 0);
564
Ben Wagner8d45a382017-11-16 10:08:28 -0500565 // Populate the hb_buffer directly with utf8 cluster indexes.
566 const char* utf8Current = utf8Start;
567 while (utf8Current < utf8End) {
568 unsigned int cluster = utf8Current - utf8Start;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400569 hb_codepoint_t u = utf8_next(&utf8Current, utf8End);
Ben Wagner8d45a382017-11-16 10:08:28 -0500570 hb_buffer_add(buffer, u, cluster);
571 }
572
Ben Wagnerc0c99b32018-08-07 10:14:18 -0400573 // Add postcontext.
574 hb_buffer_add_utf8(buffer, utf8Current, utf8 + utf8Bytes - utf8Current, 0, 0);
575
Ben Wagner8d45a382017-11-16 10:08:28 -0500576 size_t utf8runLength = utf8End - utf8Start;
577 if (!SkTFitsIn<int>(utf8runLength)) {
578 SkDebugf("Shaping error: utf8 too long");
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500579 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500580 }
581 hb_buffer_set_script(buffer, script->currentScript());
582 hb_direction_t direction = is_LTR(bidi->currentLevel()) ? HB_DIRECTION_LTR:HB_DIRECTION_RTL;
583 hb_buffer_set_direction(buffer, direction);
584 // TODO: language
585 hb_buffer_guess_segment_properties(buffer);
586 // TODO: features
587 hb_shape(font->currentHBFont(), buffer, nullptr, 0);
588 unsigned len = hb_buffer_get_length(buffer);
589 if (len == 0) {
590 continue;
591 }
592
593 if (direction == HB_DIRECTION_RTL) {
594 // Put the clusters back in logical order.
595 // Note that the advances remain ltr.
596 hb_buffer_reverse(buffer);
597 }
598 hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, nullptr);
599 hb_glyph_position_t* pos = hb_buffer_get_glyph_positions(buffer, nullptr);
600
601 if (!SkTFitsIn<int>(len)) {
602 SkDebugf("Shaping error: too many glyphs");
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500603 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500604 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400605
606 SkPaint paint(srcPaint);
607 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Ben Wagner8d45a382017-11-16 10:08:28 -0500608 paint.setTypeface(sk_ref_sp(font->currentTypeface()));
609 ShapedRun& run = runs.emplace_back(utf8Start, utf8End, len, paint, bidi->currentLevel(),
610 std::unique_ptr<ShapedGlyph[]>(new ShapedGlyph[len]));
611 int scaleX, scaleY;
612 hb_font_get_scale(font->currentHBFont(), &scaleX, &scaleY);
613 double textSizeY = run.fPaint.getTextSize() / scaleY;
614 double textSizeX = run.fPaint.getTextSize() / scaleX * run.fPaint.getTextScaleX();
615 for (unsigned i = 0; i < len; i++) {
616 ShapedGlyph& glyph = run.fGlyphs[i];
617 glyph.fID = info[i].codepoint;
618 glyph.fCluster = info[i].cluster;
619 glyph.fOffset.fX = pos[i].x_offset * textSizeX;
620 glyph.fOffset.fY = pos[i].y_offset * textSizeY;
621 glyph.fAdvance.fX = pos[i].x_advance * textSizeX;
622 glyph.fAdvance.fY = pos[i].y_advance * textSizeY;
623 glyph.fHasVisual = true; //!font->currentTypeface()->glyphBoundsAreZero(glyph.fID);
624 //info->mask safe_to_break;
625 glyph.fMustLineBreakBefore = false;
626 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400627
Ben Wagner8d45a382017-11-16 10:08:28 -0500628 int32_t clusterOffset = utf8Start - utf8;
629 uint32_t previousCluster = 0xFFFFFFFF;
630 for (unsigned i = 0; i < len; ++i) {
631 ShapedGlyph& glyph = run.fGlyphs[i];
632 int32_t glyphCluster = glyph.fCluster + clusterOffset;
633 int32_t breakIteratorCurrent = breakIterator.current();
634 while (breakIteratorCurrent != icu::BreakIterator::DONE &&
635 breakIteratorCurrent < glyphCluster)
636 {
637 breakIteratorCurrent = breakIterator.next();
Ben Wagner2868b782017-08-31 14:12:27 -0400638 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500639 glyph.fMayLineBreakBefore = glyph.fCluster != previousCluster &&
640 breakIteratorCurrent == glyphCluster;
641 previousCluster = glyph.fCluster;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400642 }
643 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500644}
645
646// Iterate over the glyphs in logical order to mark line endings.
647{
648 SkScalar widthSoFar = 0;
649 bool previousBreakValid = false; // Set when previousBreak is set to a valid candidate break.
650 bool canAddBreakNow = false; // Disallow line breaks before the first glyph of a run.
651 ShapedRunGlyphIterator previousBreak(runs);
652 ShapedRunGlyphIterator glyphIterator(runs);
653 while (ShapedGlyph* glyph = glyphIterator.current()) {
654 if (canAddBreakNow && glyph->fMayLineBreakBefore) {
655 previousBreakValid = true;
656 previousBreak = glyphIterator;
657 }
658 SkScalar glyphWidth = glyph->fAdvance.fX;
659 if (widthSoFar + glyphWidth < width) {
660 widthSoFar += glyphWidth;
661 glyphIterator.next();
662 canAddBreakNow = true;
663 continue;
664 }
665
666 if (widthSoFar == 0) {
667 // Adding just this glyph is too much, just break with this glyph
668 glyphIterator.next();
669 previousBreak = glyphIterator;
670 } else if (!previousBreakValid) {
671 // No break opprotunity found yet, just break without this glyph
672 previousBreak = glyphIterator;
673 }
674 glyphIterator = previousBreak;
675 glyph = glyphIterator.current();
676 if (glyph) {
677 glyph->fMustLineBreakBefore = true;
678 }
679 widthSoFar = 0;
680 previousBreakValid = false;
681 canAddBreakNow = false;
682 }
683}
684
685// Reorder the runs and glyphs per line and write them out.
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500686 SkPoint currentPoint = point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500687{
688 ShapedRunGlyphIterator previousBreak(runs);
689 ShapedRunGlyphIterator glyphIterator(runs);
690 SkScalar maxAscent = 0;
691 SkScalar maxDescent = 0;
692 SkScalar maxLeading = 0;
693 int previousRunIndex = -1;
694 while (glyphIterator.current()) {
695 int runIndex = glyphIterator.fRunIndex;
696 int glyphIndex = glyphIterator.fGlyphIndex;
697 ShapedGlyph* nextGlyph = glyphIterator.next();
698
699 if (previousRunIndex != runIndex) {
700 SkPaint::FontMetrics metrics;
701 runs[runIndex].fPaint.getFontMetrics(&metrics);
702 maxAscent = SkTMin(maxAscent, metrics.fAscent);
703 maxDescent = SkTMax(maxDescent, metrics.fDescent);
704 maxLeading = SkTMax(maxLeading, metrics.fLeading);
705 previousRunIndex = runIndex;
706 }
707
708 // Nothing can be written until the baseline is known.
709 if (!(nextGlyph == nullptr || nextGlyph->fMustLineBreakBefore)) {
710 continue;
711 }
712
713 currentPoint.fY -= maxAscent;
714
715 int numRuns = runIndex - previousBreak.fRunIndex + 1;
716 SkAutoSTMalloc<4, UBiDiLevel> runLevels(numRuns);
717 for (int i = 0; i < numRuns; ++i) {
718 runLevels[i] = runs[previousBreak.fRunIndex + i].fLevel;
719 }
720 SkAutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
721 ubidi_reorderVisual(runLevels, numRuns, logicalFromVisual);
722
723 for (int i = 0; i < numRuns; ++i) {
724 int logicalIndex = previousBreak.fRunIndex + logicalFromVisual[i];
725
726 int startGlyphIndex = (logicalIndex == previousBreak.fRunIndex)
727 ? previousBreak.fGlyphIndex
728 : 0;
729 int endGlyphIndex = (logicalIndex == runIndex)
730 ? glyphIndex + 1
731 : runs[logicalIndex].fNumGlyphs;
732 append(builder, runs[logicalIndex], startGlyphIndex, endGlyphIndex, &currentPoint);
733 }
734
735 currentPoint.fY += maxDescent + maxLeading;
736 currentPoint.fX = point.fX;
737 maxAscent = 0;
738 maxDescent = 0;
739 maxLeading = 0;
740 previousRunIndex = -1;
741 previousBreak = glyphIterator;
742 }
743}
744
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500745 return currentPoint;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400746}