blob: 8c15e3349308ce69456dcfc12aed8fe3eec3363a [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;
Hal Canaryddef43f2018-11-16 10:53:51 -050078 std::unique_ptr<SkStreamAsset> typefaceAsset(tf->openStream(&index));
79 if (!typefaceAsset) {
80 SkString name;
81 tf->getFamilyName(&name);
82 SkDebugf("Typeface '%s' has no data :(\n", name.c_str());
83 return nullptr;
84 }
85 HBBlob blob(stream_to_blob(std::move(typefaceAsset)));
Ben Wagnera25fbef2017-08-30 13:56:19 -040086 HBFace face(hb_face_create(blob.get(), (unsigned)index));
87 SkASSERT(face);
88 if (!face) {
Ben Wagnere0001732017-08-31 16:26:26 -040089 return nullptr;
Ben Wagnera25fbef2017-08-30 13:56:19 -040090 }
91 hb_face_set_index(face.get(), (unsigned)index);
Ben Wagnere0001732017-08-31 16:26:26 -040092 hb_face_set_upem(face.get(), tf->getUnitsPerEm());
Ben Wagnera25fbef2017-08-30 13:56:19 -040093
Ben Wagnere0001732017-08-31 16:26:26 -040094 HBFont font(hb_font_create(face.get()));
95 SkASSERT(font);
96 if (!font) {
97 return nullptr;
98 }
Ben Wagnere0001732017-08-31 16:26:26 -040099 hb_ot_font_set_funcs(font.get());
100 int axis_count = tf->getVariationDesignPosition(nullptr, 0);
101 if (axis_count > 0) {
102 SkAutoSTMalloc<4, SkFontArguments::VariationPosition::Coordinate> axis_values(axis_count);
103 if (tf->getVariationDesignPosition(axis_values, axis_count) == axis_count) {
104 hb_font_set_variations(font.get(),
105 reinterpret_cast<hb_variation_t*>(axis_values.get()),
106 axis_count);
107 }
108 }
109 return font;
110}
111
Hal Canaryf107a2f2018-07-25 16:52:48 -0400112/** this version replaces invalid utf-8 sequences with code point U+FFFD. */
113static inline SkUnichar utf8_next(const char** ptr, const char* end) {
114 SkUnichar val = SkUTF::NextUTF8(ptr, end);
115 if (val < 0) {
116 return 0xFFFD; // REPLACEMENT CHARACTER
117 }
118 return val;
119}
120
Ben Wagner8d45a382017-11-16 10:08:28 -0500121class RunIterator {
122public:
123 virtual ~RunIterator() {}
124 virtual void consume() = 0;
125 // Pointer one past the last (utf8) element in the current run.
126 virtual const char* endOfCurrentRun() const = 0;
127 virtual bool atEnd() const = 0;
128 bool operator<(const RunIterator& that) const {
129 return this->endOfCurrentRun() < that.endOfCurrentRun();
130 }
131};
132
133class BiDiRunIterator : public RunIterator {
134public:
135 static SkTLazy<BiDiRunIterator> Make(const char* utf8, size_t utf8Bytes, UBiDiLevel level) {
136 SkTLazy<BiDiRunIterator> ret;
137
138 // ubidi only accepts utf16 (though internally it basically works on utf32 chars).
139 // We want an ubidi_setPara(UBiDi*, UText*, UBiDiLevel, UBiDiLevel*, UErrorCode*);
140 if (!SkTFitsIn<int32_t>(utf8Bytes)) {
141 SkDebugf("Bidi error: text too long");
142 return ret;
143 }
144 icu::UnicodeString utf16 = icu::UnicodeString::fromUTF8(icu::StringPiece(utf8, utf8Bytes));
145
146 UErrorCode status = U_ZERO_ERROR;
147 ICUBiDi bidi(ubidi_openSized(utf16.length(), 0, &status));
148 if (U_FAILURE(status)) {
149 SkDebugf("Bidi error: %s", u_errorName(status));
150 return ret;
151 }
152 SkASSERT(bidi);
153
154 // The required lifetime of utf16 isn't well documented.
155 // It appears it isn't used after ubidi_setPara except through ubidi_getText.
156 ubidi_setPara(bidi.get(), utf16.getBuffer(), utf16.length(), level, nullptr, &status);
157 if (U_FAILURE(status)) {
158 SkDebugf("Bidi error: %s", u_errorName(status));
159 return ret;
160 }
161
Hal Canary4014ba62018-07-24 11:33:21 -0400162 ret.init(utf8, utf8 + utf8Bytes, std::move(bidi));
Ben Wagner8d45a382017-11-16 10:08:28 -0500163 return ret;
164 }
Hal Canary4014ba62018-07-24 11:33:21 -0400165 BiDiRunIterator(const char* utf8, const char* end, ICUBiDi bidi)
Ben Wagner8d45a382017-11-16 10:08:28 -0500166 : fBidi(std::move(bidi))
167 , fEndOfCurrentRun(utf8)
Hal Canary4014ba62018-07-24 11:33:21 -0400168 , fEndOfAllRuns(end)
Ben Wagner8d45a382017-11-16 10:08:28 -0500169 , fUTF16LogicalPosition(0)
170 , fLevel(UBIDI_DEFAULT_LTR)
171 {}
172 void consume() override {
173 SkASSERT(fUTF16LogicalPosition < ubidi_getLength(fBidi.get()));
174 int32_t endPosition = ubidi_getLength(fBidi.get());
175 fLevel = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400176 SkUnichar u = utf8_next(&fEndOfCurrentRun, fEndOfAllRuns);
177 fUTF16LogicalPosition += SkUTF::ToUTF16(u);
Ben Wagner8d45a382017-11-16 10:08:28 -0500178 UBiDiLevel level;
179 while (fUTF16LogicalPosition < endPosition) {
180 level = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
181 if (level != fLevel) {
182 break;
183 }
Hal Canaryf107a2f2018-07-25 16:52:48 -0400184 u = utf8_next(&fEndOfCurrentRun, fEndOfAllRuns);
185 fUTF16LogicalPosition += SkUTF::ToUTF16(u);
Ben Wagner8d45a382017-11-16 10:08:28 -0500186 }
187 }
188 const char* endOfCurrentRun() const override {
189 return fEndOfCurrentRun;
190 }
191 bool atEnd() const override {
192 return fUTF16LogicalPosition == ubidi_getLength(fBidi.get());
193 }
194
195 UBiDiLevel currentLevel() const {
196 return fLevel;
197 }
198private:
199 ICUBiDi fBidi;
200 const char* fEndOfCurrentRun;
Hal Canary4014ba62018-07-24 11:33:21 -0400201 const char* fEndOfAllRuns;
Ben Wagner8d45a382017-11-16 10:08:28 -0500202 int32_t fUTF16LogicalPosition;
203 UBiDiLevel fLevel;
204};
205
206class ScriptRunIterator : public RunIterator {
207public:
208 static SkTLazy<ScriptRunIterator> Make(const char* utf8, size_t utf8Bytes,
209 hb_unicode_funcs_t* hbUnicode)
210 {
211 SkTLazy<ScriptRunIterator> ret;
212 ret.init(utf8, utf8Bytes, hbUnicode);
213 return ret;
214 }
215 ScriptRunIterator(const char* utf8, size_t utf8Bytes, hb_unicode_funcs_t* hbUnicode)
216 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
217 , fHBUnicode(hbUnicode)
218 , fCurrentScript(HB_SCRIPT_UNKNOWN)
219 {}
220 void consume() override {
221 SkASSERT(fCurrent < fEnd);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400222 SkUnichar u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500223 fCurrentScript = hb_unicode_script(fHBUnicode, u);
224 while (fCurrent < fEnd) {
225 const char* prev = fCurrent;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400226 u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500227 const hb_script_t script = hb_unicode_script(fHBUnicode, u);
228 if (script != fCurrentScript) {
229 if (fCurrentScript == HB_SCRIPT_INHERITED || fCurrentScript == HB_SCRIPT_COMMON) {
230 fCurrentScript = script;
231 } else if (script == HB_SCRIPT_INHERITED || script == HB_SCRIPT_COMMON) {
232 continue;
233 } else {
234 fCurrent = prev;
235 break;
236 }
237 }
238 }
239 if (fCurrentScript == HB_SCRIPT_INHERITED) {
240 fCurrentScript = HB_SCRIPT_COMMON;
241 }
242 }
243 const char* endOfCurrentRun() const override {
244 return fCurrent;
245 }
246 bool atEnd() const override {
247 return fCurrent == fEnd;
248 }
249
250 hb_script_t currentScript() const {
251 return fCurrentScript;
252 }
253private:
254 const char* fCurrent;
255 const char* fEnd;
256 hb_unicode_funcs_t* fHBUnicode;
257 hb_script_t fCurrentScript;
258};
259
260class FontRunIterator : public RunIterator {
261public:
262 static SkTLazy<FontRunIterator> Make(const char* utf8, size_t utf8Bytes,
263 sk_sp<SkTypeface> typeface,
264 hb_font_t* hbFace,
265 sk_sp<SkFontMgr> fallbackMgr)
266 {
267 SkTLazy<FontRunIterator> ret;
268 ret.init(utf8, utf8Bytes, std::move(typeface), hbFace, std::move(fallbackMgr));
269 return ret;
270 }
271 FontRunIterator(const char* utf8, size_t utf8Bytes, sk_sp<SkTypeface> typeface,
272 hb_font_t* hbFace, sk_sp<SkFontMgr> fallbackMgr)
273 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
274 , fFallbackMgr(std::move(fallbackMgr))
275 , fHBFont(hbFace), fTypeface(std::move(typeface))
276 , fFallbackHBFont(nullptr), fFallbackTypeface(nullptr)
277 , fCurrentHBFont(fHBFont), fCurrentTypeface(fTypeface.get())
278 {}
279 void consume() override {
280 SkASSERT(fCurrent < fEnd);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400281 SkUnichar u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500282 // If the starting typeface can handle this character, use it.
283 if (fTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1)) {
Ben Wagnera900ad52018-08-31 17:48:19 -0400284 fCurrentTypeface = fTypeface.get();
285 fCurrentHBFont = fHBFont;
286 // If the current fallback can handle this character, use it.
287 } else if (fFallbackTypeface &&
288 fFallbackTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1))
289 {
290 fCurrentTypeface = fFallbackTypeface.get();
291 fCurrentHBFont = fFallbackHBFont.get();
Ben Wagner8d45a382017-11-16 10:08:28 -0500292 // If not, try to find a fallback typeface
293 } else {
294 fFallbackTypeface.reset(fFallbackMgr->matchFamilyStyleCharacter(
295 nullptr, fTypeface->fontStyle(), nullptr, 0, u));
Ben Wagner8d45a382017-11-16 10:08:28 -0500296 fFallbackHBFont = create_hb_font(fFallbackTypeface.get());
297 fCurrentTypeface = fFallbackTypeface.get();
298 fCurrentHBFont = fFallbackHBFont.get();
Ben Wagner8d45a382017-11-16 10:08:28 -0500299 }
300
301 while (fCurrent < fEnd) {
302 const char* prev = fCurrent;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400303 u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500304
Ben Wagnera900ad52018-08-31 17:48:19 -0400305 // If not using initial typeface and initial typeface has this character, stop fallback.
306 if (fCurrentTypeface != fTypeface.get() &&
Ben Wagner8d45a382017-11-16 10:08:28 -0500307 fTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1))
308 {
309 fCurrent = prev;
310 return;
311 }
312 // If the current typeface cannot handle this character, stop using it.
313 if (!fCurrentTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1)) {
314 fCurrent = prev;
315 return;
316 }
317 }
318 }
319 const char* endOfCurrentRun() const override {
320 return fCurrent;
321 }
322 bool atEnd() const override {
323 return fCurrent == fEnd;
324 }
325
326 SkTypeface* currentTypeface() const {
327 return fCurrentTypeface;
328 }
329 hb_font_t* currentHBFont() const {
330 return fCurrentHBFont;
331 }
332private:
333 const char* fCurrent;
334 const char* fEnd;
335 sk_sp<SkFontMgr> fFallbackMgr;
336 hb_font_t* fHBFont;
337 sk_sp<SkTypeface> fTypeface;
338 HBFont fFallbackHBFont;
339 sk_sp<SkTypeface> fFallbackTypeface;
340 hb_font_t* fCurrentHBFont;
341 SkTypeface* fCurrentTypeface;
342};
343
344class RunIteratorQueue {
345public:
346 void insert(RunIterator* runIterator) {
347 fRunIterators.insert(runIterator);
348 }
349
350 bool advanceRuns() {
351 const RunIterator* leastRun = fRunIterators.peek();
352 if (leastRun->atEnd()) {
353 SkASSERT(this->allRunsAreAtEnd());
354 return false;
355 }
356 const char* leastEnd = leastRun->endOfCurrentRun();
357 RunIterator* currentRun = nullptr;
358 SkDEBUGCODE(const char* previousEndOfCurrentRun);
359 while ((currentRun = fRunIterators.peek())->endOfCurrentRun() <= leastEnd) {
360 fRunIterators.pop();
361 SkDEBUGCODE(previousEndOfCurrentRun = currentRun->endOfCurrentRun());
362 currentRun->consume();
363 SkASSERT(previousEndOfCurrentRun < currentRun->endOfCurrentRun());
364 fRunIterators.insert(currentRun);
365 }
366 return true;
367 }
368
369 const char* endOfCurrentRun() const {
370 return fRunIterators.peek()->endOfCurrentRun();
371 }
372
373private:
374 bool allRunsAreAtEnd() const {
375 for (int i = 0; i < fRunIterators.count(); ++i) {
376 if (!fRunIterators.at(i)->atEnd()) {
377 return false;
378 }
379 }
380 return true;
381 }
382
383 static bool CompareRunIterator(RunIterator* const& a, RunIterator* const& b) {
384 return *a < *b;
385 }
386 SkTDPQueue<RunIterator*, CompareRunIterator> fRunIterators;
387};
388
389struct ShapedGlyph {
390 SkGlyphID fID;
391 uint32_t fCluster;
392 SkPoint fOffset;
393 SkVector fAdvance;
394 bool fMayLineBreakBefore;
395 bool fMustLineBreakBefore;
396 bool fHasVisual;
397};
398struct ShapedRun {
399 ShapedRun(const char* utf8Start, const char* utf8End, int numGlyphs, const SkPaint& paint,
400 UBiDiLevel level, std::unique_ptr<ShapedGlyph[]> glyphs)
401 : fUtf8Start(utf8Start), fUtf8End(utf8End), fNumGlyphs(numGlyphs), fPaint(paint)
402 , fLevel(level), fGlyphs(std::move(glyphs))
403 {}
404
405 const char* fUtf8Start;
406 const char* fUtf8End;
407 int fNumGlyphs;
408 SkPaint fPaint;
409 UBiDiLevel fLevel;
410 std::unique_ptr<ShapedGlyph[]> fGlyphs;
411};
412
413static constexpr bool is_LTR(UBiDiLevel level) {
414 return (level & 1) == 0;
415}
416
417static void append(SkTextBlobBuilder* b, const ShapedRun& run, int start, int end, SkPoint* p) {
418 unsigned len = end - start;
Cary Clarke12a0902018-08-09 10:07:33 -0400419 auto runBuffer = SkTextBlobBuilderPriv::AllocRunTextPos(b, run.fPaint, len,
420 run.fUtf8End - run.fUtf8Start, SkString());
Ben Wagner8d45a382017-11-16 10:08:28 -0500421 memcpy(runBuffer.utf8text, run.fUtf8Start, run.fUtf8End - run.fUtf8Start);
422
423 for (unsigned i = 0; i < len; i++) {
424 // Glyphs are in logical order, but output ltr since PDF readers seem to expect that.
425 const ShapedGlyph& glyph = run.fGlyphs[is_LTR(run.fLevel) ? start + i : end - 1 - i];
426 runBuffer.glyphs[i] = glyph.fID;
427 runBuffer.clusters[i] = glyph.fCluster;
428 reinterpret_cast<SkPoint*>(runBuffer.pos)[i] =
429 SkPoint::Make(p->fX + glyph.fOffset.fX, p->fY - glyph.fOffset.fY);
430 p->fX += glyph.fAdvance.fX;
431 p->fY += glyph.fAdvance.fY;
432 }
433}
434
435struct ShapedRunGlyphIterator {
436 ShapedRunGlyphIterator(const SkTArray<ShapedRun>& origRuns)
437 : fRuns(&origRuns), fRunIndex(0), fGlyphIndex(0)
438 { }
439
440 ShapedRunGlyphIterator(const ShapedRunGlyphIterator& that) = default;
441 ShapedRunGlyphIterator& operator=(const ShapedRunGlyphIterator& that) = default;
442 bool operator==(const ShapedRunGlyphIterator& that) const {
443 return fRuns == that.fRuns &&
444 fRunIndex == that.fRunIndex &&
445 fGlyphIndex == that.fGlyphIndex;
446 }
447 bool operator!=(const ShapedRunGlyphIterator& that) const {
448 return fRuns != that.fRuns ||
449 fRunIndex != that.fRunIndex ||
450 fGlyphIndex != that.fGlyphIndex;
451 }
452
453 ShapedGlyph* next() {
454 const SkTArray<ShapedRun>& runs = *fRuns;
455 SkASSERT(fRunIndex < runs.count());
456 SkASSERT(fGlyphIndex < runs[fRunIndex].fNumGlyphs);
457
458 ++fGlyphIndex;
459 if (fGlyphIndex == runs[fRunIndex].fNumGlyphs) {
460 fGlyphIndex = 0;
461 ++fRunIndex;
462 if (fRunIndex >= runs.count()) {
463 return nullptr;
464 }
465 }
466 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
467 }
468
469 ShapedGlyph* current() {
470 const SkTArray<ShapedRun>& runs = *fRuns;
471 if (fRunIndex >= runs.count()) {
472 return nullptr;
473 }
474 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
475 }
476
477 const SkTArray<ShapedRun>* fRuns;
478 int fRunIndex;
479 int fGlyphIndex;
480};
481
482} // namespace
483
484struct SkShaper::Impl {
485 HBFont fHarfBuzzFont;
486 HBBuffer fBuffer;
487 sk_sp<SkTypeface> fTypeface;
488 std::unique_ptr<icu::BreakIterator> fBreakIterator;
489};
490
Ben Wagnere0001732017-08-31 16:26:26 -0400491SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
Hal Canary0e07ad72018-02-08 13:06:56 -0500492 SkOnce once;
493 once([] { SkLoadICU(); });
494
Ben Wagnere0001732017-08-31 16:26:26 -0400495 fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
496 fImpl->fHarfBuzzFont = create_hb_font(fImpl->fTypeface.get());
Ben Wagnera25fbef2017-08-30 13:56:19 -0400497 SkASSERT(fImpl->fHarfBuzzFont);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400498 fImpl->fBuffer.reset(hb_buffer_create());
Ben Wagner8d45a382017-11-16 10:08:28 -0500499 SkASSERT(fImpl->fBuffer);
500
501 icu::Locale thai("th");
502 UErrorCode status = U_ZERO_ERROR;
503 fImpl->fBreakIterator.reset(icu::BreakIterator::createLineInstance(thai, status));
504 if (U_FAILURE(status)) {
505 SkDebugf("Could not create break iterator: %s", u_errorName(status));
506 SK_ABORT("");
507 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400508}
509
510SkShaper::~SkShaper() {}
511
Ben Wagner8d45a382017-11-16 10:08:28 -0500512bool SkShaper::good() const {
513 return fImpl->fHarfBuzzFont &&
514 fImpl->fBuffer &&
515 fImpl->fTypeface &&
516 fImpl->fBreakIterator;
517}
Ben Wagnera25fbef2017-08-30 13:56:19 -0400518
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500519SkPoint SkShaper::shape(SkTextBlobBuilder* builder,
520 const SkPaint& srcPaint,
521 const char* utf8,
522 size_t utf8Bytes,
523 bool leftToRight,
524 SkPoint point,
525 SkScalar width) const {
Ben Wagner67e3a302017-09-05 14:46:19 -0400526 sk_sp<SkFontMgr> fontMgr = SkFontMgr::RefDefault();
Ben Wagnera25fbef2017-08-30 13:56:19 -0400527 SkASSERT(builder);
Ben Wagner8d45a382017-11-16 10:08:28 -0500528 UBiDiLevel defaultLevel = leftToRight ? UBIDI_DEFAULT_LTR : UBIDI_DEFAULT_RTL;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400529 //hb_script_t script = ...
Ben Wagnera25fbef2017-08-30 13:56:19 -0400530
Ben Wagner8d45a382017-11-16 10:08:28 -0500531 SkTArray<ShapedRun> runs;
532{
533 RunIteratorQueue runSegmenter;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400534
Ben Wagner8d45a382017-11-16 10:08:28 -0500535 SkTLazy<BiDiRunIterator> maybeBidi(BiDiRunIterator::Make(utf8, utf8Bytes, defaultLevel));
536 BiDiRunIterator* bidi = maybeBidi.getMaybeNull();
537 if (!bidi) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500538 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400539 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500540 runSegmenter.insert(bidi);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400541
Ben Wagner8d45a382017-11-16 10:08:28 -0500542 hb_unicode_funcs_t* hbUnicode = hb_buffer_get_unicode_funcs(fImpl->fBuffer.get());
543 SkTLazy<ScriptRunIterator> maybeScript(ScriptRunIterator::Make(utf8, utf8Bytes, hbUnicode));
544 ScriptRunIterator* script = maybeScript.getMaybeNull();
545 if (!script) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500546 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400547 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500548 runSegmenter.insert(script);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400549
Ben Wagner8d45a382017-11-16 10:08:28 -0500550 SkTLazy<FontRunIterator> maybeFont(FontRunIterator::Make(utf8, utf8Bytes,
551 fImpl->fTypeface,
552 fImpl->fHarfBuzzFont.get(),
553 std::move(fontMgr)));
554 FontRunIterator* font = maybeFont.getMaybeNull();
555 if (!font) {
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(font);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400559
Ben Wagner8d45a382017-11-16 10:08:28 -0500560 icu::BreakIterator& breakIterator = *fImpl->fBreakIterator;
561 {
562 UErrorCode status = U_ZERO_ERROR;
563 UText utf8UText = UTEXT_INITIALIZER;
564 utext_openUTF8(&utf8UText, utf8, utf8Bytes, &status);
565 std::unique_ptr<UText, SkFunctionWrapper<UText*, UText, utext_close>> autoClose(&utf8UText);
566 if (U_FAILURE(status)) {
567 SkDebugf("Could not create utf8UText: %s", u_errorName(status));
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500568 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500569 }
570 breakIterator.setText(&utf8UText, status);
571 //utext_close(&utf8UText);
572 if (U_FAILURE(status)) {
573 SkDebugf("Could not setText on break iterator: %s", u_errorName(status));
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500574 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500575 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400576 }
577
Ben Wagner8d45a382017-11-16 10:08:28 -0500578 const char* utf8Start = nullptr;
579 const char* utf8End = utf8;
580 while (runSegmenter.advanceRuns()) {
581 utf8Start = utf8End;
582 utf8End = runSegmenter.endOfCurrentRun();
583
584 hb_buffer_t* buffer = fImpl->fBuffer.get();
585 SkAutoTCallVProc<hb_buffer_t, hb_buffer_clear_contents> autoClearBuffer(buffer);
586 hb_buffer_set_content_type(buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
587 hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
588
Ben Wagnerc0c99b32018-08-07 10:14:18 -0400589 // Add precontext.
590 hb_buffer_add_utf8(buffer, utf8, utf8Start - utf8, utf8Start - utf8, 0);
591
Ben Wagner8d45a382017-11-16 10:08:28 -0500592 // Populate the hb_buffer directly with utf8 cluster indexes.
593 const char* utf8Current = utf8Start;
594 while (utf8Current < utf8End) {
595 unsigned int cluster = utf8Current - utf8Start;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400596 hb_codepoint_t u = utf8_next(&utf8Current, utf8End);
Ben Wagner8d45a382017-11-16 10:08:28 -0500597 hb_buffer_add(buffer, u, cluster);
598 }
599
Ben Wagnerc0c99b32018-08-07 10:14:18 -0400600 // Add postcontext.
601 hb_buffer_add_utf8(buffer, utf8Current, utf8 + utf8Bytes - utf8Current, 0, 0);
602
Ben Wagner8d45a382017-11-16 10:08:28 -0500603 size_t utf8runLength = utf8End - utf8Start;
604 if (!SkTFitsIn<int>(utf8runLength)) {
605 SkDebugf("Shaping error: utf8 too long");
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500606 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500607 }
608 hb_buffer_set_script(buffer, script->currentScript());
609 hb_direction_t direction = is_LTR(bidi->currentLevel()) ? HB_DIRECTION_LTR:HB_DIRECTION_RTL;
610 hb_buffer_set_direction(buffer, direction);
611 // TODO: language
612 hb_buffer_guess_segment_properties(buffer);
613 // TODO: features
Hal Canary0dfa2082018-10-31 13:02:49 -0400614 if (!font->currentHBFont()) {
615 continue;
616 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500617 hb_shape(font->currentHBFont(), buffer, nullptr, 0);
618 unsigned len = hb_buffer_get_length(buffer);
619 if (len == 0) {
620 continue;
621 }
622
623 if (direction == HB_DIRECTION_RTL) {
624 // Put the clusters back in logical order.
625 // Note that the advances remain ltr.
626 hb_buffer_reverse(buffer);
627 }
628 hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, nullptr);
629 hb_glyph_position_t* pos = hb_buffer_get_glyph_positions(buffer, nullptr);
630
631 if (!SkTFitsIn<int>(len)) {
632 SkDebugf("Shaping error: too many glyphs");
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500633 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500634 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400635
636 SkPaint paint(srcPaint);
637 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Ben Wagner8d45a382017-11-16 10:08:28 -0500638 paint.setTypeface(sk_ref_sp(font->currentTypeface()));
639 ShapedRun& run = runs.emplace_back(utf8Start, utf8End, len, paint, bidi->currentLevel(),
640 std::unique_ptr<ShapedGlyph[]>(new ShapedGlyph[len]));
641 int scaleX, scaleY;
642 hb_font_get_scale(font->currentHBFont(), &scaleX, &scaleY);
643 double textSizeY = run.fPaint.getTextSize() / scaleY;
644 double textSizeX = run.fPaint.getTextSize() / scaleX * run.fPaint.getTextScaleX();
645 for (unsigned i = 0; i < len; i++) {
646 ShapedGlyph& glyph = run.fGlyphs[i];
647 glyph.fID = info[i].codepoint;
648 glyph.fCluster = info[i].cluster;
649 glyph.fOffset.fX = pos[i].x_offset * textSizeX;
650 glyph.fOffset.fY = pos[i].y_offset * textSizeY;
651 glyph.fAdvance.fX = pos[i].x_advance * textSizeX;
652 glyph.fAdvance.fY = pos[i].y_advance * textSizeY;
653 glyph.fHasVisual = true; //!font->currentTypeface()->glyphBoundsAreZero(glyph.fID);
654 //info->mask safe_to_break;
655 glyph.fMustLineBreakBefore = false;
656 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400657
Ben Wagner8d45a382017-11-16 10:08:28 -0500658 int32_t clusterOffset = utf8Start - utf8;
659 uint32_t previousCluster = 0xFFFFFFFF;
660 for (unsigned i = 0; i < len; ++i) {
661 ShapedGlyph& glyph = run.fGlyphs[i];
662 int32_t glyphCluster = glyph.fCluster + clusterOffset;
663 int32_t breakIteratorCurrent = breakIterator.current();
664 while (breakIteratorCurrent != icu::BreakIterator::DONE &&
665 breakIteratorCurrent < glyphCluster)
666 {
667 breakIteratorCurrent = breakIterator.next();
Ben Wagner2868b782017-08-31 14:12:27 -0400668 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500669 glyph.fMayLineBreakBefore = glyph.fCluster != previousCluster &&
670 breakIteratorCurrent == glyphCluster;
671 previousCluster = glyph.fCluster;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400672 }
673 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500674}
675
676// Iterate over the glyphs in logical order to mark line endings.
677{
678 SkScalar widthSoFar = 0;
679 bool previousBreakValid = false; // Set when previousBreak is set to a valid candidate break.
680 bool canAddBreakNow = false; // Disallow line breaks before the first glyph of a run.
681 ShapedRunGlyphIterator previousBreak(runs);
682 ShapedRunGlyphIterator glyphIterator(runs);
683 while (ShapedGlyph* glyph = glyphIterator.current()) {
684 if (canAddBreakNow && glyph->fMayLineBreakBefore) {
685 previousBreakValid = true;
686 previousBreak = glyphIterator;
687 }
688 SkScalar glyphWidth = glyph->fAdvance.fX;
Ben Wagnera900ad52018-08-31 17:48:19 -0400689 // TODO: if the glyph is non-visible it can be added.
Ben Wagner8d45a382017-11-16 10:08:28 -0500690 if (widthSoFar + glyphWidth < width) {
691 widthSoFar += glyphWidth;
692 glyphIterator.next();
693 canAddBreakNow = true;
694 continue;
695 }
696
Ben Wagnera900ad52018-08-31 17:48:19 -0400697 // TODO: for both of these emergency break cases
698 // don't break grapheme clusters and pull in any zero width or non-visible
Ben Wagner8d45a382017-11-16 10:08:28 -0500699 if (widthSoFar == 0) {
700 // Adding just this glyph is too much, just break with this glyph
701 glyphIterator.next();
702 previousBreak = glyphIterator;
703 } else if (!previousBreakValid) {
Ben Wagnera900ad52018-08-31 17:48:19 -0400704 // No break opportunity found yet, just break without this glyph
Ben Wagner8d45a382017-11-16 10:08:28 -0500705 previousBreak = glyphIterator;
706 }
707 glyphIterator = previousBreak;
708 glyph = glyphIterator.current();
709 if (glyph) {
710 glyph->fMustLineBreakBefore = true;
711 }
712 widthSoFar = 0;
713 previousBreakValid = false;
714 canAddBreakNow = false;
715 }
716}
717
718// Reorder the runs and glyphs per line and write them out.
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500719 SkPoint currentPoint = point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500720{
721 ShapedRunGlyphIterator previousBreak(runs);
722 ShapedRunGlyphIterator glyphIterator(runs);
723 SkScalar maxAscent = 0;
724 SkScalar maxDescent = 0;
725 SkScalar maxLeading = 0;
726 int previousRunIndex = -1;
727 while (glyphIterator.current()) {
728 int runIndex = glyphIterator.fRunIndex;
729 int glyphIndex = glyphIterator.fGlyphIndex;
730 ShapedGlyph* nextGlyph = glyphIterator.next();
731
732 if (previousRunIndex != runIndex) {
Mike Reedb5784ac2018-11-12 09:35:15 -0500733 SkFontMetrics metrics;
Ben Wagner8d45a382017-11-16 10:08:28 -0500734 runs[runIndex].fPaint.getFontMetrics(&metrics);
735 maxAscent = SkTMin(maxAscent, metrics.fAscent);
736 maxDescent = SkTMax(maxDescent, metrics.fDescent);
737 maxLeading = SkTMax(maxLeading, metrics.fLeading);
738 previousRunIndex = runIndex;
739 }
740
741 // Nothing can be written until the baseline is known.
742 if (!(nextGlyph == nullptr || nextGlyph->fMustLineBreakBefore)) {
743 continue;
744 }
745
746 currentPoint.fY -= maxAscent;
747
748 int numRuns = runIndex - previousBreak.fRunIndex + 1;
749 SkAutoSTMalloc<4, UBiDiLevel> runLevels(numRuns);
750 for (int i = 0; i < numRuns; ++i) {
751 runLevels[i] = runs[previousBreak.fRunIndex + i].fLevel;
752 }
753 SkAutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
754 ubidi_reorderVisual(runLevels, numRuns, logicalFromVisual);
755
756 for (int i = 0; i < numRuns; ++i) {
757 int logicalIndex = previousBreak.fRunIndex + logicalFromVisual[i];
758
759 int startGlyphIndex = (logicalIndex == previousBreak.fRunIndex)
760 ? previousBreak.fGlyphIndex
761 : 0;
762 int endGlyphIndex = (logicalIndex == runIndex)
763 ? glyphIndex + 1
764 : runs[logicalIndex].fNumGlyphs;
765 append(builder, runs[logicalIndex], startGlyphIndex, endGlyphIndex, &currentPoint);
766 }
767
768 currentPoint.fY += maxDescent + maxLeading;
769 currentPoint.fX = point.fX;
770 maxAscent = 0;
771 maxDescent = 0;
772 maxLeading = 0;
773 previousRunIndex = -1;
774 previousBreak = glyphIterator;
775 }
776}
777
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500778 return currentPoint;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400779}