blob: 47630d5c6b3ba277c2686764a69583508c1c4680 [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"
Ben Wagner17774242018-08-07 14:31:33 -040013#include "SkPaint.h"
14#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"
Cary Clarke12a0902018-08-09 10:07:33 -040025#include "SkTextBlobPriv.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040026#include "SkTo.h"
Ben Wagnera25fbef2017-08-30 13:56:19 -040027#include "SkTypeface.h"
Ben Wagner17774242018-08-07 14:31:33 -040028#include "SkTypes.h"
29#include "SkUTF.h"
30
31#include <hb.h>
32#include <hb-ot.h>
33#include <unicode/brkiter.h>
34#include <unicode/locid.h>
35#include <unicode/stringpiece.h>
36#include <unicode/ubidi.h>
37#include <unicode/unistr.h>
38#include <unicode/urename.h>
39#include <unicode/utext.h>
40#include <unicode/utypes.h>
41
42#include <memory>
43#include <utility>
44#include <cstring>
Ben Wagnera25fbef2017-08-30 13:56:19 -040045
Ben Wagnera25fbef2017-08-30 13:56:19 -040046namespace {
47template <class T, void(*P)(T*)> using resource = std::unique_ptr<T, SkFunctionWrapper<void, T, P>>;
48using HBBlob = resource<hb_blob_t , hb_blob_destroy >;
49using HBFace = resource<hb_face_t , hb_face_destroy >;
50using HBFont = resource<hb_font_t , hb_font_destroy >;
51using HBBuffer = resource<hb_buffer_t, hb_buffer_destroy>;
52using ICUBiDi = resource<UBiDi , ubidi_close >;
53
54HBBlob stream_to_blob(std::unique_ptr<SkStreamAsset> asset) {
55 size_t size = asset->getLength();
56 HBBlob blob;
57 if (const void* base = asset->getMemoryBase()) {
58 blob.reset(hb_blob_create((char*)base, SkToUInt(size),
59 HB_MEMORY_MODE_READONLY, asset.release(),
60 [](void* p) { delete (SkStreamAsset*)p; }));
61 } else {
62 // SkDebugf("Extra SkStreamAsset copy\n");
63 void* ptr = size ? sk_malloc_throw(size) : nullptr;
64 asset->read(ptr, size);
65 blob.reset(hb_blob_create((char*)ptr, SkToUInt(size),
66 HB_MEMORY_MODE_READONLY, ptr, sk_free));
67 }
68 SkASSERT(blob);
69 hb_blob_make_immutable(blob.get());
70 return blob;
71}
Ben Wagnera25fbef2017-08-30 13:56:19 -040072
Ben Wagner8d45a382017-11-16 10:08:28 -050073HBFont create_hb_font(SkTypeface* tf) {
Hal Canary0dfa2082018-10-31 13:02:49 -040074 if (!tf) {
75 return nullptr;
76 }
Ben Wagnera25fbef2017-08-30 13:56:19 -040077 int index;
Ben Wagnere0001732017-08-31 16:26:26 -040078 HBBlob blob(stream_to_blob(std::unique_ptr<SkStreamAsset>(tf->openStream(&index))));
Ben Wagnera25fbef2017-08-30 13:56:19 -040079 HBFace face(hb_face_create(blob.get(), (unsigned)index));
80 SkASSERT(face);
81 if (!face) {
Ben Wagnere0001732017-08-31 16:26:26 -040082 return nullptr;
Ben Wagnera25fbef2017-08-30 13:56:19 -040083 }
84 hb_face_set_index(face.get(), (unsigned)index);
Ben Wagnere0001732017-08-31 16:26:26 -040085 hb_face_set_upem(face.get(), tf->getUnitsPerEm());
Ben Wagnera25fbef2017-08-30 13:56:19 -040086
Ben Wagnere0001732017-08-31 16:26:26 -040087 HBFont font(hb_font_create(face.get()));
88 SkASSERT(font);
89 if (!font) {
90 return nullptr;
91 }
Ben Wagnere0001732017-08-31 16:26:26 -040092 hb_ot_font_set_funcs(font.get());
93 int axis_count = tf->getVariationDesignPosition(nullptr, 0);
94 if (axis_count > 0) {
95 SkAutoSTMalloc<4, SkFontArguments::VariationPosition::Coordinate> axis_values(axis_count);
96 if (tf->getVariationDesignPosition(axis_values, axis_count) == axis_count) {
97 hb_font_set_variations(font.get(),
98 reinterpret_cast<hb_variation_t*>(axis_values.get()),
99 axis_count);
100 }
101 }
102 return font;
103}
104
Hal Canaryf107a2f2018-07-25 16:52:48 -0400105/** this version replaces invalid utf-8 sequences with code point U+FFFD. */
106static inline SkUnichar utf8_next(const char** ptr, const char* end) {
107 SkUnichar val = SkUTF::NextUTF8(ptr, end);
108 if (val < 0) {
109 return 0xFFFD; // REPLACEMENT CHARACTER
110 }
111 return val;
112}
113
Ben Wagner8d45a382017-11-16 10:08:28 -0500114class RunIterator {
115public:
116 virtual ~RunIterator() {}
117 virtual void consume() = 0;
118 // Pointer one past the last (utf8) element in the current run.
119 virtual const char* endOfCurrentRun() const = 0;
120 virtual bool atEnd() const = 0;
121 bool operator<(const RunIterator& that) const {
122 return this->endOfCurrentRun() < that.endOfCurrentRun();
123 }
124};
125
126class BiDiRunIterator : public RunIterator {
127public:
128 static SkTLazy<BiDiRunIterator> Make(const char* utf8, size_t utf8Bytes, UBiDiLevel level) {
129 SkTLazy<BiDiRunIterator> ret;
130
131 // ubidi only accepts utf16 (though internally it basically works on utf32 chars).
132 // We want an ubidi_setPara(UBiDi*, UText*, UBiDiLevel, UBiDiLevel*, UErrorCode*);
133 if (!SkTFitsIn<int32_t>(utf8Bytes)) {
134 SkDebugf("Bidi error: text too long");
135 return ret;
136 }
137 icu::UnicodeString utf16 = icu::UnicodeString::fromUTF8(icu::StringPiece(utf8, utf8Bytes));
138
139 UErrorCode status = U_ZERO_ERROR;
140 ICUBiDi bidi(ubidi_openSized(utf16.length(), 0, &status));
141 if (U_FAILURE(status)) {
142 SkDebugf("Bidi error: %s", u_errorName(status));
143 return ret;
144 }
145 SkASSERT(bidi);
146
147 // The required lifetime of utf16 isn't well documented.
148 // It appears it isn't used after ubidi_setPara except through ubidi_getText.
149 ubidi_setPara(bidi.get(), utf16.getBuffer(), utf16.length(), level, nullptr, &status);
150 if (U_FAILURE(status)) {
151 SkDebugf("Bidi error: %s", u_errorName(status));
152 return ret;
153 }
154
Hal Canary4014ba62018-07-24 11:33:21 -0400155 ret.init(utf8, utf8 + utf8Bytes, std::move(bidi));
Ben Wagner8d45a382017-11-16 10:08:28 -0500156 return ret;
157 }
Hal Canary4014ba62018-07-24 11:33:21 -0400158 BiDiRunIterator(const char* utf8, const char* end, ICUBiDi bidi)
Ben Wagner8d45a382017-11-16 10:08:28 -0500159 : fBidi(std::move(bidi))
160 , fEndOfCurrentRun(utf8)
Hal Canary4014ba62018-07-24 11:33:21 -0400161 , fEndOfAllRuns(end)
Ben Wagner8d45a382017-11-16 10:08:28 -0500162 , fUTF16LogicalPosition(0)
163 , fLevel(UBIDI_DEFAULT_LTR)
164 {}
165 void consume() override {
166 SkASSERT(fUTF16LogicalPosition < ubidi_getLength(fBidi.get()));
167 int32_t endPosition = ubidi_getLength(fBidi.get());
168 fLevel = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400169 SkUnichar u = utf8_next(&fEndOfCurrentRun, fEndOfAllRuns);
170 fUTF16LogicalPosition += SkUTF::ToUTF16(u);
Ben Wagner8d45a382017-11-16 10:08:28 -0500171 UBiDiLevel level;
172 while (fUTF16LogicalPosition < endPosition) {
173 level = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
174 if (level != fLevel) {
175 break;
176 }
Hal Canaryf107a2f2018-07-25 16:52:48 -0400177 u = utf8_next(&fEndOfCurrentRun, fEndOfAllRuns);
178 fUTF16LogicalPosition += SkUTF::ToUTF16(u);
Ben Wagner8d45a382017-11-16 10:08:28 -0500179 }
180 }
181 const char* endOfCurrentRun() const override {
182 return fEndOfCurrentRun;
183 }
184 bool atEnd() const override {
185 return fUTF16LogicalPosition == ubidi_getLength(fBidi.get());
186 }
187
188 UBiDiLevel currentLevel() const {
189 return fLevel;
190 }
191private:
192 ICUBiDi fBidi;
193 const char* fEndOfCurrentRun;
Hal Canary4014ba62018-07-24 11:33:21 -0400194 const char* fEndOfAllRuns;
Ben Wagner8d45a382017-11-16 10:08:28 -0500195 int32_t fUTF16LogicalPosition;
196 UBiDiLevel fLevel;
197};
198
199class ScriptRunIterator : public RunIterator {
200public:
201 static SkTLazy<ScriptRunIterator> Make(const char* utf8, size_t utf8Bytes,
202 hb_unicode_funcs_t* hbUnicode)
203 {
204 SkTLazy<ScriptRunIterator> ret;
205 ret.init(utf8, utf8Bytes, hbUnicode);
206 return ret;
207 }
208 ScriptRunIterator(const char* utf8, size_t utf8Bytes, hb_unicode_funcs_t* hbUnicode)
209 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
210 , fHBUnicode(hbUnicode)
211 , fCurrentScript(HB_SCRIPT_UNKNOWN)
212 {}
213 void consume() override {
214 SkASSERT(fCurrent < fEnd);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400215 SkUnichar u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500216 fCurrentScript = hb_unicode_script(fHBUnicode, u);
217 while (fCurrent < fEnd) {
218 const char* prev = fCurrent;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400219 u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500220 const hb_script_t script = hb_unicode_script(fHBUnicode, u);
221 if (script != fCurrentScript) {
222 if (fCurrentScript == HB_SCRIPT_INHERITED || fCurrentScript == HB_SCRIPT_COMMON) {
223 fCurrentScript = script;
224 } else if (script == HB_SCRIPT_INHERITED || script == HB_SCRIPT_COMMON) {
225 continue;
226 } else {
227 fCurrent = prev;
228 break;
229 }
230 }
231 }
232 if (fCurrentScript == HB_SCRIPT_INHERITED) {
233 fCurrentScript = HB_SCRIPT_COMMON;
234 }
235 }
236 const char* endOfCurrentRun() const override {
237 return fCurrent;
238 }
239 bool atEnd() const override {
240 return fCurrent == fEnd;
241 }
242
243 hb_script_t currentScript() const {
244 return fCurrentScript;
245 }
246private:
247 const char* fCurrent;
248 const char* fEnd;
249 hb_unicode_funcs_t* fHBUnicode;
250 hb_script_t fCurrentScript;
251};
252
253class FontRunIterator : public RunIterator {
254public:
255 static SkTLazy<FontRunIterator> Make(const char* utf8, size_t utf8Bytes,
256 sk_sp<SkTypeface> typeface,
257 hb_font_t* hbFace,
258 sk_sp<SkFontMgr> fallbackMgr)
259 {
260 SkTLazy<FontRunIterator> ret;
261 ret.init(utf8, utf8Bytes, std::move(typeface), hbFace, std::move(fallbackMgr));
262 return ret;
263 }
264 FontRunIterator(const char* utf8, size_t utf8Bytes, sk_sp<SkTypeface> typeface,
265 hb_font_t* hbFace, sk_sp<SkFontMgr> fallbackMgr)
266 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
267 , fFallbackMgr(std::move(fallbackMgr))
268 , fHBFont(hbFace), fTypeface(std::move(typeface))
269 , fFallbackHBFont(nullptr), fFallbackTypeface(nullptr)
270 , fCurrentHBFont(fHBFont), fCurrentTypeface(fTypeface.get())
271 {}
272 void consume() override {
273 SkASSERT(fCurrent < fEnd);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400274 SkUnichar u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500275 // If the starting typeface can handle this character, use it.
276 if (fTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1)) {
Ben Wagnera900ad52018-08-31 17:48:19 -0400277 fCurrentTypeface = fTypeface.get();
278 fCurrentHBFont = fHBFont;
279 // If the current fallback can handle this character, use it.
280 } else if (fFallbackTypeface &&
281 fFallbackTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1))
282 {
283 fCurrentTypeface = fFallbackTypeface.get();
284 fCurrentHBFont = fFallbackHBFont.get();
Ben Wagner8d45a382017-11-16 10:08:28 -0500285 // If not, try to find a fallback typeface
286 } else {
287 fFallbackTypeface.reset(fFallbackMgr->matchFamilyStyleCharacter(
288 nullptr, fTypeface->fontStyle(), nullptr, 0, u));
Ben Wagner8d45a382017-11-16 10:08:28 -0500289 fFallbackHBFont = create_hb_font(fFallbackTypeface.get());
290 fCurrentTypeface = fFallbackTypeface.get();
291 fCurrentHBFont = fFallbackHBFont.get();
Ben Wagner8d45a382017-11-16 10:08:28 -0500292 }
293
294 while (fCurrent < fEnd) {
295 const char* prev = fCurrent;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400296 u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500297
Ben Wagnera900ad52018-08-31 17:48:19 -0400298 // If not using initial typeface and initial typeface has this character, stop fallback.
299 if (fCurrentTypeface != fTypeface.get() &&
Ben Wagner8d45a382017-11-16 10:08:28 -0500300 fTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1))
301 {
302 fCurrent = prev;
303 return;
304 }
305 // If the current typeface cannot handle this character, stop using it.
306 if (!fCurrentTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1)) {
307 fCurrent = prev;
308 return;
309 }
310 }
311 }
312 const char* endOfCurrentRun() const override {
313 return fCurrent;
314 }
315 bool atEnd() const override {
316 return fCurrent == fEnd;
317 }
318
319 SkTypeface* currentTypeface() const {
320 return fCurrentTypeface;
321 }
322 hb_font_t* currentHBFont() const {
323 return fCurrentHBFont;
324 }
325private:
326 const char* fCurrent;
327 const char* fEnd;
328 sk_sp<SkFontMgr> fFallbackMgr;
329 hb_font_t* fHBFont;
330 sk_sp<SkTypeface> fTypeface;
331 HBFont fFallbackHBFont;
332 sk_sp<SkTypeface> fFallbackTypeface;
333 hb_font_t* fCurrentHBFont;
334 SkTypeface* fCurrentTypeface;
335};
336
337class RunIteratorQueue {
338public:
339 void insert(RunIterator* runIterator) {
340 fRunIterators.insert(runIterator);
341 }
342
343 bool advanceRuns() {
344 const RunIterator* leastRun = fRunIterators.peek();
345 if (leastRun->atEnd()) {
346 SkASSERT(this->allRunsAreAtEnd());
347 return false;
348 }
349 const char* leastEnd = leastRun->endOfCurrentRun();
350 RunIterator* currentRun = nullptr;
351 SkDEBUGCODE(const char* previousEndOfCurrentRun);
352 while ((currentRun = fRunIterators.peek())->endOfCurrentRun() <= leastEnd) {
353 fRunIterators.pop();
354 SkDEBUGCODE(previousEndOfCurrentRun = currentRun->endOfCurrentRun());
355 currentRun->consume();
356 SkASSERT(previousEndOfCurrentRun < currentRun->endOfCurrentRun());
357 fRunIterators.insert(currentRun);
358 }
359 return true;
360 }
361
362 const char* endOfCurrentRun() const {
363 return fRunIterators.peek()->endOfCurrentRun();
364 }
365
366private:
367 bool allRunsAreAtEnd() const {
368 for (int i = 0; i < fRunIterators.count(); ++i) {
369 if (!fRunIterators.at(i)->atEnd()) {
370 return false;
371 }
372 }
373 return true;
374 }
375
376 static bool CompareRunIterator(RunIterator* const& a, RunIterator* const& b) {
377 return *a < *b;
378 }
379 SkTDPQueue<RunIterator*, CompareRunIterator> fRunIterators;
380};
381
382struct ShapedGlyph {
383 SkGlyphID fID;
384 uint32_t fCluster;
385 SkPoint fOffset;
386 SkVector fAdvance;
387 bool fMayLineBreakBefore;
388 bool fMustLineBreakBefore;
389 bool fHasVisual;
390};
391struct ShapedRun {
392 ShapedRun(const char* utf8Start, const char* utf8End, int numGlyphs, const SkPaint& paint,
393 UBiDiLevel level, std::unique_ptr<ShapedGlyph[]> glyphs)
394 : fUtf8Start(utf8Start), fUtf8End(utf8End), fNumGlyphs(numGlyphs), fPaint(paint)
395 , fLevel(level), fGlyphs(std::move(glyphs))
396 {}
397
398 const char* fUtf8Start;
399 const char* fUtf8End;
400 int fNumGlyphs;
401 SkPaint fPaint;
402 UBiDiLevel fLevel;
403 std::unique_ptr<ShapedGlyph[]> fGlyphs;
404};
405
406static constexpr bool is_LTR(UBiDiLevel level) {
407 return (level & 1) == 0;
408}
409
410static void append(SkTextBlobBuilder* b, const ShapedRun& run, int start, int end, SkPoint* p) {
411 unsigned len = end - start;
Cary Clarke12a0902018-08-09 10:07:33 -0400412 auto runBuffer = SkTextBlobBuilderPriv::AllocRunTextPos(b, run.fPaint, len,
413 run.fUtf8End - run.fUtf8Start, SkString());
Ben Wagner8d45a382017-11-16 10:08:28 -0500414 memcpy(runBuffer.utf8text, run.fUtf8Start, run.fUtf8End - run.fUtf8Start);
415
416 for (unsigned i = 0; i < len; i++) {
417 // Glyphs are in logical order, but output ltr since PDF readers seem to expect that.
418 const ShapedGlyph& glyph = run.fGlyphs[is_LTR(run.fLevel) ? start + i : end - 1 - i];
419 runBuffer.glyphs[i] = glyph.fID;
420 runBuffer.clusters[i] = glyph.fCluster;
421 reinterpret_cast<SkPoint*>(runBuffer.pos)[i] =
422 SkPoint::Make(p->fX + glyph.fOffset.fX, p->fY - glyph.fOffset.fY);
423 p->fX += glyph.fAdvance.fX;
424 p->fY += glyph.fAdvance.fY;
425 }
426}
427
428struct ShapedRunGlyphIterator {
429 ShapedRunGlyphIterator(const SkTArray<ShapedRun>& origRuns)
430 : fRuns(&origRuns), fRunIndex(0), fGlyphIndex(0)
431 { }
432
433 ShapedRunGlyphIterator(const ShapedRunGlyphIterator& that) = default;
434 ShapedRunGlyphIterator& operator=(const ShapedRunGlyphIterator& that) = default;
435 bool operator==(const ShapedRunGlyphIterator& that) const {
436 return fRuns == that.fRuns &&
437 fRunIndex == that.fRunIndex &&
438 fGlyphIndex == that.fGlyphIndex;
439 }
440 bool operator!=(const ShapedRunGlyphIterator& that) const {
441 return fRuns != that.fRuns ||
442 fRunIndex != that.fRunIndex ||
443 fGlyphIndex != that.fGlyphIndex;
444 }
445
446 ShapedGlyph* next() {
447 const SkTArray<ShapedRun>& runs = *fRuns;
448 SkASSERT(fRunIndex < runs.count());
449 SkASSERT(fGlyphIndex < runs[fRunIndex].fNumGlyphs);
450
451 ++fGlyphIndex;
452 if (fGlyphIndex == runs[fRunIndex].fNumGlyphs) {
453 fGlyphIndex = 0;
454 ++fRunIndex;
455 if (fRunIndex >= runs.count()) {
456 return nullptr;
457 }
458 }
459 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
460 }
461
462 ShapedGlyph* current() {
463 const SkTArray<ShapedRun>& runs = *fRuns;
464 if (fRunIndex >= runs.count()) {
465 return nullptr;
466 }
467 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
468 }
469
470 const SkTArray<ShapedRun>* fRuns;
471 int fRunIndex;
472 int fGlyphIndex;
473};
474
475} // namespace
476
477struct SkShaper::Impl {
478 HBFont fHarfBuzzFont;
479 HBBuffer fBuffer;
480 sk_sp<SkTypeface> fTypeface;
481 std::unique_ptr<icu::BreakIterator> fBreakIterator;
482};
483
Ben Wagnere0001732017-08-31 16:26:26 -0400484SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
Hal Canary0e07ad72018-02-08 13:06:56 -0500485 SkOnce once;
486 once([] { SkLoadICU(); });
487
Ben Wagnere0001732017-08-31 16:26:26 -0400488 fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
489 fImpl->fHarfBuzzFont = create_hb_font(fImpl->fTypeface.get());
Ben Wagnera25fbef2017-08-30 13:56:19 -0400490 SkASSERT(fImpl->fHarfBuzzFont);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400491 fImpl->fBuffer.reset(hb_buffer_create());
Ben Wagner8d45a382017-11-16 10:08:28 -0500492 SkASSERT(fImpl->fBuffer);
493
494 icu::Locale thai("th");
495 UErrorCode status = U_ZERO_ERROR;
496 fImpl->fBreakIterator.reset(icu::BreakIterator::createLineInstance(thai, status));
497 if (U_FAILURE(status)) {
498 SkDebugf("Could not create break iterator: %s", u_errorName(status));
499 SK_ABORT("");
500 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400501}
502
503SkShaper::~SkShaper() {}
504
Ben Wagner8d45a382017-11-16 10:08:28 -0500505bool SkShaper::good() const {
506 return fImpl->fHarfBuzzFont &&
507 fImpl->fBuffer &&
508 fImpl->fTypeface &&
509 fImpl->fBreakIterator;
510}
Ben Wagnera25fbef2017-08-30 13:56:19 -0400511
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500512SkPoint SkShaper::shape(SkTextBlobBuilder* builder,
513 const SkPaint& srcPaint,
514 const char* utf8,
515 size_t utf8Bytes,
516 bool leftToRight,
517 SkPoint point,
518 SkScalar width) const {
Ben Wagner67e3a302017-09-05 14:46:19 -0400519 sk_sp<SkFontMgr> fontMgr = SkFontMgr::RefDefault();
Ben Wagnera25fbef2017-08-30 13:56:19 -0400520 SkASSERT(builder);
Ben Wagner8d45a382017-11-16 10:08:28 -0500521 UBiDiLevel defaultLevel = leftToRight ? UBIDI_DEFAULT_LTR : UBIDI_DEFAULT_RTL;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400522 //hb_script_t script = ...
Ben Wagnera25fbef2017-08-30 13:56:19 -0400523
Ben Wagner8d45a382017-11-16 10:08:28 -0500524 SkTArray<ShapedRun> runs;
525{
526 RunIteratorQueue runSegmenter;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400527
Ben Wagner8d45a382017-11-16 10:08:28 -0500528 SkTLazy<BiDiRunIterator> maybeBidi(BiDiRunIterator::Make(utf8, utf8Bytes, defaultLevel));
529 BiDiRunIterator* bidi = maybeBidi.getMaybeNull();
530 if (!bidi) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500531 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400532 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500533 runSegmenter.insert(bidi);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400534
Ben Wagner8d45a382017-11-16 10:08:28 -0500535 hb_unicode_funcs_t* hbUnicode = hb_buffer_get_unicode_funcs(fImpl->fBuffer.get());
536 SkTLazy<ScriptRunIterator> maybeScript(ScriptRunIterator::Make(utf8, utf8Bytes, hbUnicode));
537 ScriptRunIterator* script = maybeScript.getMaybeNull();
538 if (!script) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500539 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400540 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500541 runSegmenter.insert(script);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400542
Ben Wagner8d45a382017-11-16 10:08:28 -0500543 SkTLazy<FontRunIterator> maybeFont(FontRunIterator::Make(utf8, utf8Bytes,
544 fImpl->fTypeface,
545 fImpl->fHarfBuzzFont.get(),
546 std::move(fontMgr)));
547 FontRunIterator* font = maybeFont.getMaybeNull();
548 if (!font) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500549 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400550 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500551 runSegmenter.insert(font);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400552
Ben Wagner8d45a382017-11-16 10:08:28 -0500553 icu::BreakIterator& breakIterator = *fImpl->fBreakIterator;
554 {
555 UErrorCode status = U_ZERO_ERROR;
556 UText utf8UText = UTEXT_INITIALIZER;
557 utext_openUTF8(&utf8UText, utf8, utf8Bytes, &status);
558 std::unique_ptr<UText, SkFunctionWrapper<UText*, UText, utext_close>> autoClose(&utf8UText);
559 if (U_FAILURE(status)) {
560 SkDebugf("Could not create utf8UText: %s", u_errorName(status));
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500561 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500562 }
563 breakIterator.setText(&utf8UText, status);
564 //utext_close(&utf8UText);
565 if (U_FAILURE(status)) {
566 SkDebugf("Could not setText on break iterator: %s", u_errorName(status));
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500567 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500568 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400569 }
570
Ben Wagner8d45a382017-11-16 10:08:28 -0500571 const char* utf8Start = nullptr;
572 const char* utf8End = utf8;
573 while (runSegmenter.advanceRuns()) {
574 utf8Start = utf8End;
575 utf8End = runSegmenter.endOfCurrentRun();
576
577 hb_buffer_t* buffer = fImpl->fBuffer.get();
578 SkAutoTCallVProc<hb_buffer_t, hb_buffer_clear_contents> autoClearBuffer(buffer);
579 hb_buffer_set_content_type(buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
580 hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
581
Ben Wagnerc0c99b32018-08-07 10:14:18 -0400582 // Add precontext.
583 hb_buffer_add_utf8(buffer, utf8, utf8Start - utf8, utf8Start - utf8, 0);
584
Ben Wagner8d45a382017-11-16 10:08:28 -0500585 // Populate the hb_buffer directly with utf8 cluster indexes.
586 const char* utf8Current = utf8Start;
587 while (utf8Current < utf8End) {
588 unsigned int cluster = utf8Current - utf8Start;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400589 hb_codepoint_t u = utf8_next(&utf8Current, utf8End);
Ben Wagner8d45a382017-11-16 10:08:28 -0500590 hb_buffer_add(buffer, u, cluster);
591 }
592
Ben Wagnerc0c99b32018-08-07 10:14:18 -0400593 // Add postcontext.
594 hb_buffer_add_utf8(buffer, utf8Current, utf8 + utf8Bytes - utf8Current, 0, 0);
595
Ben Wagner8d45a382017-11-16 10:08:28 -0500596 size_t utf8runLength = utf8End - utf8Start;
597 if (!SkTFitsIn<int>(utf8runLength)) {
598 SkDebugf("Shaping error: utf8 too long");
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500599 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500600 }
601 hb_buffer_set_script(buffer, script->currentScript());
602 hb_direction_t direction = is_LTR(bidi->currentLevel()) ? HB_DIRECTION_LTR:HB_DIRECTION_RTL;
603 hb_buffer_set_direction(buffer, direction);
604 // TODO: language
605 hb_buffer_guess_segment_properties(buffer);
606 // TODO: features
Hal Canary0dfa2082018-10-31 13:02:49 -0400607 if (!font->currentHBFont()) {
608 continue;
609 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500610 hb_shape(font->currentHBFont(), buffer, nullptr, 0);
611 unsigned len = hb_buffer_get_length(buffer);
612 if (len == 0) {
613 continue;
614 }
615
616 if (direction == HB_DIRECTION_RTL) {
617 // Put the clusters back in logical order.
618 // Note that the advances remain ltr.
619 hb_buffer_reverse(buffer);
620 }
621 hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, nullptr);
622 hb_glyph_position_t* pos = hb_buffer_get_glyph_positions(buffer, nullptr);
623
624 if (!SkTFitsIn<int>(len)) {
625 SkDebugf("Shaping error: too many glyphs");
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500626 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500627 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400628
629 SkPaint paint(srcPaint);
630 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Ben Wagner8d45a382017-11-16 10:08:28 -0500631 paint.setTypeface(sk_ref_sp(font->currentTypeface()));
632 ShapedRun& run = runs.emplace_back(utf8Start, utf8End, len, paint, bidi->currentLevel(),
633 std::unique_ptr<ShapedGlyph[]>(new ShapedGlyph[len]));
634 int scaleX, scaleY;
635 hb_font_get_scale(font->currentHBFont(), &scaleX, &scaleY);
636 double textSizeY = run.fPaint.getTextSize() / scaleY;
637 double textSizeX = run.fPaint.getTextSize() / scaleX * run.fPaint.getTextScaleX();
638 for (unsigned i = 0; i < len; i++) {
639 ShapedGlyph& glyph = run.fGlyphs[i];
640 glyph.fID = info[i].codepoint;
641 glyph.fCluster = info[i].cluster;
642 glyph.fOffset.fX = pos[i].x_offset * textSizeX;
643 glyph.fOffset.fY = pos[i].y_offset * textSizeY;
644 glyph.fAdvance.fX = pos[i].x_advance * textSizeX;
645 glyph.fAdvance.fY = pos[i].y_advance * textSizeY;
646 glyph.fHasVisual = true; //!font->currentTypeface()->glyphBoundsAreZero(glyph.fID);
647 //info->mask safe_to_break;
648 glyph.fMustLineBreakBefore = false;
649 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400650
Ben Wagner8d45a382017-11-16 10:08:28 -0500651 int32_t clusterOffset = utf8Start - utf8;
652 uint32_t previousCluster = 0xFFFFFFFF;
653 for (unsigned i = 0; i < len; ++i) {
654 ShapedGlyph& glyph = run.fGlyphs[i];
655 int32_t glyphCluster = glyph.fCluster + clusterOffset;
656 int32_t breakIteratorCurrent = breakIterator.current();
657 while (breakIteratorCurrent != icu::BreakIterator::DONE &&
658 breakIteratorCurrent < glyphCluster)
659 {
660 breakIteratorCurrent = breakIterator.next();
Ben Wagner2868b782017-08-31 14:12:27 -0400661 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500662 glyph.fMayLineBreakBefore = glyph.fCluster != previousCluster &&
663 breakIteratorCurrent == glyphCluster;
664 previousCluster = glyph.fCluster;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400665 }
666 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500667}
668
669// Iterate over the glyphs in logical order to mark line endings.
670{
671 SkScalar widthSoFar = 0;
672 bool previousBreakValid = false; // Set when previousBreak is set to a valid candidate break.
673 bool canAddBreakNow = false; // Disallow line breaks before the first glyph of a run.
674 ShapedRunGlyphIterator previousBreak(runs);
675 ShapedRunGlyphIterator glyphIterator(runs);
676 while (ShapedGlyph* glyph = glyphIterator.current()) {
677 if (canAddBreakNow && glyph->fMayLineBreakBefore) {
678 previousBreakValid = true;
679 previousBreak = glyphIterator;
680 }
681 SkScalar glyphWidth = glyph->fAdvance.fX;
Ben Wagnera900ad52018-08-31 17:48:19 -0400682 // TODO: if the glyph is non-visible it can be added.
Ben Wagner8d45a382017-11-16 10:08:28 -0500683 if (widthSoFar + glyphWidth < width) {
684 widthSoFar += glyphWidth;
685 glyphIterator.next();
686 canAddBreakNow = true;
687 continue;
688 }
689
Ben Wagnera900ad52018-08-31 17:48:19 -0400690 // TODO: for both of these emergency break cases
691 // don't break grapheme clusters and pull in any zero width or non-visible
Ben Wagner8d45a382017-11-16 10:08:28 -0500692 if (widthSoFar == 0) {
693 // Adding just this glyph is too much, just break with this glyph
694 glyphIterator.next();
695 previousBreak = glyphIterator;
696 } else if (!previousBreakValid) {
Ben Wagnera900ad52018-08-31 17:48:19 -0400697 // No break opportunity found yet, just break without this glyph
Ben Wagner8d45a382017-11-16 10:08:28 -0500698 previousBreak = glyphIterator;
699 }
700 glyphIterator = previousBreak;
701 glyph = glyphIterator.current();
702 if (glyph) {
703 glyph->fMustLineBreakBefore = true;
704 }
705 widthSoFar = 0;
706 previousBreakValid = false;
707 canAddBreakNow = false;
708 }
709}
710
711// Reorder the runs and glyphs per line and write them out.
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500712 SkPoint currentPoint = point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500713{
714 ShapedRunGlyphIterator previousBreak(runs);
715 ShapedRunGlyphIterator glyphIterator(runs);
716 SkScalar maxAscent = 0;
717 SkScalar maxDescent = 0;
718 SkScalar maxLeading = 0;
719 int previousRunIndex = -1;
720 while (glyphIterator.current()) {
721 int runIndex = glyphIterator.fRunIndex;
722 int glyphIndex = glyphIterator.fGlyphIndex;
723 ShapedGlyph* nextGlyph = glyphIterator.next();
724
725 if (previousRunIndex != runIndex) {
Mike Reedb5784ac2018-11-12 09:35:15 -0500726 SkFontMetrics metrics;
Ben Wagner8d45a382017-11-16 10:08:28 -0500727 runs[runIndex].fPaint.getFontMetrics(&metrics);
728 maxAscent = SkTMin(maxAscent, metrics.fAscent);
729 maxDescent = SkTMax(maxDescent, metrics.fDescent);
730 maxLeading = SkTMax(maxLeading, metrics.fLeading);
731 previousRunIndex = runIndex;
732 }
733
734 // Nothing can be written until the baseline is known.
735 if (!(nextGlyph == nullptr || nextGlyph->fMustLineBreakBefore)) {
736 continue;
737 }
738
739 currentPoint.fY -= maxAscent;
740
741 int numRuns = runIndex - previousBreak.fRunIndex + 1;
742 SkAutoSTMalloc<4, UBiDiLevel> runLevels(numRuns);
743 for (int i = 0; i < numRuns; ++i) {
744 runLevels[i] = runs[previousBreak.fRunIndex + i].fLevel;
745 }
746 SkAutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
747 ubidi_reorderVisual(runLevels, numRuns, logicalFromVisual);
748
749 for (int i = 0; i < numRuns; ++i) {
750 int logicalIndex = previousBreak.fRunIndex + logicalFromVisual[i];
751
752 int startGlyphIndex = (logicalIndex == previousBreak.fRunIndex)
753 ? previousBreak.fGlyphIndex
754 : 0;
755 int endGlyphIndex = (logicalIndex == runIndex)
756 ? glyphIndex + 1
757 : runs[logicalIndex].fNumGlyphs;
758 append(builder, runs[logicalIndex], startGlyphIndex, endGlyphIndex, &currentPoint);
759 }
760
761 currentPoint.fY += maxDescent + maxLeading;
762 currentPoint.fX = point.fX;
763 maxAscent = 0;
764 maxDescent = 0;
765 maxLeading = 0;
766 previousRunIndex = -1;
767 previousBreak = glyphIterator;
768 }
769}
770
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500771 return currentPoint;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400772}