blob: 40414d9a79d99f861854f2f9dfa6411a0c653ba7 [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"
26#include "SkTypeface.h"
27#include "SkUtils.h"
28
Ben Wagnera25fbef2017-08-30 13:56:19 -040029namespace {
30template <class T, void(*P)(T*)> using resource = std::unique_ptr<T, SkFunctionWrapper<void, T, P>>;
31using HBBlob = resource<hb_blob_t , hb_blob_destroy >;
32using HBFace = resource<hb_face_t , hb_face_destroy >;
33using HBFont = resource<hb_font_t , hb_font_destroy >;
34using HBBuffer = resource<hb_buffer_t, hb_buffer_destroy>;
35using ICUBiDi = resource<UBiDi , ubidi_close >;
36
37HBBlob stream_to_blob(std::unique_ptr<SkStreamAsset> asset) {
38 size_t size = asset->getLength();
39 HBBlob blob;
40 if (const void* base = asset->getMemoryBase()) {
41 blob.reset(hb_blob_create((char*)base, SkToUInt(size),
42 HB_MEMORY_MODE_READONLY, asset.release(),
43 [](void* p) { delete (SkStreamAsset*)p; }));
44 } else {
45 // SkDebugf("Extra SkStreamAsset copy\n");
46 void* ptr = size ? sk_malloc_throw(size) : nullptr;
47 asset->read(ptr, size);
48 blob.reset(hb_blob_create((char*)ptr, SkToUInt(size),
49 HB_MEMORY_MODE_READONLY, ptr, sk_free));
50 }
51 SkASSERT(blob);
52 hb_blob_make_immutable(blob.get());
53 return blob;
54}
Ben Wagnera25fbef2017-08-30 13:56:19 -040055
Ben Wagner8d45a382017-11-16 10:08:28 -050056HBFont create_hb_font(SkTypeface* tf) {
Ben Wagnera25fbef2017-08-30 13:56:19 -040057 int index;
Ben Wagnere0001732017-08-31 16:26:26 -040058 HBBlob blob(stream_to_blob(std::unique_ptr<SkStreamAsset>(tf->openStream(&index))));
Ben Wagnera25fbef2017-08-30 13:56:19 -040059 HBFace face(hb_face_create(blob.get(), (unsigned)index));
60 SkASSERT(face);
61 if (!face) {
Ben Wagnere0001732017-08-31 16:26:26 -040062 return nullptr;
Ben Wagnera25fbef2017-08-30 13:56:19 -040063 }
64 hb_face_set_index(face.get(), (unsigned)index);
Ben Wagnere0001732017-08-31 16:26:26 -040065 hb_face_set_upem(face.get(), tf->getUnitsPerEm());
Ben Wagnera25fbef2017-08-30 13:56:19 -040066
Ben Wagnere0001732017-08-31 16:26:26 -040067 HBFont font(hb_font_create(face.get()));
68 SkASSERT(font);
69 if (!font) {
70 return nullptr;
71 }
Ben Wagnere0001732017-08-31 16:26:26 -040072 hb_ot_font_set_funcs(font.get());
73 int axis_count = tf->getVariationDesignPosition(nullptr, 0);
74 if (axis_count > 0) {
75 SkAutoSTMalloc<4, SkFontArguments::VariationPosition::Coordinate> axis_values(axis_count);
76 if (tf->getVariationDesignPosition(axis_values, axis_count) == axis_count) {
77 hb_font_set_variations(font.get(),
78 reinterpret_cast<hb_variation_t*>(axis_values.get()),
79 axis_count);
80 }
81 }
82 return font;
83}
84
Ben Wagner8d45a382017-11-16 10:08:28 -050085class RunIterator {
86public:
87 virtual ~RunIterator() {}
88 virtual void consume() = 0;
89 // Pointer one past the last (utf8) element in the current run.
90 virtual const char* endOfCurrentRun() const = 0;
91 virtual bool atEnd() const = 0;
92 bool operator<(const RunIterator& that) const {
93 return this->endOfCurrentRun() < that.endOfCurrentRun();
94 }
95};
96
97class BiDiRunIterator : public RunIterator {
98public:
99 static SkTLazy<BiDiRunIterator> Make(const char* utf8, size_t utf8Bytes, UBiDiLevel level) {
100 SkTLazy<BiDiRunIterator> ret;
101
102 // ubidi only accepts utf16 (though internally it basically works on utf32 chars).
103 // We want an ubidi_setPara(UBiDi*, UText*, UBiDiLevel, UBiDiLevel*, UErrorCode*);
104 if (!SkTFitsIn<int32_t>(utf8Bytes)) {
105 SkDebugf("Bidi error: text too long");
106 return ret;
107 }
108 icu::UnicodeString utf16 = icu::UnicodeString::fromUTF8(icu::StringPiece(utf8, utf8Bytes));
109
110 UErrorCode status = U_ZERO_ERROR;
111 ICUBiDi bidi(ubidi_openSized(utf16.length(), 0, &status));
112 if (U_FAILURE(status)) {
113 SkDebugf("Bidi error: %s", u_errorName(status));
114 return ret;
115 }
116 SkASSERT(bidi);
117
118 // The required lifetime of utf16 isn't well documented.
119 // It appears it isn't used after ubidi_setPara except through ubidi_getText.
120 ubidi_setPara(bidi.get(), utf16.getBuffer(), utf16.length(), level, nullptr, &status);
121 if (U_FAILURE(status)) {
122 SkDebugf("Bidi error: %s", u_errorName(status));
123 return ret;
124 }
125
126 ret.init(utf8, std::move(bidi));
127 return ret;
128 }
129 BiDiRunIterator(const char* utf8, ICUBiDi bidi)
130 : fBidi(std::move(bidi))
131 , fEndOfCurrentRun(utf8)
132 , fUTF16LogicalPosition(0)
133 , fLevel(UBIDI_DEFAULT_LTR)
134 {}
135 void consume() override {
136 SkASSERT(fUTF16LogicalPosition < ubidi_getLength(fBidi.get()));
137 int32_t endPosition = ubidi_getLength(fBidi.get());
138 fLevel = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
Ben Wagner5a907a72018-01-25 16:03:22 -0500139 SkUnichar u = SkUTF8_NextUnichar(&fEndOfCurrentRun);
140 fUTF16LogicalPosition += SkUTF16_FromUnichar(u);
Ben Wagner8d45a382017-11-16 10:08:28 -0500141 UBiDiLevel level;
142 while (fUTF16LogicalPosition < endPosition) {
143 level = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
144 if (level != fLevel) {
145 break;
146 }
Ben Wagner5a907a72018-01-25 16:03:22 -0500147 u = SkUTF8_NextUnichar(&fEndOfCurrentRun);
148 fUTF16LogicalPosition += SkUTF16_FromUnichar(u);
Ben Wagner8d45a382017-11-16 10:08:28 -0500149 }
150 }
151 const char* endOfCurrentRun() const override {
152 return fEndOfCurrentRun;
153 }
154 bool atEnd() const override {
155 return fUTF16LogicalPosition == ubidi_getLength(fBidi.get());
156 }
157
158 UBiDiLevel currentLevel() const {
159 return fLevel;
160 }
161private:
162 ICUBiDi fBidi;
163 const char* fEndOfCurrentRun;
164 int32_t fUTF16LogicalPosition;
165 UBiDiLevel fLevel;
166};
167
168class ScriptRunIterator : public RunIterator {
169public:
170 static SkTLazy<ScriptRunIterator> Make(const char* utf8, size_t utf8Bytes,
171 hb_unicode_funcs_t* hbUnicode)
172 {
173 SkTLazy<ScriptRunIterator> ret;
174 ret.init(utf8, utf8Bytes, hbUnicode);
175 return ret;
176 }
177 ScriptRunIterator(const char* utf8, size_t utf8Bytes, hb_unicode_funcs_t* hbUnicode)
178 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
179 , fHBUnicode(hbUnicode)
180 , fCurrentScript(HB_SCRIPT_UNKNOWN)
181 {}
182 void consume() override {
183 SkASSERT(fCurrent < fEnd);
184 SkUnichar u = SkUTF8_NextUnichar(&fCurrent);
185 fCurrentScript = hb_unicode_script(fHBUnicode, u);
186 while (fCurrent < fEnd) {
187 const char* prev = fCurrent;
188 u = SkUTF8_NextUnichar(&fCurrent);
189 const hb_script_t script = hb_unicode_script(fHBUnicode, u);
190 if (script != fCurrentScript) {
191 if (fCurrentScript == HB_SCRIPT_INHERITED || fCurrentScript == HB_SCRIPT_COMMON) {
192 fCurrentScript = script;
193 } else if (script == HB_SCRIPT_INHERITED || script == HB_SCRIPT_COMMON) {
194 continue;
195 } else {
196 fCurrent = prev;
197 break;
198 }
199 }
200 }
201 if (fCurrentScript == HB_SCRIPT_INHERITED) {
202 fCurrentScript = HB_SCRIPT_COMMON;
203 }
204 }
205 const char* endOfCurrentRun() const override {
206 return fCurrent;
207 }
208 bool atEnd() const override {
209 return fCurrent == fEnd;
210 }
211
212 hb_script_t currentScript() const {
213 return fCurrentScript;
214 }
215private:
216 const char* fCurrent;
217 const char* fEnd;
218 hb_unicode_funcs_t* fHBUnicode;
219 hb_script_t fCurrentScript;
220};
221
222class FontRunIterator : public RunIterator {
223public:
224 static SkTLazy<FontRunIterator> Make(const char* utf8, size_t utf8Bytes,
225 sk_sp<SkTypeface> typeface,
226 hb_font_t* hbFace,
227 sk_sp<SkFontMgr> fallbackMgr)
228 {
229 SkTLazy<FontRunIterator> ret;
230 ret.init(utf8, utf8Bytes, std::move(typeface), hbFace, std::move(fallbackMgr));
231 return ret;
232 }
233 FontRunIterator(const char* utf8, size_t utf8Bytes, sk_sp<SkTypeface> typeface,
234 hb_font_t* hbFace, sk_sp<SkFontMgr> fallbackMgr)
235 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
236 , fFallbackMgr(std::move(fallbackMgr))
237 , fHBFont(hbFace), fTypeface(std::move(typeface))
238 , fFallbackHBFont(nullptr), fFallbackTypeface(nullptr)
239 , fCurrentHBFont(fHBFont), fCurrentTypeface(fTypeface.get())
240 {}
241 void consume() override {
242 SkASSERT(fCurrent < fEnd);
243 SkUnichar u = SkUTF8_NextUnichar(&fCurrent);
244 // If the starting typeface can handle this character, use it.
245 if (fTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1)) {
246 fFallbackTypeface.reset();
247 // If not, try to find a fallback typeface
248 } else {
249 fFallbackTypeface.reset(fFallbackMgr->matchFamilyStyleCharacter(
250 nullptr, fTypeface->fontStyle(), nullptr, 0, u));
251 }
252
253 if (fFallbackTypeface) {
254 fFallbackHBFont = create_hb_font(fFallbackTypeface.get());
255 fCurrentTypeface = fFallbackTypeface.get();
256 fCurrentHBFont = fFallbackHBFont.get();
257 } else {
258 fFallbackHBFont.reset();
259 fCurrentTypeface = fTypeface.get();
260 fCurrentHBFont = fHBFont;
261 }
262
263 while (fCurrent < fEnd) {
264 const char* prev = fCurrent;
265 u = SkUTF8_NextUnichar(&fCurrent);
266
267 // If using a fallback and the initial typeface has this character, stop fallback.
268 if (fFallbackTypeface &&
269 fTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1))
270 {
271 fCurrent = prev;
272 return;
273 }
274 // If the current typeface cannot handle this character, stop using it.
275 if (!fCurrentTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1)) {
276 fCurrent = prev;
277 return;
278 }
279 }
280 }
281 const char* endOfCurrentRun() const override {
282 return fCurrent;
283 }
284 bool atEnd() const override {
285 return fCurrent == fEnd;
286 }
287
288 SkTypeface* currentTypeface() const {
289 return fCurrentTypeface;
290 }
291 hb_font_t* currentHBFont() const {
292 return fCurrentHBFont;
293 }
294private:
295 const char* fCurrent;
296 const char* fEnd;
297 sk_sp<SkFontMgr> fFallbackMgr;
298 hb_font_t* fHBFont;
299 sk_sp<SkTypeface> fTypeface;
300 HBFont fFallbackHBFont;
301 sk_sp<SkTypeface> fFallbackTypeface;
302 hb_font_t* fCurrentHBFont;
303 SkTypeface* fCurrentTypeface;
304};
305
306class RunIteratorQueue {
307public:
308 void insert(RunIterator* runIterator) {
309 fRunIterators.insert(runIterator);
310 }
311
312 bool advanceRuns() {
313 const RunIterator* leastRun = fRunIterators.peek();
314 if (leastRun->atEnd()) {
315 SkASSERT(this->allRunsAreAtEnd());
316 return false;
317 }
318 const char* leastEnd = leastRun->endOfCurrentRun();
319 RunIterator* currentRun = nullptr;
320 SkDEBUGCODE(const char* previousEndOfCurrentRun);
321 while ((currentRun = fRunIterators.peek())->endOfCurrentRun() <= leastEnd) {
322 fRunIterators.pop();
323 SkDEBUGCODE(previousEndOfCurrentRun = currentRun->endOfCurrentRun());
324 currentRun->consume();
325 SkASSERT(previousEndOfCurrentRun < currentRun->endOfCurrentRun());
326 fRunIterators.insert(currentRun);
327 }
328 return true;
329 }
330
331 const char* endOfCurrentRun() const {
332 return fRunIterators.peek()->endOfCurrentRun();
333 }
334
335private:
336 bool allRunsAreAtEnd() const {
337 for (int i = 0; i < fRunIterators.count(); ++i) {
338 if (!fRunIterators.at(i)->atEnd()) {
339 return false;
340 }
341 }
342 return true;
343 }
344
345 static bool CompareRunIterator(RunIterator* const& a, RunIterator* const& b) {
346 return *a < *b;
347 }
348 SkTDPQueue<RunIterator*, CompareRunIterator> fRunIterators;
349};
350
351struct ShapedGlyph {
352 SkGlyphID fID;
353 uint32_t fCluster;
354 SkPoint fOffset;
355 SkVector fAdvance;
356 bool fMayLineBreakBefore;
357 bool fMustLineBreakBefore;
358 bool fHasVisual;
359};
360struct ShapedRun {
361 ShapedRun(const char* utf8Start, const char* utf8End, int numGlyphs, const SkPaint& paint,
362 UBiDiLevel level, std::unique_ptr<ShapedGlyph[]> glyphs)
363 : fUtf8Start(utf8Start), fUtf8End(utf8End), fNumGlyphs(numGlyphs), fPaint(paint)
364 , fLevel(level), fGlyphs(std::move(glyphs))
365 {}
366
367 const char* fUtf8Start;
368 const char* fUtf8End;
369 int fNumGlyphs;
370 SkPaint fPaint;
371 UBiDiLevel fLevel;
372 std::unique_ptr<ShapedGlyph[]> fGlyphs;
373};
374
375static constexpr bool is_LTR(UBiDiLevel level) {
376 return (level & 1) == 0;
377}
378
379static void append(SkTextBlobBuilder* b, const ShapedRun& run, int start, int end, SkPoint* p) {
380 unsigned len = end - start;
381 auto runBuffer = b->allocRunTextPos(run.fPaint, len, run.fUtf8End - run.fUtf8Start, SkString());
382 memcpy(runBuffer.utf8text, run.fUtf8Start, run.fUtf8End - run.fUtf8Start);
383
384 for (unsigned i = 0; i < len; i++) {
385 // Glyphs are in logical order, but output ltr since PDF readers seem to expect that.
386 const ShapedGlyph& glyph = run.fGlyphs[is_LTR(run.fLevel) ? start + i : end - 1 - i];
387 runBuffer.glyphs[i] = glyph.fID;
388 runBuffer.clusters[i] = glyph.fCluster;
389 reinterpret_cast<SkPoint*>(runBuffer.pos)[i] =
390 SkPoint::Make(p->fX + glyph.fOffset.fX, p->fY - glyph.fOffset.fY);
391 p->fX += glyph.fAdvance.fX;
392 p->fY += glyph.fAdvance.fY;
393 }
394}
395
396struct ShapedRunGlyphIterator {
397 ShapedRunGlyphIterator(const SkTArray<ShapedRun>& origRuns)
398 : fRuns(&origRuns), fRunIndex(0), fGlyphIndex(0)
399 { }
400
401 ShapedRunGlyphIterator(const ShapedRunGlyphIterator& that) = default;
402 ShapedRunGlyphIterator& operator=(const ShapedRunGlyphIterator& that) = default;
403 bool operator==(const ShapedRunGlyphIterator& that) const {
404 return fRuns == that.fRuns &&
405 fRunIndex == that.fRunIndex &&
406 fGlyphIndex == that.fGlyphIndex;
407 }
408 bool operator!=(const ShapedRunGlyphIterator& that) const {
409 return fRuns != that.fRuns ||
410 fRunIndex != that.fRunIndex ||
411 fGlyphIndex != that.fGlyphIndex;
412 }
413
414 ShapedGlyph* next() {
415 const SkTArray<ShapedRun>& runs = *fRuns;
416 SkASSERT(fRunIndex < runs.count());
417 SkASSERT(fGlyphIndex < runs[fRunIndex].fNumGlyphs);
418
419 ++fGlyphIndex;
420 if (fGlyphIndex == runs[fRunIndex].fNumGlyphs) {
421 fGlyphIndex = 0;
422 ++fRunIndex;
423 if (fRunIndex >= runs.count()) {
424 return nullptr;
425 }
426 }
427 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
428 }
429
430 ShapedGlyph* current() {
431 const SkTArray<ShapedRun>& runs = *fRuns;
432 if (fRunIndex >= runs.count()) {
433 return nullptr;
434 }
435 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
436 }
437
438 const SkTArray<ShapedRun>* fRuns;
439 int fRunIndex;
440 int fGlyphIndex;
441};
442
443} // namespace
444
445struct SkShaper::Impl {
446 HBFont fHarfBuzzFont;
447 HBBuffer fBuffer;
448 sk_sp<SkTypeface> fTypeface;
449 std::unique_ptr<icu::BreakIterator> fBreakIterator;
450};
451
Ben Wagnere0001732017-08-31 16:26:26 -0400452SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
Hal Canary0e07ad72018-02-08 13:06:56 -0500453 SkOnce once;
454 once([] { SkLoadICU(); });
455
Ben Wagnere0001732017-08-31 16:26:26 -0400456 fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
457 fImpl->fHarfBuzzFont = create_hb_font(fImpl->fTypeface.get());
Ben Wagnera25fbef2017-08-30 13:56:19 -0400458 SkASSERT(fImpl->fHarfBuzzFont);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400459 fImpl->fBuffer.reset(hb_buffer_create());
Ben Wagner8d45a382017-11-16 10:08:28 -0500460 SkASSERT(fImpl->fBuffer);
461
462 icu::Locale thai("th");
463 UErrorCode status = U_ZERO_ERROR;
464 fImpl->fBreakIterator.reset(icu::BreakIterator::createLineInstance(thai, status));
465 if (U_FAILURE(status)) {
466 SkDebugf("Could not create break iterator: %s", u_errorName(status));
467 SK_ABORT("");
468 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400469}
470
471SkShaper::~SkShaper() {}
472
Ben Wagner8d45a382017-11-16 10:08:28 -0500473bool SkShaper::good() const {
474 return fImpl->fHarfBuzzFont &&
475 fImpl->fBuffer &&
476 fImpl->fTypeface &&
477 fImpl->fBreakIterator;
478}
Ben Wagnera25fbef2017-08-30 13:56:19 -0400479
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500480SkPoint SkShaper::shape(SkTextBlobBuilder* builder,
481 const SkPaint& srcPaint,
482 const char* utf8,
483 size_t utf8Bytes,
484 bool leftToRight,
485 SkPoint point,
486 SkScalar width) const {
Ben Wagner67e3a302017-09-05 14:46:19 -0400487 sk_sp<SkFontMgr> fontMgr = SkFontMgr::RefDefault();
Ben Wagnera25fbef2017-08-30 13:56:19 -0400488 SkASSERT(builder);
Ben Wagner8d45a382017-11-16 10:08:28 -0500489 UBiDiLevel defaultLevel = leftToRight ? UBIDI_DEFAULT_LTR : UBIDI_DEFAULT_RTL;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400490 //hb_script_t script = ...
Ben Wagnera25fbef2017-08-30 13:56:19 -0400491
Ben Wagner8d45a382017-11-16 10:08:28 -0500492 SkTArray<ShapedRun> runs;
493{
494 RunIteratorQueue runSegmenter;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400495
Ben Wagner8d45a382017-11-16 10:08:28 -0500496 SkTLazy<BiDiRunIterator> maybeBidi(BiDiRunIterator::Make(utf8, utf8Bytes, defaultLevel));
497 BiDiRunIterator* bidi = maybeBidi.getMaybeNull();
498 if (!bidi) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500499 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400500 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500501 runSegmenter.insert(bidi);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400502
Ben Wagner8d45a382017-11-16 10:08:28 -0500503 hb_unicode_funcs_t* hbUnicode = hb_buffer_get_unicode_funcs(fImpl->fBuffer.get());
504 SkTLazy<ScriptRunIterator> maybeScript(ScriptRunIterator::Make(utf8, utf8Bytes, hbUnicode));
505 ScriptRunIterator* script = maybeScript.getMaybeNull();
506 if (!script) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500507 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400508 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500509 runSegmenter.insert(script);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400510
Ben Wagner8d45a382017-11-16 10:08:28 -0500511 SkTLazy<FontRunIterator> maybeFont(FontRunIterator::Make(utf8, utf8Bytes,
512 fImpl->fTypeface,
513 fImpl->fHarfBuzzFont.get(),
514 std::move(fontMgr)));
515 FontRunIterator* font = maybeFont.getMaybeNull();
516 if (!font) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500517 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400518 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500519 runSegmenter.insert(font);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400520
Ben Wagner8d45a382017-11-16 10:08:28 -0500521 icu::BreakIterator& breakIterator = *fImpl->fBreakIterator;
522 {
523 UErrorCode status = U_ZERO_ERROR;
524 UText utf8UText = UTEXT_INITIALIZER;
525 utext_openUTF8(&utf8UText, utf8, utf8Bytes, &status);
526 std::unique_ptr<UText, SkFunctionWrapper<UText*, UText, utext_close>> autoClose(&utf8UText);
527 if (U_FAILURE(status)) {
528 SkDebugf("Could not create utf8UText: %s", u_errorName(status));
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500529 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500530 }
531 breakIterator.setText(&utf8UText, status);
532 //utext_close(&utf8UText);
533 if (U_FAILURE(status)) {
534 SkDebugf("Could not setText on break iterator: %s", u_errorName(status));
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500535 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500536 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400537 }
538
Ben Wagner8d45a382017-11-16 10:08:28 -0500539 const char* utf8Start = nullptr;
540 const char* utf8End = utf8;
541 while (runSegmenter.advanceRuns()) {
542 utf8Start = utf8End;
543 utf8End = runSegmenter.endOfCurrentRun();
544
545 hb_buffer_t* buffer = fImpl->fBuffer.get();
546 SkAutoTCallVProc<hb_buffer_t, hb_buffer_clear_contents> autoClearBuffer(buffer);
547 hb_buffer_set_content_type(buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
548 hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
549
550 // Populate the hb_buffer directly with utf8 cluster indexes.
551 const char* utf8Current = utf8Start;
552 while (utf8Current < utf8End) {
553 unsigned int cluster = utf8Current - utf8Start;
554 hb_codepoint_t u = SkUTF8_NextUnichar(&utf8Current);
555 hb_buffer_add(buffer, u, cluster);
556 }
557
558 size_t utf8runLength = utf8End - utf8Start;
559 if (!SkTFitsIn<int>(utf8runLength)) {
560 SkDebugf("Shaping error: utf8 too long");
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500561 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500562 }
563 hb_buffer_set_script(buffer, script->currentScript());
564 hb_direction_t direction = is_LTR(bidi->currentLevel()) ? HB_DIRECTION_LTR:HB_DIRECTION_RTL;
565 hb_buffer_set_direction(buffer, direction);
566 // TODO: language
567 hb_buffer_guess_segment_properties(buffer);
568 // TODO: features
569 hb_shape(font->currentHBFont(), buffer, nullptr, 0);
570 unsigned len = hb_buffer_get_length(buffer);
571 if (len == 0) {
572 continue;
573 }
574
575 if (direction == HB_DIRECTION_RTL) {
576 // Put the clusters back in logical order.
577 // Note that the advances remain ltr.
578 hb_buffer_reverse(buffer);
579 }
580 hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, nullptr);
581 hb_glyph_position_t* pos = hb_buffer_get_glyph_positions(buffer, nullptr);
582
583 if (!SkTFitsIn<int>(len)) {
584 SkDebugf("Shaping error: too many glyphs");
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500585 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500586 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400587
588 SkPaint paint(srcPaint);
589 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Ben Wagner8d45a382017-11-16 10:08:28 -0500590 paint.setTypeface(sk_ref_sp(font->currentTypeface()));
591 ShapedRun& run = runs.emplace_back(utf8Start, utf8End, len, paint, bidi->currentLevel(),
592 std::unique_ptr<ShapedGlyph[]>(new ShapedGlyph[len]));
593 int scaleX, scaleY;
594 hb_font_get_scale(font->currentHBFont(), &scaleX, &scaleY);
595 double textSizeY = run.fPaint.getTextSize() / scaleY;
596 double textSizeX = run.fPaint.getTextSize() / scaleX * run.fPaint.getTextScaleX();
597 for (unsigned i = 0; i < len; i++) {
598 ShapedGlyph& glyph = run.fGlyphs[i];
599 glyph.fID = info[i].codepoint;
600 glyph.fCluster = info[i].cluster;
601 glyph.fOffset.fX = pos[i].x_offset * textSizeX;
602 glyph.fOffset.fY = pos[i].y_offset * textSizeY;
603 glyph.fAdvance.fX = pos[i].x_advance * textSizeX;
604 glyph.fAdvance.fY = pos[i].y_advance * textSizeY;
605 glyph.fHasVisual = true; //!font->currentTypeface()->glyphBoundsAreZero(glyph.fID);
606 //info->mask safe_to_break;
607 glyph.fMustLineBreakBefore = false;
608 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400609
Ben Wagner8d45a382017-11-16 10:08:28 -0500610 int32_t clusterOffset = utf8Start - utf8;
611 uint32_t previousCluster = 0xFFFFFFFF;
612 for (unsigned i = 0; i < len; ++i) {
613 ShapedGlyph& glyph = run.fGlyphs[i];
614 int32_t glyphCluster = glyph.fCluster + clusterOffset;
615 int32_t breakIteratorCurrent = breakIterator.current();
616 while (breakIteratorCurrent != icu::BreakIterator::DONE &&
617 breakIteratorCurrent < glyphCluster)
618 {
619 breakIteratorCurrent = breakIterator.next();
Ben Wagner2868b782017-08-31 14:12:27 -0400620 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500621 glyph.fMayLineBreakBefore = glyph.fCluster != previousCluster &&
622 breakIteratorCurrent == glyphCluster;
623 previousCluster = glyph.fCluster;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400624 }
625 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500626}
627
628// Iterate over the glyphs in logical order to mark line endings.
629{
630 SkScalar widthSoFar = 0;
631 bool previousBreakValid = false; // Set when previousBreak is set to a valid candidate break.
632 bool canAddBreakNow = false; // Disallow line breaks before the first glyph of a run.
633 ShapedRunGlyphIterator previousBreak(runs);
634 ShapedRunGlyphIterator glyphIterator(runs);
635 while (ShapedGlyph* glyph = glyphIterator.current()) {
636 if (canAddBreakNow && glyph->fMayLineBreakBefore) {
637 previousBreakValid = true;
638 previousBreak = glyphIterator;
639 }
640 SkScalar glyphWidth = glyph->fAdvance.fX;
641 if (widthSoFar + glyphWidth < width) {
642 widthSoFar += glyphWidth;
643 glyphIterator.next();
644 canAddBreakNow = true;
645 continue;
646 }
647
648 if (widthSoFar == 0) {
649 // Adding just this glyph is too much, just break with this glyph
650 glyphIterator.next();
651 previousBreak = glyphIterator;
652 } else if (!previousBreakValid) {
653 // No break opprotunity found yet, just break without this glyph
654 previousBreak = glyphIterator;
655 }
656 glyphIterator = previousBreak;
657 glyph = glyphIterator.current();
658 if (glyph) {
659 glyph->fMustLineBreakBefore = true;
660 }
661 widthSoFar = 0;
662 previousBreakValid = false;
663 canAddBreakNow = false;
664 }
665}
666
667// Reorder the runs and glyphs per line and write them out.
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500668 SkPoint currentPoint = point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500669{
670 ShapedRunGlyphIterator previousBreak(runs);
671 ShapedRunGlyphIterator glyphIterator(runs);
672 SkScalar maxAscent = 0;
673 SkScalar maxDescent = 0;
674 SkScalar maxLeading = 0;
675 int previousRunIndex = -1;
676 while (glyphIterator.current()) {
677 int runIndex = glyphIterator.fRunIndex;
678 int glyphIndex = glyphIterator.fGlyphIndex;
679 ShapedGlyph* nextGlyph = glyphIterator.next();
680
681 if (previousRunIndex != runIndex) {
682 SkPaint::FontMetrics metrics;
683 runs[runIndex].fPaint.getFontMetrics(&metrics);
684 maxAscent = SkTMin(maxAscent, metrics.fAscent);
685 maxDescent = SkTMax(maxDescent, metrics.fDescent);
686 maxLeading = SkTMax(maxLeading, metrics.fLeading);
687 previousRunIndex = runIndex;
688 }
689
690 // Nothing can be written until the baseline is known.
691 if (!(nextGlyph == nullptr || nextGlyph->fMustLineBreakBefore)) {
692 continue;
693 }
694
695 currentPoint.fY -= maxAscent;
696
697 int numRuns = runIndex - previousBreak.fRunIndex + 1;
698 SkAutoSTMalloc<4, UBiDiLevel> runLevels(numRuns);
699 for (int i = 0; i < numRuns; ++i) {
700 runLevels[i] = runs[previousBreak.fRunIndex + i].fLevel;
701 }
702 SkAutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
703 ubidi_reorderVisual(runLevels, numRuns, logicalFromVisual);
704
705 for (int i = 0; i < numRuns; ++i) {
706 int logicalIndex = previousBreak.fRunIndex + logicalFromVisual[i];
707
708 int startGlyphIndex = (logicalIndex == previousBreak.fRunIndex)
709 ? previousBreak.fGlyphIndex
710 : 0;
711 int endGlyphIndex = (logicalIndex == runIndex)
712 ? glyphIndex + 1
713 : runs[logicalIndex].fNumGlyphs;
714 append(builder, runs[logicalIndex], startGlyphIndex, endGlyphIndex, &currentPoint);
715 }
716
717 currentPoint.fY += maxDescent + maxLeading;
718 currentPoint.fX = point.fX;
719 maxAscent = 0;
720 maxDescent = 0;
721 maxLeading = 0;
722 previousRunIndex = -1;
723 previousBreak = glyphIterator;
724 }
725}
726
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500727 return currentPoint;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400728}