blob: ca05b94955aaba9eef8333ae283a81400a824ef7 [file] [log] [blame]
Ben Wagnera25fbef2017-08-30 13:56:19 -04001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Ben Wagner17774242018-08-07 14:31:33 -04008#include "SkFontArguments.h"
Ben Wagner67e3a302017-09-05 14:46:19 -04009#include "SkFontMgr.h"
Hal Canary0e07ad72018-02-08 13:06:56 -050010#include "SkLoadICU.h"
Ben Wagner17774242018-08-07 14:31:33 -040011#include "SkMalloc.h"
Hal Canary0e07ad72018-02-08 13:06:56 -050012#include "SkOnce.h"
Hal Canary2a1848d2018-11-26 17:23:24 -050013#include "SkFont.h"
Mike Reed77f94ea2019-01-22 16:30:40 -050014#include "SkFontMetrics.h"
Ben Wagner17774242018-08-07 14:31:33 -040015#include "SkPoint.h"
16#include "SkRefCnt.h"
17#include "SkScalar.h"
Ben Wagnera25fbef2017-08-30 13:56:19 -040018#include "SkShaper.h"
19#include "SkStream.h"
Ben Wagner17774242018-08-07 14:31:33 -040020#include "SkString.h"
21#include "SkTArray.h"
Ben Wagner8d45a382017-11-16 10:08:28 -050022#include "SkTDPQueue.h"
Ben Wagner17774242018-08-07 14:31:33 -040023#include "SkTFitsIn.h"
Ben Wagner8d45a382017-11-16 10:08:28 -050024#include "SkTLazy.h"
Ben Wagnere0001732017-08-31 16:26:26 -040025#include "SkTemplates.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.
Florin Malita6d415bc2019-01-17 16:42:15 -0500156 ubidi_setPara(bidi.get(),
157 reinterpret_cast<const UChar*>(utf16.getBuffer()),
158 utf16.length(), level, nullptr, &status);
Ben Wagner8d45a382017-11-16 10:08:28 -0500159 if (U_FAILURE(status)) {
160 SkDebugf("Bidi error: %s", u_errorName(status));
161 return ret;
162 }
163
Hal Canary4014ba62018-07-24 11:33:21 -0400164 ret.init(utf8, utf8 + utf8Bytes, std::move(bidi));
Ben Wagner8d45a382017-11-16 10:08:28 -0500165 return ret;
166 }
Hal Canary4014ba62018-07-24 11:33:21 -0400167 BiDiRunIterator(const char* utf8, const char* end, ICUBiDi bidi)
Ben Wagner8d45a382017-11-16 10:08:28 -0500168 : fBidi(std::move(bidi))
169 , fEndOfCurrentRun(utf8)
Hal Canary4014ba62018-07-24 11:33:21 -0400170 , fEndOfAllRuns(end)
Ben Wagner8d45a382017-11-16 10:08:28 -0500171 , fUTF16LogicalPosition(0)
172 , fLevel(UBIDI_DEFAULT_LTR)
173 {}
174 void consume() override {
175 SkASSERT(fUTF16LogicalPosition < ubidi_getLength(fBidi.get()));
176 int32_t endPosition = ubidi_getLength(fBidi.get());
177 fLevel = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400178 SkUnichar u = utf8_next(&fEndOfCurrentRun, fEndOfAllRuns);
179 fUTF16LogicalPosition += SkUTF::ToUTF16(u);
Ben Wagner8d45a382017-11-16 10:08:28 -0500180 UBiDiLevel level;
181 while (fUTF16LogicalPosition < endPosition) {
182 level = ubidi_getLevelAt(fBidi.get(), fUTF16LogicalPosition);
183 if (level != fLevel) {
184 break;
185 }
Hal Canaryf107a2f2018-07-25 16:52:48 -0400186 u = utf8_next(&fEndOfCurrentRun, fEndOfAllRuns);
187 fUTF16LogicalPosition += SkUTF::ToUTF16(u);
Ben Wagner8d45a382017-11-16 10:08:28 -0500188 }
189 }
190 const char* endOfCurrentRun() const override {
191 return fEndOfCurrentRun;
192 }
193 bool atEnd() const override {
194 return fUTF16LogicalPosition == ubidi_getLength(fBidi.get());
195 }
196
197 UBiDiLevel currentLevel() const {
198 return fLevel;
199 }
200private:
201 ICUBiDi fBidi;
202 const char* fEndOfCurrentRun;
Hal Canary4014ba62018-07-24 11:33:21 -0400203 const char* fEndOfAllRuns;
Ben Wagner8d45a382017-11-16 10:08:28 -0500204 int32_t fUTF16LogicalPosition;
205 UBiDiLevel fLevel;
206};
207
208class ScriptRunIterator : public RunIterator {
209public:
210 static SkTLazy<ScriptRunIterator> Make(const char* utf8, size_t utf8Bytes,
211 hb_unicode_funcs_t* hbUnicode)
212 {
213 SkTLazy<ScriptRunIterator> ret;
214 ret.init(utf8, utf8Bytes, hbUnicode);
215 return ret;
216 }
217 ScriptRunIterator(const char* utf8, size_t utf8Bytes, hb_unicode_funcs_t* hbUnicode)
218 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
219 , fHBUnicode(hbUnicode)
220 , fCurrentScript(HB_SCRIPT_UNKNOWN)
221 {}
222 void consume() override {
223 SkASSERT(fCurrent < fEnd);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400224 SkUnichar u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500225 fCurrentScript = hb_unicode_script(fHBUnicode, u);
226 while (fCurrent < fEnd) {
227 const char* prev = fCurrent;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400228 u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500229 const hb_script_t script = hb_unicode_script(fHBUnicode, u);
230 if (script != fCurrentScript) {
231 if (fCurrentScript == HB_SCRIPT_INHERITED || fCurrentScript == HB_SCRIPT_COMMON) {
232 fCurrentScript = script;
233 } else if (script == HB_SCRIPT_INHERITED || script == HB_SCRIPT_COMMON) {
234 continue;
235 } else {
236 fCurrent = prev;
237 break;
238 }
239 }
240 }
241 if (fCurrentScript == HB_SCRIPT_INHERITED) {
242 fCurrentScript = HB_SCRIPT_COMMON;
243 }
244 }
245 const char* endOfCurrentRun() const override {
246 return fCurrent;
247 }
248 bool atEnd() const override {
249 return fCurrent == fEnd;
250 }
251
252 hb_script_t currentScript() const {
253 return fCurrentScript;
254 }
255private:
256 const char* fCurrent;
257 const char* fEnd;
258 hb_unicode_funcs_t* fHBUnicode;
259 hb_script_t fCurrentScript;
260};
261
262class FontRunIterator : public RunIterator {
263public:
264 static SkTLazy<FontRunIterator> Make(const char* utf8, size_t utf8Bytes,
265 sk_sp<SkTypeface> typeface,
266 hb_font_t* hbFace,
267 sk_sp<SkFontMgr> fallbackMgr)
268 {
269 SkTLazy<FontRunIterator> ret;
270 ret.init(utf8, utf8Bytes, std::move(typeface), hbFace, std::move(fallbackMgr));
271 return ret;
272 }
273 FontRunIterator(const char* utf8, size_t utf8Bytes, sk_sp<SkTypeface> typeface,
274 hb_font_t* hbFace, sk_sp<SkFontMgr> fallbackMgr)
275 : fCurrent(utf8), fEnd(fCurrent + utf8Bytes)
276 , fFallbackMgr(std::move(fallbackMgr))
277 , fHBFont(hbFace), fTypeface(std::move(typeface))
278 , fFallbackHBFont(nullptr), fFallbackTypeface(nullptr)
279 , fCurrentHBFont(fHBFont), fCurrentTypeface(fTypeface.get())
280 {}
281 void consume() override {
282 SkASSERT(fCurrent < fEnd);
Hal Canaryf107a2f2018-07-25 16:52:48 -0400283 SkUnichar u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500284 // If the starting typeface can handle this character, use it.
285 if (fTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1)) {
Ben Wagnera900ad52018-08-31 17:48:19 -0400286 fCurrentTypeface = fTypeface.get();
287 fCurrentHBFont = fHBFont;
288 // If the current fallback can handle this character, use it.
289 } else if (fFallbackTypeface &&
290 fFallbackTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1))
291 {
292 fCurrentTypeface = fFallbackTypeface.get();
293 fCurrentHBFont = fFallbackHBFont.get();
Ben Wagner8d45a382017-11-16 10:08:28 -0500294 // If not, try to find a fallback typeface
295 } else {
296 fFallbackTypeface.reset(fFallbackMgr->matchFamilyStyleCharacter(
297 nullptr, fTypeface->fontStyle(), nullptr, 0, u));
Ben Wagner8d45a382017-11-16 10:08:28 -0500298 fFallbackHBFont = create_hb_font(fFallbackTypeface.get());
299 fCurrentTypeface = fFallbackTypeface.get();
300 fCurrentHBFont = fFallbackHBFont.get();
Ben Wagner8d45a382017-11-16 10:08:28 -0500301 }
302
303 while (fCurrent < fEnd) {
304 const char* prev = fCurrent;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400305 u = utf8_next(&fCurrent, fEnd);
Ben Wagner8d45a382017-11-16 10:08:28 -0500306
Ben Wagnera900ad52018-08-31 17:48:19 -0400307 // If not using initial typeface and initial typeface has this character, stop fallback.
308 if (fCurrentTypeface != fTypeface.get() &&
Ben Wagner8d45a382017-11-16 10:08:28 -0500309 fTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1))
310 {
311 fCurrent = prev;
312 return;
313 }
314 // If the current typeface cannot handle this character, stop using it.
315 if (!fCurrentTypeface->charsToGlyphs(&u, SkTypeface::kUTF32_Encoding, nullptr, 1)) {
316 fCurrent = prev;
317 return;
318 }
319 }
320 }
321 const char* endOfCurrentRun() const override {
322 return fCurrent;
323 }
324 bool atEnd() const override {
325 return fCurrent == fEnd;
326 }
327
328 SkTypeface* currentTypeface() const {
329 return fCurrentTypeface;
330 }
331 hb_font_t* currentHBFont() const {
332 return fCurrentHBFont;
333 }
334private:
335 const char* fCurrent;
336 const char* fEnd;
337 sk_sp<SkFontMgr> fFallbackMgr;
338 hb_font_t* fHBFont;
339 sk_sp<SkTypeface> fTypeface;
340 HBFont fFallbackHBFont;
341 sk_sp<SkTypeface> fFallbackTypeface;
342 hb_font_t* fCurrentHBFont;
343 SkTypeface* fCurrentTypeface;
344};
345
346class RunIteratorQueue {
347public:
348 void insert(RunIterator* runIterator) {
349 fRunIterators.insert(runIterator);
350 }
351
352 bool advanceRuns() {
353 const RunIterator* leastRun = fRunIterators.peek();
354 if (leastRun->atEnd()) {
355 SkASSERT(this->allRunsAreAtEnd());
356 return false;
357 }
358 const char* leastEnd = leastRun->endOfCurrentRun();
359 RunIterator* currentRun = nullptr;
360 SkDEBUGCODE(const char* previousEndOfCurrentRun);
361 while ((currentRun = fRunIterators.peek())->endOfCurrentRun() <= leastEnd) {
362 fRunIterators.pop();
363 SkDEBUGCODE(previousEndOfCurrentRun = currentRun->endOfCurrentRun());
364 currentRun->consume();
365 SkASSERT(previousEndOfCurrentRun < currentRun->endOfCurrentRun());
366 fRunIterators.insert(currentRun);
367 }
368 return true;
369 }
370
371 const char* endOfCurrentRun() const {
372 return fRunIterators.peek()->endOfCurrentRun();
373 }
374
375private:
376 bool allRunsAreAtEnd() const {
377 for (int i = 0; i < fRunIterators.count(); ++i) {
378 if (!fRunIterators.at(i)->atEnd()) {
379 return false;
380 }
381 }
382 return true;
383 }
384
385 static bool CompareRunIterator(RunIterator* const& a, RunIterator* const& b) {
386 return *a < *b;
387 }
388 SkTDPQueue<RunIterator*, CompareRunIterator> fRunIterators;
389};
390
391struct ShapedGlyph {
392 SkGlyphID fID;
393 uint32_t fCluster;
394 SkPoint fOffset;
395 SkVector fAdvance;
396 bool fMayLineBreakBefore;
397 bool fMustLineBreakBefore;
398 bool fHasVisual;
399};
400struct ShapedRun {
Mike Reed6d595682018-12-05 17:28:14 -0500401 ShapedRun(const char* utf8Start, const char* utf8End, int numGlyphs, const SkFont& font,
Ben Wagner8d45a382017-11-16 10:08:28 -0500402 UBiDiLevel level, std::unique_ptr<ShapedGlyph[]> glyphs)
Mike Reed6d595682018-12-05 17:28:14 -0500403 : fUtf8Start(utf8Start), fUtf8End(utf8End), fNumGlyphs(numGlyphs), fFont(font)
Ben Wagner8d45a382017-11-16 10:08:28 -0500404 , fLevel(level), fGlyphs(std::move(glyphs))
405 {}
406
407 const char* fUtf8Start;
408 const char* fUtf8End;
409 int fNumGlyphs;
Mike Reed6d595682018-12-05 17:28:14 -0500410 SkFont fFont;
Ben Wagner8d45a382017-11-16 10:08:28 -0500411 UBiDiLevel fLevel;
412 std::unique_ptr<ShapedGlyph[]> fGlyphs;
Florin Malita950243d2019-01-11 11:08:35 -0500413 SkVector fAdvance = { 0, 0 };
Ben Wagner8d45a382017-11-16 10:08:28 -0500414};
415
416static constexpr bool is_LTR(UBiDiLevel level) {
417 return (level & 1) == 0;
418}
419
Florin Malita950243d2019-01-11 11:08:35 -0500420static void append(SkShaper::RunHandler* handler, const SkShaper::RunHandler::RunInfo& runInfo,
421 const ShapedRun& run, int start, int end,
Florin Malita9867f612018-12-12 10:54:49 -0500422 SkPoint* p) {
Ben Wagner8d45a382017-11-16 10:08:28 -0500423 unsigned len = end - start;
Florin Malita9867f612018-12-12 10:54:49 -0500424
Florin Malita950243d2019-01-11 11:08:35 -0500425 const auto buffer = handler->newRunBuffer(runInfo, run.fFont, len, run.fUtf8End - run.fUtf8Start);
Florin Malita9867f612018-12-12 10:54:49 -0500426 SkASSERT(buffer.glyphs);
427 SkASSERT(buffer.positions);
428
429 if (buffer.utf8text) {
430 memcpy(buffer.utf8text, run.fUtf8Start, run.fUtf8End - run.fUtf8Start);
431 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500432
433 for (unsigned i = 0; i < len; i++) {
434 // Glyphs are in logical order, but output ltr since PDF readers seem to expect that.
435 const ShapedGlyph& glyph = run.fGlyphs[is_LTR(run.fLevel) ? start + i : end - 1 - i];
Florin Malita9867f612018-12-12 10:54:49 -0500436 buffer.glyphs[i] = glyph.fID;
437 buffer.positions[i] = SkPoint::Make(p->fX + glyph.fOffset.fX, p->fY - glyph.fOffset.fY);
438 if (buffer.clusters) {
439 buffer.clusters[i] = glyph.fCluster;
440 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500441 p->fX += glyph.fAdvance.fX;
442 p->fY += glyph.fAdvance.fY;
443 }
444}
445
446struct ShapedRunGlyphIterator {
447 ShapedRunGlyphIterator(const SkTArray<ShapedRun>& origRuns)
448 : fRuns(&origRuns), fRunIndex(0), fGlyphIndex(0)
449 { }
450
451 ShapedRunGlyphIterator(const ShapedRunGlyphIterator& that) = default;
452 ShapedRunGlyphIterator& operator=(const ShapedRunGlyphIterator& that) = default;
453 bool operator==(const ShapedRunGlyphIterator& that) const {
454 return fRuns == that.fRuns &&
455 fRunIndex == that.fRunIndex &&
456 fGlyphIndex == that.fGlyphIndex;
457 }
458 bool operator!=(const ShapedRunGlyphIterator& that) const {
459 return fRuns != that.fRuns ||
460 fRunIndex != that.fRunIndex ||
461 fGlyphIndex != that.fGlyphIndex;
462 }
463
464 ShapedGlyph* next() {
465 const SkTArray<ShapedRun>& runs = *fRuns;
466 SkASSERT(fRunIndex < runs.count());
467 SkASSERT(fGlyphIndex < runs[fRunIndex].fNumGlyphs);
468
469 ++fGlyphIndex;
470 if (fGlyphIndex == runs[fRunIndex].fNumGlyphs) {
471 fGlyphIndex = 0;
472 ++fRunIndex;
473 if (fRunIndex >= runs.count()) {
474 return nullptr;
475 }
476 }
477 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
478 }
479
480 ShapedGlyph* current() {
481 const SkTArray<ShapedRun>& runs = *fRuns;
482 if (fRunIndex >= runs.count()) {
483 return nullptr;
484 }
485 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
486 }
487
488 const SkTArray<ShapedRun>* fRuns;
489 int fRunIndex;
490 int fGlyphIndex;
491};
492
493} // namespace
494
495struct SkShaper::Impl {
496 HBFont fHarfBuzzFont;
497 HBBuffer fBuffer;
498 sk_sp<SkTypeface> fTypeface;
499 std::unique_ptr<icu::BreakIterator> fBreakIterator;
500};
501
Ben Wagnere0001732017-08-31 16:26:26 -0400502SkShaper::SkShaper(sk_sp<SkTypeface> tf) : fImpl(new Impl) {
Hal Canary0e07ad72018-02-08 13:06:56 -0500503 SkOnce once;
504 once([] { SkLoadICU(); });
505
Ben Wagnere0001732017-08-31 16:26:26 -0400506 fImpl->fTypeface = tf ? std::move(tf) : SkTypeface::MakeDefault();
507 fImpl->fHarfBuzzFont = create_hb_font(fImpl->fTypeface.get());
Florin Malitaa4e1a632019-01-22 16:27:01 -0500508 if (!fImpl->fHarfBuzzFont) {
509 SkDebugf("create_hb_font failed!\n");
510 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400511 fImpl->fBuffer.reset(hb_buffer_create());
Ben Wagner8d45a382017-11-16 10:08:28 -0500512 SkASSERT(fImpl->fBuffer);
513
514 icu::Locale thai("th");
515 UErrorCode status = U_ZERO_ERROR;
516 fImpl->fBreakIterator.reset(icu::BreakIterator::createLineInstance(thai, status));
517 if (U_FAILURE(status)) {
518 SkDebugf("Could not create break iterator: %s", u_errorName(status));
519 SK_ABORT("");
520 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400521}
522
523SkShaper::~SkShaper() {}
524
Ben Wagner8d45a382017-11-16 10:08:28 -0500525bool SkShaper::good() const {
526 return fImpl->fHarfBuzzFont &&
527 fImpl->fBuffer &&
528 fImpl->fTypeface &&
529 fImpl->fBreakIterator;
530}
Ben Wagnera25fbef2017-08-30 13:56:19 -0400531
Florin Malita950243d2019-01-11 11:08:35 -0500532SkPoint SkShaper::shape(RunHandler* handler,
Hal Canary2a1848d2018-11-26 17:23:24 -0500533 const SkFont& srcPaint,
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500534 const char* utf8,
535 size_t utf8Bytes,
536 bool leftToRight,
537 SkPoint point,
538 SkScalar width) const {
Ben Wagner67e3a302017-09-05 14:46:19 -0400539 sk_sp<SkFontMgr> fontMgr = SkFontMgr::RefDefault();
Florin Malita9867f612018-12-12 10:54:49 -0500540 SkASSERT(handler);
Ben Wagner8d45a382017-11-16 10:08:28 -0500541 UBiDiLevel defaultLevel = leftToRight ? UBIDI_DEFAULT_LTR : UBIDI_DEFAULT_RTL;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400542 //hb_script_t script = ...
Ben Wagnera25fbef2017-08-30 13:56:19 -0400543
Ben Wagner8d45a382017-11-16 10:08:28 -0500544 SkTArray<ShapedRun> runs;
545{
546 RunIteratorQueue runSegmenter;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400547
Ben Wagner8d45a382017-11-16 10:08:28 -0500548 SkTLazy<BiDiRunIterator> maybeBidi(BiDiRunIterator::Make(utf8, utf8Bytes, defaultLevel));
549 BiDiRunIterator* bidi = maybeBidi.getMaybeNull();
550 if (!bidi) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500551 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400552 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500553 runSegmenter.insert(bidi);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400554
Ben Wagner8d45a382017-11-16 10:08:28 -0500555 hb_unicode_funcs_t* hbUnicode = hb_buffer_get_unicode_funcs(fImpl->fBuffer.get());
556 SkTLazy<ScriptRunIterator> maybeScript(ScriptRunIterator::Make(utf8, utf8Bytes, hbUnicode));
557 ScriptRunIterator* script = maybeScript.getMaybeNull();
558 if (!script) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500559 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400560 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500561 runSegmenter.insert(script);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400562
Ben Wagner8d45a382017-11-16 10:08:28 -0500563 SkTLazy<FontRunIterator> maybeFont(FontRunIterator::Make(utf8, utf8Bytes,
564 fImpl->fTypeface,
565 fImpl->fHarfBuzzFont.get(),
566 std::move(fontMgr)));
567 FontRunIterator* font = maybeFont.getMaybeNull();
568 if (!font) {
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500569 return point;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400570 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500571 runSegmenter.insert(font);
Ben Wagnera25fbef2017-08-30 13:56:19 -0400572
Ben Wagner8d45a382017-11-16 10:08:28 -0500573 icu::BreakIterator& breakIterator = *fImpl->fBreakIterator;
574 {
575 UErrorCode status = U_ZERO_ERROR;
576 UText utf8UText = UTEXT_INITIALIZER;
577 utext_openUTF8(&utf8UText, utf8, utf8Bytes, &status);
578 std::unique_ptr<UText, SkFunctionWrapper<UText*, UText, utext_close>> autoClose(&utf8UText);
579 if (U_FAILURE(status)) {
580 SkDebugf("Could not create utf8UText: %s", u_errorName(status));
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500581 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500582 }
583 breakIterator.setText(&utf8UText, status);
584 //utext_close(&utf8UText);
585 if (U_FAILURE(status)) {
586 SkDebugf("Could not setText on break iterator: %s", u_errorName(status));
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500587 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500588 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400589 }
590
Ben Wagner8d45a382017-11-16 10:08:28 -0500591 const char* utf8Start = nullptr;
592 const char* utf8End = utf8;
593 while (runSegmenter.advanceRuns()) {
594 utf8Start = utf8End;
595 utf8End = runSegmenter.endOfCurrentRun();
596
597 hb_buffer_t* buffer = fImpl->fBuffer.get();
598 SkAutoTCallVProc<hb_buffer_t, hb_buffer_clear_contents> autoClearBuffer(buffer);
599 hb_buffer_set_content_type(buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
600 hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
601
Ben Wagnerc0c99b32018-08-07 10:14:18 -0400602 // Add precontext.
603 hb_buffer_add_utf8(buffer, utf8, utf8Start - utf8, utf8Start - utf8, 0);
604
Ben Wagner8d45a382017-11-16 10:08:28 -0500605 // Populate the hb_buffer directly with utf8 cluster indexes.
606 const char* utf8Current = utf8Start;
607 while (utf8Current < utf8End) {
608 unsigned int cluster = utf8Current - utf8Start;
Hal Canaryf107a2f2018-07-25 16:52:48 -0400609 hb_codepoint_t u = utf8_next(&utf8Current, utf8End);
Ben Wagner8d45a382017-11-16 10:08:28 -0500610 hb_buffer_add(buffer, u, cluster);
611 }
612
Ben Wagnerc0c99b32018-08-07 10:14:18 -0400613 // Add postcontext.
614 hb_buffer_add_utf8(buffer, utf8Current, utf8 + utf8Bytes - utf8Current, 0, 0);
615
Ben Wagner8d45a382017-11-16 10:08:28 -0500616 size_t utf8runLength = utf8End - utf8Start;
617 if (!SkTFitsIn<int>(utf8runLength)) {
618 SkDebugf("Shaping error: utf8 too long");
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500619 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500620 }
621 hb_buffer_set_script(buffer, script->currentScript());
622 hb_direction_t direction = is_LTR(bidi->currentLevel()) ? HB_DIRECTION_LTR:HB_DIRECTION_RTL;
623 hb_buffer_set_direction(buffer, direction);
624 // TODO: language
625 hb_buffer_guess_segment_properties(buffer);
626 // TODO: features
Hal Canary0dfa2082018-10-31 13:02:49 -0400627 if (!font->currentHBFont()) {
628 continue;
629 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500630 hb_shape(font->currentHBFont(), buffer, nullptr, 0);
631 unsigned len = hb_buffer_get_length(buffer);
632 if (len == 0) {
633 continue;
634 }
635
636 if (direction == HB_DIRECTION_RTL) {
637 // Put the clusters back in logical order.
638 // Note that the advances remain ltr.
639 hb_buffer_reverse(buffer);
640 }
641 hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, nullptr);
642 hb_glyph_position_t* pos = hb_buffer_get_glyph_positions(buffer, nullptr);
643
644 if (!SkTFitsIn<int>(len)) {
645 SkDebugf("Shaping error: too many glyphs");
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500646 return point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500647 }
Ben Wagnera25fbef2017-08-30 13:56:19 -0400648
Hal Canary2a1848d2018-11-26 17:23:24 -0500649 SkFont paint(srcPaint);
Ben Wagner8d45a382017-11-16 10:08:28 -0500650 paint.setTypeface(sk_ref_sp(font->currentTypeface()));
651 ShapedRun& run = runs.emplace_back(utf8Start, utf8End, len, paint, bidi->currentLevel(),
652 std::unique_ptr<ShapedGlyph[]>(new ShapedGlyph[len]));
653 int scaleX, scaleY;
654 hb_font_get_scale(font->currentHBFont(), &scaleX, &scaleY);
Mike Reed6d595682018-12-05 17:28:14 -0500655 double textSizeY = run.fFont.getSize() / scaleY;
656 double textSizeX = run.fFont.getSize() / scaleX * run.fFont.getScaleX();
Florin Malita950243d2019-01-11 11:08:35 -0500657 SkVector runAdvance = { 0, 0 };
Ben Wagner8d45a382017-11-16 10:08:28 -0500658 for (unsigned i = 0; i < len; i++) {
659 ShapedGlyph& glyph = run.fGlyphs[i];
660 glyph.fID = info[i].codepoint;
661 glyph.fCluster = info[i].cluster;
662 glyph.fOffset.fX = pos[i].x_offset * textSizeX;
663 glyph.fOffset.fY = pos[i].y_offset * textSizeY;
664 glyph.fAdvance.fX = pos[i].x_advance * textSizeX;
665 glyph.fAdvance.fY = pos[i].y_advance * textSizeY;
666 glyph.fHasVisual = true; //!font->currentTypeface()->glyphBoundsAreZero(glyph.fID);
667 //info->mask safe_to_break;
668 glyph.fMustLineBreakBefore = false;
Florin Malita950243d2019-01-11 11:08:35 -0500669
670 runAdvance += glyph.fAdvance;
Ben Wagner8d45a382017-11-16 10:08:28 -0500671 }
Florin Malita950243d2019-01-11 11:08:35 -0500672 run.fAdvance = runAdvance;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400673
Ben Wagner8d45a382017-11-16 10:08:28 -0500674 int32_t clusterOffset = utf8Start - utf8;
675 uint32_t previousCluster = 0xFFFFFFFF;
676 for (unsigned i = 0; i < len; ++i) {
677 ShapedGlyph& glyph = run.fGlyphs[i];
678 int32_t glyphCluster = glyph.fCluster + clusterOffset;
679 int32_t breakIteratorCurrent = breakIterator.current();
680 while (breakIteratorCurrent != icu::BreakIterator::DONE &&
681 breakIteratorCurrent < glyphCluster)
682 {
683 breakIteratorCurrent = breakIterator.next();
Ben Wagner2868b782017-08-31 14:12:27 -0400684 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500685 glyph.fMayLineBreakBefore = glyph.fCluster != previousCluster &&
686 breakIteratorCurrent == glyphCluster;
687 previousCluster = glyph.fCluster;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400688 }
689 }
Ben Wagner8d45a382017-11-16 10:08:28 -0500690}
691
692// Iterate over the glyphs in logical order to mark line endings.
693{
694 SkScalar widthSoFar = 0;
695 bool previousBreakValid = false; // Set when previousBreak is set to a valid candidate break.
696 bool canAddBreakNow = false; // Disallow line breaks before the first glyph of a run.
697 ShapedRunGlyphIterator previousBreak(runs);
698 ShapedRunGlyphIterator glyphIterator(runs);
699 while (ShapedGlyph* glyph = glyphIterator.current()) {
700 if (canAddBreakNow && glyph->fMayLineBreakBefore) {
701 previousBreakValid = true;
702 previousBreak = glyphIterator;
703 }
704 SkScalar glyphWidth = glyph->fAdvance.fX;
Ben Wagnera900ad52018-08-31 17:48:19 -0400705 // TODO: if the glyph is non-visible it can be added.
Ben Wagner8d45a382017-11-16 10:08:28 -0500706 if (widthSoFar + glyphWidth < width) {
707 widthSoFar += glyphWidth;
708 glyphIterator.next();
709 canAddBreakNow = true;
710 continue;
711 }
712
Ben Wagnera900ad52018-08-31 17:48:19 -0400713 // TODO: for both of these emergency break cases
714 // don't break grapheme clusters and pull in any zero width or non-visible
Ben Wagner8d45a382017-11-16 10:08:28 -0500715 if (widthSoFar == 0) {
716 // Adding just this glyph is too much, just break with this glyph
717 glyphIterator.next();
718 previousBreak = glyphIterator;
719 } else if (!previousBreakValid) {
Ben Wagnera900ad52018-08-31 17:48:19 -0400720 // No break opportunity found yet, just break without this glyph
Ben Wagner8d45a382017-11-16 10:08:28 -0500721 previousBreak = glyphIterator;
722 }
723 glyphIterator = previousBreak;
724 glyph = glyphIterator.current();
725 if (glyph) {
726 glyph->fMustLineBreakBefore = true;
727 }
728 widthSoFar = 0;
729 previousBreakValid = false;
730 canAddBreakNow = false;
731 }
732}
733
734// Reorder the runs and glyphs per line and write them out.
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500735 SkPoint currentPoint = point;
Ben Wagner8d45a382017-11-16 10:08:28 -0500736{
737 ShapedRunGlyphIterator previousBreak(runs);
738 ShapedRunGlyphIterator glyphIterator(runs);
739 SkScalar maxAscent = 0;
740 SkScalar maxDescent = 0;
741 SkScalar maxLeading = 0;
742 int previousRunIndex = -1;
Florin Malita950243d2019-01-11 11:08:35 -0500743 size_t lineIndex = 0;
Ben Wagner8d45a382017-11-16 10:08:28 -0500744 while (glyphIterator.current()) {
745 int runIndex = glyphIterator.fRunIndex;
746 int glyphIndex = glyphIterator.fGlyphIndex;
747 ShapedGlyph* nextGlyph = glyphIterator.next();
748
749 if (previousRunIndex != runIndex) {
Mike Reedb5784ac2018-11-12 09:35:15 -0500750 SkFontMetrics metrics;
Mike Reed6d595682018-12-05 17:28:14 -0500751 runs[runIndex].fFont.getMetrics(&metrics);
Ben Wagner8d45a382017-11-16 10:08:28 -0500752 maxAscent = SkTMin(maxAscent, metrics.fAscent);
753 maxDescent = SkTMax(maxDescent, metrics.fDescent);
754 maxLeading = SkTMax(maxLeading, metrics.fLeading);
755 previousRunIndex = runIndex;
756 }
757
758 // Nothing can be written until the baseline is known.
759 if (!(nextGlyph == nullptr || nextGlyph->fMustLineBreakBefore)) {
760 continue;
761 }
762
763 currentPoint.fY -= maxAscent;
764
765 int numRuns = runIndex - previousBreak.fRunIndex + 1;
766 SkAutoSTMalloc<4, UBiDiLevel> runLevels(numRuns);
767 for (int i = 0; i < numRuns; ++i) {
768 runLevels[i] = runs[previousBreak.fRunIndex + i].fLevel;
769 }
770 SkAutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
771 ubidi_reorderVisual(runLevels, numRuns, logicalFromVisual);
772
773 for (int i = 0; i < numRuns; ++i) {
774 int logicalIndex = previousBreak.fRunIndex + logicalFromVisual[i];
775
776 int startGlyphIndex = (logicalIndex == previousBreak.fRunIndex)
777 ? previousBreak.fGlyphIndex
778 : 0;
779 int endGlyphIndex = (logicalIndex == runIndex)
780 ? glyphIndex + 1
781 : runs[logicalIndex].fNumGlyphs;
Florin Malita950243d2019-01-11 11:08:35 -0500782
783 const auto& run = runs[logicalIndex];
784 const RunHandler::RunInfo info = {
785 lineIndex,
786 run.fAdvance,
787 maxAscent,
788 maxDescent,
789 maxLeading,
790 };
791 append(handler, info, run, startGlyphIndex, endGlyphIndex, &currentPoint);
Ben Wagner8d45a382017-11-16 10:08:28 -0500792 }
793
794 currentPoint.fY += maxDescent + maxLeading;
795 currentPoint.fX = point.fX;
796 maxAscent = 0;
797 maxDescent = 0;
798 maxLeading = 0;
799 previousRunIndex = -1;
Florin Malita950243d2019-01-11 11:08:35 -0500800 ++lineIndex;
Ben Wagner8d45a382017-11-16 10:08:28 -0500801 previousBreak = glyphIterator;
802 }
803}
804
Ben Wagner5d4dd8b2018-01-25 14:37:17 -0500805 return currentPoint;
Ben Wagnera25fbef2017-08-30 13:56:19 -0400806}