Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Namespaces | Macros | Functions
SkShaper_harfbuzz.cpp File Reference
#include "modules/skshaper/include/SkShaper_harfbuzz.h"
#include "include/core/SkData.h"
#include "include/core/SkFont.h"
#include "include/core/SkFontArguments.h"
#include "include/core/SkFontMetrics.h"
#include "include/core/SkFontMgr.h"
#include "include/core/SkFontTypes.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSpan.h"
#include "include/core/SkStream.h"
#include "include/core/SkString.h"
#include "include/core/SkTypeface.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkDebug.h"
#include "include/private/base/SkMalloc.h"
#include "include/private/base/SkMutex.h"
#include "include/private/base/SkTArray.h"
#include "include/private/base/SkTemplates.h"
#include "include/private/base/SkTo.h"
#include "include/private/base/SkTypeTraits.h"
#include "modules/skshaper/include/SkShaper.h"
#include "modules/skunicode/include/SkUnicode.h"
#include "src/base/SkTDPQueue.h"
#include "src/base/SkUTF.h"
#include "src/core/SkLRUCache.h"
#include "modules/skshaper/include/SkShaper_skunicode.h"
#include <hb-ot.h>
#include <hb.h>
#include <cstdint>
#include <cstring>
#include <memory>
#include <type_traits>
#include <utility>

Go to the source code of this file.

Namespaces

namespace  SkShapers
 
namespace  SkShapers::HB
 

Macros

#define HB_FEATURE_GLOBAL_START   0
 
#define HB_FEATURE_GLOBAL_END   ((unsigned int) -1)
 
#define SK_HB_VERSION_CHECK(x, y, z)
 

Functions

static sk_sp< SkUnicodeget_unicode ()
 
SKSHAPER_API std::unique_ptr< SkShaperSkShapers::HB::ShaperDrivenWrapper (sk_sp< SkUnicode > unicode, sk_sp< SkFontMgr > fallback)
 
SKSHAPER_API std::unique_ptr< SkShaperSkShapers::HB::ShapeThenWrap (sk_sp< SkUnicode > unicode, sk_sp< SkFontMgr > fallback)
 
SKSHAPER_API std::unique_ptr< SkShaperSkShapers::HB::ShapeDontWrapOrReorder (sk_sp< SkUnicode > unicode, sk_sp< SkFontMgr > fallback)
 
SKSHAPER_API std::unique_ptr< SkShaper::ScriptRunIteratorSkShapers::HB::ScriptRunIterator (const char *utf8, size_t utf8Bytes)
 
SKSHAPER_API std::unique_ptr< SkShaper::ScriptRunIteratorSkShapers::HB::ScriptRunIterator (const char *utf8, size_t utf8Bytes, SkFourByteTag script)
 
SKSHAPER_API void SkShapers::HB::PurgeCaches ()
 

Macro Definition Documentation

◆ HB_FEATURE_GLOBAL_END

#define HB_FEATURE_GLOBAL_END   ((unsigned int) -1)

Definition at line 60 of file SkShaper_harfbuzz.cpp.

◆ HB_FEATURE_GLOBAL_START

#define HB_FEATURE_GLOBAL_START   0

Definition at line 57 of file SkShaper_harfbuzz.cpp.

◆ SK_HB_VERSION_CHECK

#define SK_HB_VERSION_CHECK (   x,
  y,
 
)
Value:
(HB_VERSION_MAJOR > (x)) || \
(HB_VERSION_MAJOR == (x) && HB_VERSION_MINOR > (y)) || \
(HB_VERSION_MAJOR == (x) && HB_VERSION_MINOR == (y) && HB_VERSION_MICRO >= (z))
double y
double x

Definition at line 206 of file SkShaper_harfbuzz.cpp.

210 {
211 static hb_font_funcs_t* const funcs = []{
212 // HarfBuzz will use the default (parent) implementation if they aren't set.
213 hb_font_funcs_t* const funcs = hb_font_funcs_create();
214 hb_font_funcs_set_variation_glyph_func(funcs, skhb_glyph, nullptr, nullptr);
215 hb_font_funcs_set_nominal_glyph_func(funcs, skhb_nominal_glyph, nullptr, nullptr);
216#if SK_HB_VERSION_CHECK(2, 0, 0)
217 hb_font_funcs_set_nominal_glyphs_func(funcs, skhb_nominal_glyphs, nullptr, nullptr);
218#else
219 sk_ignore_unused_variable(skhb_nominal_glyphs);
220#endif
221 hb_font_funcs_set_glyph_h_advance_func(funcs, skhb_glyph_h_advance, nullptr, nullptr);
222#if SK_HB_VERSION_CHECK(1, 8, 6)
223 hb_font_funcs_set_glyph_h_advances_func(funcs, skhb_glyph_h_advances, nullptr, nullptr);
224#else
225 sk_ignore_unused_variable(skhb_glyph_h_advances);
226#endif
227 hb_font_funcs_set_glyph_extents_func(funcs, skhb_glyph_extents, nullptr, nullptr);
228 hb_font_funcs_make_immutable(funcs);
229 return funcs;
230 }();
231 SkASSERT(funcs);
232 return funcs;
233}
234
235hb_blob_t* skhb_get_table(hb_face_t* face, hb_tag_t tag, void* user_data) {
236 SkTypeface& typeface = *reinterpret_cast<SkTypeface*>(user_data);
237
238 auto data = typeface.copyTableData(tag);
239 if (!data) {
240 return nullptr;
241 }
242 SkData* rawData = data.release();
243 return hb_blob_create(reinterpret_cast<char*>(rawData->writable_data()), rawData->size(),
244 HB_MEMORY_MODE_READONLY, rawData, [](void* ctx) {
245 SkSafeUnref(((SkData*)ctx));
246 });
247}
248
249HBBlob stream_to_blob(std::unique_ptr<SkStreamAsset> asset) {
250 size_t size = asset->getLength();
251 HBBlob blob;
252 if (const void* base = asset->getMemoryBase()) {
253 blob.reset(hb_blob_create((const char*)base, SkToUInt(size),
254 HB_MEMORY_MODE_READONLY, asset.release(),
255 [](void* p) { delete (SkStreamAsset*)p; }));
256 } else {
257 // SkDebugf("Extra SkStreamAsset copy\n");
258 void* ptr = size ? sk_malloc_throw(size) : nullptr;
259 asset->read(ptr, size);
260 blob.reset(hb_blob_create((char*)ptr, SkToUInt(size),
261 HB_MEMORY_MODE_READONLY, ptr, sk_free));
262 }
263 SkASSERT(blob);
264 hb_blob_make_immutable(blob.get());
265 return blob;
266}
267
268SkDEBUGCODE(static hb_user_data_key_t gDataIdKey;)
269
270HBFace create_hb_face(const SkTypeface& typeface) {
271 int index = 0;
272 std::unique_ptr<SkStreamAsset> typefaceAsset = typeface.openExistingStream(&index);
273 HBFace face;
274 if (typefaceAsset && typefaceAsset->getMemoryBase()) {
275 HBBlob blob(stream_to_blob(std::move(typefaceAsset)));
276 // hb_face_create always succeeds. Check that the format is minimally recognized first.
277 // hb_face_create_for_tables may still create a working hb_face.
278 // See https://github.com/harfbuzz/harfbuzz/issues/248 .
279 unsigned int num_hb_faces = hb_face_count(blob.get());
280 if (0 < num_hb_faces && (unsigned)index < num_hb_faces) {
281 face.reset(hb_face_create(blob.get(), (unsigned)index));
282 // Check the number of glyphs as a basic sanitization step.
283 if (face && hb_face_get_glyph_count(face.get()) == 0) {
284 face.reset();
285 }
286 }
287 }
288 if (!face) {
289 face.reset(hb_face_create_for_tables(
290 skhb_get_table,
291 const_cast<SkTypeface*>(SkRef(&typeface)),
292 [](void* user_data){ SkSafeUnref(reinterpret_cast<SkTypeface*>(user_data)); }));
293 hb_face_set_index(face.get(), (unsigned)index);
294 }
295 SkASSERT(face);
296 if (!face) {
297 return nullptr;
298 }
299 hb_face_set_upem(face.get(), typeface.getUnitsPerEm());
300
302 hb_face_set_user_data(face.get(), &gDataIdKey, const_cast<SkTypeface*>(&typeface),
303 nullptr, false);
304 )
305
306 return face;
307}
308
309HBFont create_typeface_hb_font(const SkTypeface& typeface) {
310 HBFace face(create_hb_face(typeface));
311 if (!face) {
312 return nullptr;
313 }
314
315 HBFont otFont(hb_font_create(face.get()));
316 SkASSERT(otFont);
317 if (!otFont) {
318 return nullptr;
319 }
320 hb_ot_font_set_funcs(otFont.get());
321 int axis_count = typeface.getVariationDesignPosition(nullptr, 0);
322 if (axis_count > 0) {
324 if (typeface.getVariationDesignPosition(axis_values, axis_count) == axis_count) {
325 hb_font_set_variations(otFont.get(),
326 reinterpret_cast<hb_variation_t*>(axis_values.get()),
327 axis_count);
328 }
329 }
330
331 return otFont;
332}
333
334HBFont create_sub_hb_font(const SkFont& font, const HBFont& typefaceFont) {
336 hb_face_t* face = hb_font_get_face(typefaceFont.get());
337 void* dataId = hb_face_get_user_data(face, &gDataIdKey);
338 SkASSERT(dataId == font.getTypeface());
339 )
340
341 // Creating a sub font means that non-available functions
342 // are found from the parent.
343 HBFont skFont(hb_font_create_sub_font(typefaceFont.get()));
344 hb_font_set_funcs(skFont.get(), skhb_get_font_funcs(),
345 reinterpret_cast<void *>(new SkFont(font)),
346 [](void* user_data){ delete reinterpret_cast<SkFont*>(user_data); });
347 int scale = skhb_position(font.getSize());
348 hb_font_set_scale(skFont.get(), scale, scale);
349
350 return skFont;
351}
352
353/** Replaces invalid utf-8 sequences with REPLACEMENT CHARACTER U+FFFD. */
354static inline SkUnichar utf8_next(const char** ptr, const char* end) {
355 SkUnichar val = SkUTF::NextUTF8(ptr, end);
356 return val < 0 ? 0xFFFD : val;
357}
358
359class SkUnicodeHbScriptRunIterator final: public SkShaper::ScriptRunIterator {
360public:
361 SkUnicodeHbScriptRunIterator(const char* utf8,
362 size_t utf8Bytes,
363 hb_script_t defaultScript)
364 : fCurrent(utf8)
365 , fBegin(utf8)
366 , fEnd(fCurrent + utf8Bytes)
367 , fCurrentScript(defaultScript) {}
368 hb_script_t hb_script_for_unichar(SkUnichar u) {
369 return hb_unicode_script(hb_unicode_funcs_get_default(), u);
370 }
371 void consume() override {
372 SkASSERT(fCurrent < fEnd);
373 SkUnichar u = utf8_next(&fCurrent, fEnd);
374 fCurrentScript = hb_script_for_unichar(u);
375 while (fCurrent < fEnd) {
376 const char* prev = fCurrent;
377 u = utf8_next(&fCurrent, fEnd);
378 const hb_script_t script = hb_script_for_unichar(u);
379 if (script != fCurrentScript) {
380 if (fCurrentScript == HB_SCRIPT_INHERITED || fCurrentScript == HB_SCRIPT_COMMON) {
381 fCurrentScript = script;
382 } else if (script == HB_SCRIPT_INHERITED || script == HB_SCRIPT_COMMON) {
383 continue;
384 } else {
385 fCurrent = prev;
386 break;
387 }
388 }
389 }
390 if (fCurrentScript == HB_SCRIPT_INHERITED) {
391 fCurrentScript = HB_SCRIPT_COMMON;
392 }
393 }
394 size_t endOfCurrentRun() const override {
395 return fCurrent - fBegin;
396 }
397 bool atEnd() const override {
398 return fCurrent == fEnd;
399 }
400
401 SkFourByteTag currentScript() const override {
402 return SkSetFourByteTag(HB_UNTAG(fCurrentScript));
403 }
404private:
405 char const * fCurrent;
406 char const * const fBegin;
407 char const * const fEnd;
408 hb_script_t fCurrentScript;
409};
410
411class RunIteratorQueue {
412public:
413 void insert(SkShaper::RunIterator* runIterator, int priority) {
414 fEntries.insert({runIterator, priority});
415 }
416
417 bool advanceRuns() {
418 const SkShaper::RunIterator* leastRun = fEntries.peek().runIterator;
419 if (leastRun->atEnd()) {
420 SkASSERT(this->allRunsAreAtEnd());
421 return false;
422 }
423 const size_t leastEnd = leastRun->endOfCurrentRun();
424 SkShaper::RunIterator* currentRun = nullptr;
425 SkDEBUGCODE(size_t previousEndOfCurrentRun);
426 while ((currentRun = fEntries.peek().runIterator)->endOfCurrentRun() <= leastEnd) {
427 int priority = fEntries.peek().priority;
428 fEntries.pop();
429 SkDEBUGCODE(previousEndOfCurrentRun = currentRun->endOfCurrentRun());
430 currentRun->consume();
431 SkASSERT(previousEndOfCurrentRun < currentRun->endOfCurrentRun());
432 fEntries.insert({currentRun, priority});
433 }
434 return true;
435 }
436
437 size_t endOfCurrentRun() const {
438 return fEntries.peek().runIterator->endOfCurrentRun();
439 }
440
441private:
442 bool allRunsAreAtEnd() const {
443 for (int i = 0; i < fEntries.count(); ++i) {
444 if (!fEntries.at(i).runIterator->atEnd()) {
445 return false;
446 }
447 }
448 return true;
449 }
450
451 struct Entry {
452 SkShaper::RunIterator* runIterator;
453 int priority;
454 };
455 static bool CompareEntry(Entry const& a, Entry const& b) {
456 size_t aEnd = a.runIterator->endOfCurrentRun();
457 size_t bEnd = b.runIterator->endOfCurrentRun();
458 return aEnd < bEnd || (aEnd == bEnd && a.priority < b.priority);
459 }
461};
462
463struct ShapedGlyph {
464 SkGlyphID fID;
465 uint32_t fCluster;
466 SkPoint fOffset;
467 SkVector fAdvance;
468 bool fMayLineBreakBefore;
469 bool fMustLineBreakBefore;
470 bool fHasVisual;
471 bool fGraphemeBreakBefore;
472 bool fUnsafeToBreak;
473};
474struct ShapedRun {
475 ShapedRun(SkShaper::RunHandler::Range utf8Range, const SkFont& font, SkBidiIterator::Level level,
476 std::unique_ptr<ShapedGlyph[]> glyphs, size_t numGlyphs, SkVector advance = {0, 0})
477 : fUtf8Range(utf8Range), fFont(font), fLevel(level)
478 , fGlyphs(std::move(glyphs)), fNumGlyphs(numGlyphs), fAdvance(advance)
479 {}
480
482 SkFont fFont;
484 std::unique_ptr<ShapedGlyph[]> fGlyphs;
485 size_t fNumGlyphs;
486 SkVector fAdvance;
487
488 static_assert(::sk_is_trivially_relocatable<decltype(fUtf8Range)>::value);
489 static_assert(::sk_is_trivially_relocatable<decltype(fFont)>::value);
490 static_assert(::sk_is_trivially_relocatable<decltype(fLevel)>::value);
491 static_assert(::sk_is_trivially_relocatable<decltype(fGlyphs)>::value);
492 static_assert(::sk_is_trivially_relocatable<decltype(fAdvance)>::value);
493
494 using sk_is_trivially_relocatable = std::true_type;
495};
496struct ShapedLine {
498 SkVector fAdvance = { 0, 0 };
499};
500
501constexpr bool is_LTR(SkBidiIterator::Level level) {
502 return (level & 1) == 0;
503}
504
505void append(SkShaper::RunHandler* handler, const SkShaper::RunHandler::RunInfo& runInfo,
506 const ShapedRun& run, size_t startGlyphIndex, size_t endGlyphIndex) {
507 SkASSERT(startGlyphIndex <= endGlyphIndex);
508 const size_t glyphLen = endGlyphIndex - startGlyphIndex;
509
510 const auto buffer = handler->runBuffer(runInfo);
511 SkASSERT(buffer.glyphs);
512 SkASSERT(buffer.positions);
513
514 SkVector advance = {0,0};
515 for (size_t i = 0; i < glyphLen; i++) {
516 // Glyphs are in logical order, but output ltr since PDF readers seem to expect that.
517 const ShapedGlyph& glyph = run.fGlyphs[is_LTR(run.fLevel) ? startGlyphIndex + i
518 : endGlyphIndex - 1 - i];
519 buffer.glyphs[i] = glyph.fID;
520 if (buffer.offsets) {
521 buffer.positions[i] = advance + buffer.point;
522 buffer.offsets[i] = glyph.fOffset;
523 } else {
524 buffer.positions[i] = advance + buffer.point + glyph.fOffset;
525 }
526 if (buffer.clusters) {
527 buffer.clusters[i] = glyph.fCluster;
528 }
529 advance += glyph.fAdvance;
530 }
531 handler->commitRunBuffer(runInfo);
532}
533
534void emit(SkUnicode* unicode, const ShapedLine& line, SkShaper::RunHandler* handler) {
535 // Reorder the runs and glyphs per line and write them out.
536 handler->beginLine();
537
538 int numRuns = line.runs.size();
540 for (int i = 0; i < numRuns; ++i) {
541 runLevels[i] = line.runs[i].fLevel;
542 }
543 AutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
544 unicode->reorderVisual(runLevels, numRuns, logicalFromVisual);
545
546 for (int i = 0; i < numRuns; ++i) {
547 int logicalIndex = logicalFromVisual[i];
548
549 const auto& run = line.runs[logicalIndex];
551 run.fFont,
552 run.fLevel,
553 run.fAdvance,
554 run.fNumGlyphs,
555 run.fUtf8Range
556 };
557 handler->runInfo(info);
558 }
559 handler->commitRunInfo();
560 for (int i = 0; i < numRuns; ++i) {
561 int logicalIndex = logicalFromVisual[i];
562
563 const auto& run = line.runs[logicalIndex];
565 run.fFont,
566 run.fLevel,
567 run.fAdvance,
568 run.fNumGlyphs,
569 run.fUtf8Range
570 };
571 append(handler, info, run, 0, run.fNumGlyphs);
572 }
573
574 handler->commitLine();
575}
576
577struct ShapedRunGlyphIterator {
578 ShapedRunGlyphIterator(const TArray<ShapedRun>& origRuns)
579 : fRuns(&origRuns), fRunIndex(0), fGlyphIndex(0)
580 { }
581
582 ShapedRunGlyphIterator(const ShapedRunGlyphIterator& that) = default;
583 ShapedRunGlyphIterator& operator=(const ShapedRunGlyphIterator& that) = default;
584 bool operator==(const ShapedRunGlyphIterator& that) const {
585 return fRuns == that.fRuns &&
586 fRunIndex == that.fRunIndex &&
587 fGlyphIndex == that.fGlyphIndex;
588 }
589 bool operator!=(const ShapedRunGlyphIterator& that) const {
590 return fRuns != that.fRuns ||
591 fRunIndex != that.fRunIndex ||
592 fGlyphIndex != that.fGlyphIndex;
593 }
594
595 ShapedGlyph* next() {
596 const TArray<ShapedRun>& runs = *fRuns;
597 SkASSERT(fRunIndex < runs.size());
598 SkASSERT(fGlyphIndex < runs[fRunIndex].fNumGlyphs);
599
600 ++fGlyphIndex;
601 if (fGlyphIndex == runs[fRunIndex].fNumGlyphs) {
602 fGlyphIndex = 0;
603 ++fRunIndex;
604 if (fRunIndex >= runs.size()) {
605 return nullptr;
606 }
607 }
608 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
609 }
610
611 ShapedGlyph* current() {
612 const TArray<ShapedRun>& runs = *fRuns;
613 if (fRunIndex >= runs.size()) {
614 return nullptr;
615 }
616 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
617 }
618
619 const TArray<ShapedRun>* fRuns;
620 int fRunIndex;
621 size_t fGlyphIndex;
622};
623
624class ShaperHarfBuzz : public SkShaper {
625public:
626 ShaperHarfBuzz(sk_sp<SkUnicode>,
627 HBBuffer,
629
630protected:
631 sk_sp<SkUnicode> fUnicode;
632
633 ShapedRun shape(const char* utf8, size_t utf8Bytes,
634 const char* utf8Start,
635 const char* utf8End,
636 const BiDiRunIterator&,
637 const LanguageRunIterator&,
638 const ScriptRunIterator&,
639 const FontRunIterator&,
640 const Feature*, size_t featuresSize) const;
641private:
642 const sk_sp<SkFontMgr> fFontMgr; // for fallback
643 HBBuffer fBuffer;
644 hb_language_t fUndefinedLanguage;
645
646#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
647 void shape(const char* utf8, size_t utf8Bytes,
648 const SkFont&,
649 bool leftToRight,
651 RunHandler*) const override;
652
653 void shape(const char* utf8Text, size_t textBytes,
654 FontRunIterator&,
655 BiDiRunIterator&,
656 ScriptRunIterator&,
657 LanguageRunIterator&,
659 RunHandler*) const override;
660#endif
661
662 void shape(const char* utf8Text, size_t textBytes,
663 FontRunIterator&,
664 BiDiRunIterator&,
665 ScriptRunIterator&,
666 LanguageRunIterator&,
667 const Feature*, size_t featuresSize,
669 RunHandler*) const override;
670
671 virtual void wrap(char const * const utf8, size_t utf8Bytes,
672 const BiDiRunIterator&,
673 const LanguageRunIterator&,
674 const ScriptRunIterator&,
675 const FontRunIterator&,
676 RunIteratorQueue& runSegmenter,
677 const Feature*, size_t featuresSize,
679 RunHandler*) const = 0;
680};
681
682class ShaperDrivenWrapper : public ShaperHarfBuzz {
683public:
684 using ShaperHarfBuzz::ShaperHarfBuzz;
685private:
686 void wrap(char const * const utf8, size_t utf8Bytes,
687 const BiDiRunIterator&,
688 const LanguageRunIterator&,
689 const ScriptRunIterator&,
690 const FontRunIterator&,
691 RunIteratorQueue& runSegmenter,
692 const Feature*, size_t featuresSize,
694 RunHandler*) const override;
695};
696
697class ShapeThenWrap : public ShaperHarfBuzz {
698public:
699 using ShaperHarfBuzz::ShaperHarfBuzz;
700private:
701 void wrap(char const * const utf8, size_t utf8Bytes,
702 const BiDiRunIterator&,
703 const LanguageRunIterator&,
704 const ScriptRunIterator&,
705 const FontRunIterator&,
706 RunIteratorQueue& runSegmenter,
707 const Feature*, size_t featuresSize,
709 RunHandler*) const override;
710};
711
712class ShapeDontWrapOrReorder : public ShaperHarfBuzz {
713public:
714 using ShaperHarfBuzz::ShaperHarfBuzz;
715private:
716 void wrap(char const * const utf8, size_t utf8Bytes,
717 const BiDiRunIterator&,
718 const LanguageRunIterator&,
719 const ScriptRunIterator&,
720 const FontRunIterator&,
721 RunIteratorQueue& runSegmenter,
722 const Feature*, size_t featuresSize,
724 RunHandler*) const override;
725};
726
727ShaperHarfBuzz::ShaperHarfBuzz(sk_sp<SkUnicode> unicode,
728 HBBuffer buffer,
729 sk_sp<SkFontMgr> fallback)
730 : fUnicode(unicode)
731 , fFontMgr(fallback ? std::move(fallback) : SkFontMgr::RefEmpty())
732 , fBuffer(std::move(buffer))
733 , fUndefinedLanguage(hb_language_from_string("und", -1)) {
734#if defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
735 SkASSERT(fUnicode);
736#endif
737}
738
739#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
740void ShaperHarfBuzz::shape(const char* utf8,
741 size_t utf8Bytes,
742 const SkFont& srcFont,
743 bool leftToRight,
745 RunHandler* handler) const {
747 std::unique_ptr<BiDiRunIterator> bidi(
748 SkShapers::unicode::BidiRunIterator(fUnicode, utf8, utf8Bytes, defaultLevel));
749
750 if (!bidi) {
751 return;
752 }
753
754 std::unique_ptr<LanguageRunIterator> language(MakeStdLanguageRunIterator(utf8, utf8Bytes));
755 if (!language) {
756 return;
757 }
758
759 std::unique_ptr<ScriptRunIterator> script(SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes));
760 if (!script) {
761 return;
762 }
763
764 std::unique_ptr<FontRunIterator> font(
765 MakeFontMgrRunIterator(utf8, utf8Bytes, srcFont, fFontMgr));
766 if (!font) {
767 return;
768 }
769
770 this->shape(utf8, utf8Bytes, *font, *bidi, *script, *language, width, handler);
771}
772
773void ShaperHarfBuzz::shape(const char* utf8,
774 size_t utf8Bytes,
775 FontRunIterator& font,
776 BiDiRunIterator& bidi,
777 ScriptRunIterator& script,
778 LanguageRunIterator& language,
780 RunHandler* handler) const {
781 this->shape(utf8, utf8Bytes, font, bidi, script, language, nullptr, 0, width, handler);
782}
783#endif // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
784
785void ShaperHarfBuzz::shape(const char* utf8,
786 size_t utf8Bytes,
787 FontRunIterator& font,
788 BiDiRunIterator& bidi,
789 ScriptRunIterator& script,
790 LanguageRunIterator& language,
791 const Feature* features,
792 size_t featuresSize,
794 RunHandler* handler) const {
795 SkASSERT(handler);
796 RunIteratorQueue runSegmenter;
797 runSegmenter.insert(&font, 3); // The font iterator is always run last in case of tie.
798 runSegmenter.insert(&bidi, 2);
799 runSegmenter.insert(&script, 1);
800 runSegmenter.insert(&language, 0);
801
802 this->wrap(utf8, utf8Bytes, bidi, language, script, font, runSegmenter,
803 features, featuresSize, width, handler);
804}
805
806void ShaperDrivenWrapper::wrap(char const * const utf8, size_t utf8Bytes,
807 const BiDiRunIterator& bidi,
808 const LanguageRunIterator& language,
809 const ScriptRunIterator& script,
810 const FontRunIterator& font,
811 RunIteratorQueue& runSegmenter,
812 const Feature* features, size_t featuresSize,
814 RunHandler* handler) const
815{
816 ShapedLine line;
817
818 const char* utf8Start = nullptr;
819 const char* utf8End = utf8;
820 SkUnicodeBreak lineBreakIterator;
821 SkString currentLanguage;
822 while (runSegmenter.advanceRuns()) { // For each item
823 utf8Start = utf8End;
824 utf8End = utf8 + runSegmenter.endOfCurrentRun();
825
826 ShapedRun model(RunHandler::Range(), SkFont(), 0, nullptr, 0);
827 bool modelNeedsRegenerated = true;
828 int modelGlyphOffset = 0;
829
830 struct TextProps {
831 int glyphLen = 0;
832 SkVector advance = {0, 0};
833 };
834 // map from character position to [safe to break, glyph position, advance]
835 std::unique_ptr<TextProps[]> modelText;
836 int modelTextOffset = 0;
837 SkVector modelAdvanceOffset = {0, 0};
838
839 while (utf8Start < utf8End) { // While there are still code points left in this item
840 size_t utf8runLength = utf8End - utf8Start;
841 if (modelNeedsRegenerated) {
842 model = shape(utf8, utf8Bytes,
843 utf8Start, utf8End,
844 bidi, language, script, font,
845 features, featuresSize);
846 modelGlyphOffset = 0;
847
848 SkVector advance = {0, 0};
849 modelText = std::make_unique<TextProps[]>(utf8runLength + 1);
850 size_t modelStartCluster = utf8Start - utf8;
851 size_t previousCluster = 0;
852 for (size_t i = 0; i < model.fNumGlyphs; ++i) {
853 SkASSERT(modelStartCluster <= model.fGlyphs[i].fCluster);
854 SkASSERT( model.fGlyphs[i].fCluster < (size_t)(utf8End - utf8));
855 if (!model.fGlyphs[i].fUnsafeToBreak) {
856 // Store up to the first glyph in the cluster.
857 size_t currentCluster = model.fGlyphs[i].fCluster - modelStartCluster;
858 if (previousCluster != currentCluster) {
859 previousCluster = currentCluster;
860 modelText[currentCluster].glyphLen = i;
861 modelText[currentCluster].advance = advance;
862 }
863 }
864 advance += model.fGlyphs[i].fAdvance;
865 }
866 // Assume it is always safe to break after the end of an item
867 modelText[utf8runLength].glyphLen = model.fNumGlyphs;
868 modelText[utf8runLength].advance = model.fAdvance;
869 modelTextOffset = 0;
870 modelAdvanceOffset = {0, 0};
871 modelNeedsRegenerated = false;
872 }
873
874 // TODO: break iterator per item, but just reset position if needed?
875 // Maybe break iterator with model?
876 if (!lineBreakIterator || !currentLanguage.equals(language.currentLanguage())) {
877 currentLanguage = language.currentLanguage();
878 lineBreakIterator = fUnicode->makeBreakIterator(currentLanguage.c_str(),
880 if (!lineBreakIterator) {
881 return;
882 }
883 }
884 if (!lineBreakIterator->setText(utf8Start, utf8runLength)) {
885 return;
886 }
887 SkBreakIterator& breakIterator = *lineBreakIterator;
888
889 ShapedRun best(RunHandler::Range(), SkFont(), 0, nullptr, 0,
891 bool bestIsInvalid = true;
892 bool bestUsesModelForGlyphs = false;
893 SkScalar widthLeft = width - line.fAdvance.fX;
894
895 for (int32_t breakIteratorCurrent = breakIterator.next();
896 !breakIterator.isDone();
897 breakIteratorCurrent = breakIterator.next())
898 {
899 // TODO: if past a safe to break, future safe to break will be at least as long
900
901 // TODO: adjust breakIteratorCurrent by ignorable whitespace
902 bool candidateUsesModelForGlyphs = false;
903 ShapedRun candidate = [&](const TextProps& props){
904 if (props.glyphLen) {
905 candidateUsesModelForGlyphs = true;
906 return ShapedRun(RunHandler::Range(utf8Start - utf8, breakIteratorCurrent),
907 font.currentFont(), bidi.currentLevel(),
908 std::unique_ptr<ShapedGlyph[]>(),
909 props.glyphLen - modelGlyphOffset,
910 props.advance - modelAdvanceOffset);
911 } else {
912 return shape(utf8, utf8Bytes,
913 utf8Start, utf8Start + breakIteratorCurrent,
914 bidi, language, script, font,
915 features, featuresSize);
916 }
917 }(modelText[breakIteratorCurrent + modelTextOffset]);
918 auto score = [widthLeft](const ShapedRun& run) -> SkScalar {
919 if (run.fAdvance.fX < widthLeft) {
920 return run.fUtf8Range.size();
921 } else {
922 return widthLeft - run.fAdvance.fX;
923 }
924 };
925 if (bestIsInvalid || score(best) < score(candidate)) {
926 best = std::move(candidate);
927 bestIsInvalid = false;
928 bestUsesModelForGlyphs = candidateUsesModelForGlyphs;
929 }
930 }
931
932 // If nothing fit (best score is negative) and the line is not empty
933 if (width < line.fAdvance.fX + best.fAdvance.fX && !line.runs.empty()) {
934 emit(fUnicode.get(), line, handler);
935 line.runs.clear();
936 line.fAdvance = {0, 0};
937 } else {
938 if (bestUsesModelForGlyphs) {
939 best.fGlyphs = std::make_unique<ShapedGlyph[]>(best.fNumGlyphs);
940 memcpy(best.fGlyphs.get(), model.fGlyphs.get() + modelGlyphOffset,
941 best.fNumGlyphs * sizeof(ShapedGlyph));
942 modelGlyphOffset += best.fNumGlyphs;
943 modelTextOffset += best.fUtf8Range.size();
944 modelAdvanceOffset += best.fAdvance;
945 } else {
946 modelNeedsRegenerated = true;
947 }
948 utf8Start += best.fUtf8Range.size();
949 line.fAdvance += best.fAdvance;
950 line.runs.emplace_back(std::move(best));
951
952 // If item broken, emit line (prevent remainder from accidentally fitting)
953 if (utf8Start != utf8End) {
954 emit(fUnicode.get(), line, handler);
955 line.runs.clear();
956 line.fAdvance = {0, 0};
957 }
958 }
959 }
960 }
961 emit(fUnicode.get(), line, handler);
962}
963
964void ShapeThenWrap::wrap(char const * const utf8, size_t utf8Bytes,
965 const BiDiRunIterator& bidi,
966 const LanguageRunIterator& language,
967 const ScriptRunIterator& script,
968 const FontRunIterator& font,
969 RunIteratorQueue& runSegmenter,
970 const Feature* features, size_t featuresSize,
972 RunHandler* handler) const
973{
975{
976 SkString currentLanguage;
977 SkUnicodeBreak lineBreakIterator;
978 SkUnicodeBreak graphemeBreakIterator;
979 bool needIteratorInit = true;
980 const char* utf8Start = nullptr;
981 const char* utf8End = utf8;
982 while (runSegmenter.advanceRuns()) {
983 utf8Start = utf8End;
984 utf8End = utf8 + runSegmenter.endOfCurrentRun();
985
986 runs.emplace_back(shape(utf8, utf8Bytes,
987 utf8Start, utf8End,
988 bidi, language, script, font,
989 features, featuresSize));
990 ShapedRun& run = runs.back();
991
992 if (needIteratorInit || !currentLanguage.equals(language.currentLanguage())) {
993 currentLanguage = language.currentLanguage();
994 lineBreakIterator = fUnicode->makeBreakIterator(currentLanguage.c_str(),
996 if (!lineBreakIterator) {
997 return;
998 }
999 graphemeBreakIterator = fUnicode->makeBreakIterator(currentLanguage.c_str(),
1001 if (!graphemeBreakIterator) {
1002 return;
1003 }
1004 needIteratorInit = false;
1005 }
1006 size_t utf8runLength = utf8End - utf8Start;
1007 if (!lineBreakIterator->setText(utf8Start, utf8runLength)) {
1008 return;
1009 }
1010 if (!graphemeBreakIterator->setText(utf8Start, utf8runLength)) {
1011 return;
1012 }
1013
1014 uint32_t previousCluster = 0xFFFFFFFF;
1015 for (size_t i = 0; i < run.fNumGlyphs; ++i) {
1016 ShapedGlyph& glyph = run.fGlyphs[i];
1017 int32_t glyphCluster = glyph.fCluster;
1018
1019 int32_t lineBreakIteratorCurrent = lineBreakIterator->current();
1020 while (!lineBreakIterator->isDone() && lineBreakIteratorCurrent < glyphCluster)
1021 {
1022 lineBreakIteratorCurrent = lineBreakIterator->next();
1023 }
1024 glyph.fMayLineBreakBefore = glyph.fCluster != previousCluster &&
1025 lineBreakIteratorCurrent == glyphCluster;
1026
1027 int32_t graphemeBreakIteratorCurrent = graphemeBreakIterator->current();
1028 while (!graphemeBreakIterator->isDone() && graphemeBreakIteratorCurrent < glyphCluster)
1029 {
1030 graphemeBreakIteratorCurrent = graphemeBreakIterator->next();
1031 }
1032 glyph.fGraphemeBreakBefore = glyph.fCluster != previousCluster &&
1033 graphemeBreakIteratorCurrent == glyphCluster;
1034
1035 previousCluster = glyph.fCluster;
1036 }
1037 }
1038}
1039
1040// Iterate over the glyphs in logical order to find potential line lengths.
1041{
1042 /** The position of the beginning of the line. */
1043 ShapedRunGlyphIterator beginning(runs);
1044
1045 /** The position of the candidate line break. */
1046 ShapedRunGlyphIterator candidateLineBreak(runs);
1047 SkScalar candidateLineBreakWidth = 0;
1048
1049 /** The position of the candidate grapheme break. */
1050 ShapedRunGlyphIterator candidateGraphemeBreak(runs);
1051 SkScalar candidateGraphemeBreakWidth = 0;
1052
1053 /** The position of the current location. */
1054 ShapedRunGlyphIterator current(runs);
1055 SkScalar currentWidth = 0;
1056 while (ShapedGlyph* glyph = current.current()) {
1057 // 'Break' at graphemes until a line boundary, then only at line boundaries.
1058 // Only break at graphemes if no line boundary is valid.
1059 if (current != beginning) {
1060 if (glyph->fGraphemeBreakBefore || glyph->fMayLineBreakBefore) {
1061 // TODO: preserve line breaks <= grapheme breaks
1062 // and prevent line breaks inside graphemes
1063 candidateGraphemeBreak = current;
1064 candidateGraphemeBreakWidth = currentWidth;
1065 if (glyph->fMayLineBreakBefore) {
1066 candidateLineBreak = current;
1067 candidateLineBreakWidth = currentWidth;
1068 }
1069 }
1070 }
1071
1072 SkScalar glyphWidth = glyph->fAdvance.fX;
1073 // Break when overwidth, the glyph has a visual representation, and some space is used.
1074 if (width < currentWidth + glyphWidth && glyph->fHasVisual && candidateGraphemeBreakWidth > 0){
1075 if (candidateLineBreak != beginning) {
1076 beginning = candidateLineBreak;
1077 currentWidth -= candidateLineBreakWidth;
1078 candidateGraphemeBreakWidth -= candidateLineBreakWidth;
1079 candidateLineBreakWidth = 0;
1080 } else if (candidateGraphemeBreak != beginning) {
1081 beginning = candidateGraphemeBreak;
1082 candidateLineBreak = beginning;
1083 currentWidth -= candidateGraphemeBreakWidth;
1084 candidateGraphemeBreakWidth = 0;
1085 candidateLineBreakWidth = 0;
1086 } else {
1087 SK_ABORT("");
1088 }
1089
1090 if (width < currentWidth) {
1091 if (width < candidateGraphemeBreakWidth) {
1092 candidateGraphemeBreak = candidateLineBreak;
1093 candidateGraphemeBreakWidth = candidateLineBreakWidth;
1094 }
1095 current = candidateGraphemeBreak;
1096 currentWidth = candidateGraphemeBreakWidth;
1097 }
1098
1099 glyph = beginning.current();
1100 if (glyph) {
1101 glyph->fMustLineBreakBefore = true;
1102 }
1103
1104 } else {
1105 current.next();
1106 currentWidth += glyphWidth;
1107 }
1108 }
1109}
1110
1111// Reorder the runs and glyphs per line and write them out.
1112{
1113 ShapedRunGlyphIterator previousBreak(runs);
1114 ShapedRunGlyphIterator glyphIterator(runs);
1115 int previousRunIndex = -1;
1116 while (glyphIterator.current()) {
1117 const ShapedRunGlyphIterator current = glyphIterator;
1118 ShapedGlyph* nextGlyph = glyphIterator.next();
1119
1120 if (previousRunIndex != current.fRunIndex) {
1121 SkFontMetrics metrics;
1122 runs[current.fRunIndex].fFont.getMetrics(&metrics);
1123 previousRunIndex = current.fRunIndex;
1124 }
1125
1126 // Nothing can be written until the baseline is known.
1127 if (!(nextGlyph == nullptr || nextGlyph->fMustLineBreakBefore)) {
1128 continue;
1129 }
1130
1131 int numRuns = current.fRunIndex - previousBreak.fRunIndex + 1;
1132 AutoSTMalloc<4, SkBidiIterator::Level> runLevels(numRuns);
1133 for (int i = 0; i < numRuns; ++i) {
1134 runLevels[i] = runs[previousBreak.fRunIndex + i].fLevel;
1135 }
1136 AutoSTMalloc<4, int32_t> logicalFromVisual(numRuns);
1137 fUnicode->reorderVisual(runLevels, numRuns, logicalFromVisual);
1138
1139 // step through the runs in reverse visual order and the glyphs in reverse logical order
1140 // until a visible glyph is found and force them to the end of the visual line.
1141
1142 handler->beginLine();
1143
1144 struct SubRun { const ShapedRun& run; size_t startGlyphIndex; size_t endGlyphIndex; };
1145 auto makeSubRun = [&runs, &previousBreak, &current, &logicalFromVisual](size_t visualIndex){
1146 int logicalIndex = previousBreak.fRunIndex + logicalFromVisual[visualIndex];
1147 const auto& run = runs[logicalIndex];
1148 size_t startGlyphIndex = (logicalIndex == previousBreak.fRunIndex)
1149 ? previousBreak.fGlyphIndex
1150 : 0;
1151 size_t endGlyphIndex = (logicalIndex == current.fRunIndex)
1152 ? current.fGlyphIndex + 1
1153 : run.fNumGlyphs;
1154 return SubRun{ run, startGlyphIndex, endGlyphIndex };
1155 };
1156 auto makeRunInfo = [](const SubRun& sub) {
1157 uint32_t startUtf8 = sub.run.fGlyphs[sub.startGlyphIndex].fCluster;
1158 uint32_t endUtf8 = (sub.endGlyphIndex < sub.run.fNumGlyphs)
1159 ? sub.run.fGlyphs[sub.endGlyphIndex].fCluster
1160 : sub.run.fUtf8Range.end();
1161
1162 SkVector advance = SkVector::Make(0, 0);
1163 for (size_t i = sub.startGlyphIndex; i < sub.endGlyphIndex; ++i) {
1164 advance += sub.run.fGlyphs[i].fAdvance;
1165 }
1166
1167 return RunHandler::RunInfo{
1168 sub.run.fFont,
1169 sub.run.fLevel,
1170 advance,
1171 sub.endGlyphIndex - sub.startGlyphIndex,
1172 RunHandler::Range(startUtf8, endUtf8 - startUtf8)
1173 };
1174 };
1175
1176 for (int i = 0; i < numRuns; ++i) {
1177 handler->runInfo(makeRunInfo(makeSubRun(i)));
1178 }
1179 handler->commitRunInfo();
1180 for (int i = 0; i < numRuns; ++i) {
1181 SubRun sub = makeSubRun(i);
1182 append(handler, makeRunInfo(sub), sub.run, sub.startGlyphIndex, sub.endGlyphIndex);
1183 }
1184
1185 handler->commitLine();
1186
1187 previousRunIndex = -1;
1188 previousBreak = glyphIterator;
1189 }
1190}
1191}
1192
1193void ShapeDontWrapOrReorder::wrap(char const * const utf8, size_t utf8Bytes,
1194 const BiDiRunIterator& bidi,
1195 const LanguageRunIterator& language,
1196 const ScriptRunIterator& script,
1197 const FontRunIterator& font,
1198 RunIteratorQueue& runSegmenter,
1199 const Feature* features, size_t featuresSize,
1201 RunHandler* handler) const
1202{
1204 TArray<ShapedRun> runs;
1205
1206 const char* utf8Start = nullptr;
1207 const char* utf8End = utf8;
1208 while (runSegmenter.advanceRuns()) {
1209 utf8Start = utf8End;
1210 utf8End = utf8 + runSegmenter.endOfCurrentRun();
1211
1212 runs.emplace_back(shape(utf8, utf8Bytes,
1213 utf8Start, utf8End,
1214 bidi, language, script, font,
1215 features, featuresSize));
1216 }
1217
1218 handler->beginLine();
1219 for (const auto& run : runs) {
1220 const RunHandler::RunInfo info = {
1221 run.fFont,
1222 run.fLevel,
1223 run.fAdvance,
1224 run.fNumGlyphs,
1225 run.fUtf8Range
1226 };
1227 handler->runInfo(info);
1228 }
1229 handler->commitRunInfo();
1230 for (const auto& run : runs) {
1231 const RunHandler::RunInfo info = {
1232 run.fFont,
1233 run.fLevel,
1234 run.fAdvance,
1235 run.fNumGlyphs,
1236 run.fUtf8Range
1237 };
1238 append(handler, info, run, 0, run.fNumGlyphs);
1239 }
1240 handler->commitLine();
1241}
1242
1243class HBLockedFaceCache {
1244public:
1245 HBLockedFaceCache(SkLRUCache<SkTypefaceID, HBFont>& lruCache, SkMutex& mutex)
1246 : fLRUCache(lruCache), fMutex(mutex)
1247 {
1248 fMutex.acquire();
1249 }
1250 HBLockedFaceCache(const HBLockedFaceCache&) = delete;
1251 HBLockedFaceCache& operator=(const HBLockedFaceCache&) = delete;
1252 HBLockedFaceCache& operator=(HBLockedFaceCache&&) = delete;
1253
1254 ~HBLockedFaceCache() {
1255 fMutex.release();
1256 }
1257
1258 HBFont* find(SkTypefaceID fontId) {
1259 return fLRUCache.find(fontId);
1260 }
1261 HBFont* insert(SkTypefaceID fontId, HBFont hbFont) {
1262 return fLRUCache.insert(fontId, std::move(hbFont));
1263 }
1264 void reset() {
1265 fLRUCache.reset();
1266 }
1267private:
1269 SkMutex& fMutex;
1270};
1271static HBLockedFaceCache get_hbFace_cache() {
1272 static SkMutex gHBFaceCacheMutex;
1273 static SkLRUCache<SkTypefaceID, HBFont> gHBFaceCache(100);
1274 return HBLockedFaceCache(gHBFaceCache, gHBFaceCacheMutex);
1275}
1276
1277ShapedRun ShaperHarfBuzz::shape(char const * const utf8,
1278 size_t const utf8Bytes,
1279 char const * const utf8Start,
1280 char const * const utf8End,
1281 const BiDiRunIterator& bidi,
1282 const LanguageRunIterator& language,
1283 const ScriptRunIterator& script,
1284 const FontRunIterator& font,
1285 Feature const * const features, size_t const featuresSize) const
1286{
1287 size_t utf8runLength = utf8End - utf8Start;
1288 ShapedRun run(RunHandler::Range(utf8Start - utf8, utf8runLength),
1289 font.currentFont(), bidi.currentLevel(), nullptr, 0);
1290
1291 hb_buffer_t* buffer = fBuffer.get();
1293 hb_buffer_set_content_type(buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
1294 hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
1295
1296 // Documentation for HB_BUFFER_FLAG_BOT/EOT at 763e5466c0a03a7c27020e1e2598e488612529a7.
1297 // Currently BOT forces a dotted circle when first codepoint is a mark; EOT has no effect.
1298 // Avoid adding dotted circle, re-evaluate if BOT/EOT change. See https://skbug.com/9618.
1299 // hb_buffer_set_flags(buffer, HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT);
1300
1301 // Add precontext.
1302 hb_buffer_add_utf8(buffer, utf8, utf8Start - utf8, utf8Start - utf8, 0);
1303
1304 // Populate the hb_buffer directly with utf8 cluster indexes.
1305 const char* utf8Current = utf8Start;
1306 while (utf8Current < utf8End) {
1307 unsigned int cluster = utf8Current - utf8;
1308 hb_codepoint_t u = utf8_next(&utf8Current, utf8End);
1309 hb_buffer_add(buffer, u, cluster);
1310 }
1311
1312 // Add postcontext.
1313 hb_buffer_add_utf8(buffer, utf8Current, utf8 + utf8Bytes - utf8Current, 0, 0);
1314
1315 hb_direction_t direction = is_LTR(bidi.currentLevel()) ? HB_DIRECTION_LTR:HB_DIRECTION_RTL;
1316 hb_buffer_set_direction(buffer, direction);
1317 hb_buffer_set_script(buffer, hb_script_from_iso15924_tag((hb_tag_t)script.currentScript()));
1318 // Buffers with HB_LANGUAGE_INVALID race since hb_language_get_default is not thread safe.
1319 // The user must provide a language, but may provide data hb_language_from_string cannot use.
1320 // Use "und" for the undefined language in this case (RFC5646 4.1 5).
1321 hb_language_t hbLanguage = hb_language_from_string(language.currentLanguage(), -1);
1322 if (hbLanguage == HB_LANGUAGE_INVALID) {
1323 hbLanguage = fUndefinedLanguage;
1324 }
1325 hb_buffer_set_language(buffer, hbLanguage);
1326 hb_buffer_guess_segment_properties(buffer);
1327
1328 // TODO: better cache HBFace (data) / hbfont (typeface)
1329 // An HBFace is expensive (it sanitizes the bits).
1330 // An HBFont is fairly inexpensive.
1331 // An HBFace is actually tied to the data, not the typeface.
1332 // The size of 100 here is completely arbitrary and used to match libtxt.
1333 HBFont hbFont;
1334 {
1335 HBLockedFaceCache cache = get_hbFace_cache();
1336 SkTypefaceID dataId = font.currentFont().getTypeface()->uniqueID();
1337 HBFont* typefaceFontCached = cache.find(dataId);
1338 if (!typefaceFontCached) {
1339 HBFont typefaceFont(create_typeface_hb_font(*font.currentFont().getTypeface()));
1340 typefaceFontCached = cache.insert(dataId, std::move(typefaceFont));
1341 }
1342 hbFont = create_sub_hb_font(font.currentFont(), *typefaceFontCached);
1343 }
1344 if (!hbFont) {
1345 return run;
1346 }
1347
1348 STArray<32, hb_feature_t> hbFeatures;
1349 for (const auto& feature : SkSpan(features, featuresSize)) {
1350 if (feature.end < SkTo<size_t>(utf8Start - utf8) ||
1351 SkTo<size_t>(utf8End - utf8) <= feature.start)
1352 {
1353 continue;
1354 }
1355 if (feature.start <= SkTo<size_t>(utf8Start - utf8) &&
1356 SkTo<size_t>(utf8End - utf8) <= feature.end)
1357 {
1358 hbFeatures.push_back({ (hb_tag_t)feature.tag, feature.value,
1360 } else {
1361 hbFeatures.push_back({ (hb_tag_t)feature.tag, feature.value,
1362 SkTo<unsigned>(feature.start), SkTo<unsigned>(feature.end)});
1363 }
1364 }
1365
1366 hb_shape(hbFont.get(), buffer, hbFeatures.data(), hbFeatures.size());
1367 unsigned len = hb_buffer_get_length(buffer);
1368 if (len == 0) {
1369 return run;
1370 }
1371
1372 if (direction == HB_DIRECTION_RTL) {
1373 // Put the clusters back in logical order.
1374 // Note that the advances remain ltr.
1375 hb_buffer_reverse(buffer);
1376 }
1377 hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, nullptr);
1378 hb_glyph_position_t* pos = hb_buffer_get_glyph_positions(buffer, nullptr);
1379
1380 run = ShapedRun(RunHandler::Range(utf8Start - utf8, utf8runLength),
1381 font.currentFont(), bidi.currentLevel(),
1382 std::unique_ptr<ShapedGlyph[]>(new ShapedGlyph[len]), len);
1383
1384 // Undo skhb_position with (1.0/(1<<16)) and scale as needed.
1385 AutoSTArray<32, SkGlyphID> glyphIDs(len);
1386 for (unsigned i = 0; i < len; i++) {
1387 glyphIDs[i] = info[i].codepoint;
1388 }
1389 AutoSTArray<32, SkRect> glyphBounds(len);
1390 SkPaint p;
1391 run.fFont.getBounds(glyphIDs.get(), len, glyphBounds.get(), &p);
1392
1393 double SkScalarFromHBPosX = +(1.52587890625e-5) * run.fFont.getScaleX();
1394 double SkScalarFromHBPosY = -(1.52587890625e-5); // HarfBuzz y-up, Skia y-down
1395 SkVector runAdvance = { 0, 0 };
1396 for (unsigned i = 0; i < len; i++) {
1397 ShapedGlyph& glyph = run.fGlyphs[i];
1398 glyph.fID = info[i].codepoint;
1399 glyph.fCluster = info[i].cluster;
1400 glyph.fOffset.fX = pos[i].x_offset * SkScalarFromHBPosX;
1401 glyph.fOffset.fY = pos[i].y_offset * SkScalarFromHBPosY;
1402 glyph.fAdvance.fX = pos[i].x_advance * SkScalarFromHBPosX;
1403 glyph.fAdvance.fY = pos[i].y_advance * SkScalarFromHBPosY;
1404
1405 glyph.fHasVisual = !glyphBounds[i].isEmpty(); //!font->currentTypeface()->glyphBoundsAreZero(glyph.fID);
1406#if SK_HB_VERSION_CHECK(1, 5, 0)
1407 glyph.fUnsafeToBreak = info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
1408#else
1409 glyph.fUnsafeToBreak = false;
1410#endif
1411 glyph.fMustLineBreakBefore = false;
1412
1413 runAdvance += glyph.fAdvance;
1414 }
1415 run.fAdvance = runAdvance;
1416
1417 return run;
1418}
1419} // namespace
1420
1421#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
1422
1423#if defined(SK_UNICODE_ICU_IMPLEMENTATION)
1425#endif
1426
1427#if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
1429#endif
1430
1431#if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
1433#endif
1434
1436#if defined(SK_UNICODE_ICU_IMPLEMENTATION)
1437 if (auto unicode = SkUnicodes::ICU::Make()) {
1438 return unicode;
1439 }
1440#endif // defined(SK_UNICODE_ICU_IMPLEMENTATION)
1441#if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
1442 if (auto unicode = SkUnicodes::Libgrapheme::Make()) {
1443 return unicode;
1444 }
1445#endif
1446#if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
1447 if (auto unicode = SkUnicodes::ICU4X::Make()) {
1448 return unicode;
1449 }
1450#endif
1451 return nullptr;
1452}
1453
1454std::unique_ptr<SkShaper::ScriptRunIterator>
1455SkShaper::MakeHbIcuScriptRunIterator(const char* utf8, size_t utf8Bytes) {
1456 return SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes);
1457}
1458
1459std::unique_ptr<SkShaper::ScriptRunIterator>
1460SkShaper::MakeSkUnicodeHbScriptRunIterator(const char* utf8, size_t utf8Bytes) {
1461 return SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes);
1462}
1463
1464std::unique_ptr<SkShaper::ScriptRunIterator> SkShaper::MakeSkUnicodeHbScriptRunIterator(
1465 const char* utf8, size_t utf8Bytes, SkFourByteTag script) {
1466 return SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes, script);
1467}
1468
1469std::unique_ptr<SkShaper> SkShaper::MakeShaperDrivenWrapper(sk_sp<SkFontMgr> fontmgr) {
1471}
1472
1473std::unique_ptr<SkShaper> SkShaper::MakeShapeThenWrap(sk_sp<SkFontMgr> fontmgr) {
1474 return SkShapers::HB::ShapeThenWrap(get_unicode(), fontmgr);
1475}
1476
1477void SkShaper::PurgeHarfBuzzCache() { SkShapers::HB::PurgeCaches(); }
1478#endif // !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
1479
1480namespace SkShapers::HB {
1481std::unique_ptr<SkShaper> ShaperDrivenWrapper(sk_sp<SkUnicode> unicode,
1482 sk_sp<SkFontMgr> fallback) {
1483 if (!unicode) {
1484 return nullptr;
1485 }
1486 HBBuffer buffer(hb_buffer_create());
1487 if (!buffer) {
1488 SkDEBUGF("Could not create hb_buffer");
1489 return nullptr;
1490 }
1491 return std::make_unique<::ShaperDrivenWrapper>(
1492 unicode, std::move(buffer), std::move(fallback));
1493}
1494
1495std::unique_ptr<SkShaper> ShapeThenWrap(sk_sp<SkUnicode> unicode,
1496 sk_sp<SkFontMgr> fallback) {
1497 if (!unicode) {
1498 return nullptr;
1499 }
1500 HBBuffer buffer(hb_buffer_create());
1501 if (!buffer) {
1502 SkDEBUGF("Could not create hb_buffer");
1503 return nullptr;
1504 }
1505 return std::make_unique<::ShapeThenWrap>(
1506 unicode, std::move(buffer), std::move(fallback));
1507}
1508
1509std::unique_ptr<SkShaper> ShapeDontWrapOrReorder(sk_sp<SkUnicode> unicode,
1510 sk_sp<SkFontMgr> fallback) {
1511 if (!unicode) {
1512 return nullptr;
1513 }
1514 HBBuffer buffer(hb_buffer_create());
1515 if (!buffer) {
1516 SkDEBUGF("Could not create hb_buffer");
1517 return nullptr;
1518 }
1519 return std::make_unique<::ShapeDontWrapOrReorder>(
1520 unicode, std::move(buffer), std::move(fallback));
1521}
1522
1523std::unique_ptr<SkShaper::ScriptRunIterator> ScriptRunIterator(const char* utf8, size_t utf8Bytes) {
1524 return std::make_unique<SkUnicodeHbScriptRunIterator>(utf8, utf8Bytes, HB_SCRIPT_UNKNOWN);
1525}
1526std::unique_ptr<SkShaper::ScriptRunIterator> ScriptRunIterator(const char* utf8,
1527 size_t utf8Bytes,
1528 SkFourByteTag script) {
1529 return std::make_unique<SkUnicodeHbScriptRunIterator>(
1530 utf8, utf8Bytes, hb_script_from_iso15924_tag((hb_tag_t)script));
1531}
1532
1533void PurgeCaches() {
1534 HBLockedFaceCache cache = get_hbFace_cache();
1535 cache.reset();
1536}
1537} // namespace SkShapers::HB
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
m reset()
uint16_t glyphs[5]
SkPoint pos
static float next(float f)
static float prev(float f)
#define SK_ABORT(message,...)
Definition SkAssert.h:70
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SkDEBUGF(...)
Definition SkDebug.h:24
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
SK_API void sk_free(void *)
static void * sk_malloc_throw(size_t size)
Definition SkMalloc.h:67
bool operator!=(const sk_sp< T > &a, const sk_sp< U > &b)
Definition SkRefCnt.h:355
static void SkSafeUnref(T *obj)
Definition SkRefCnt.h:149
static T * SkRef(T *obj)
Definition SkRefCnt.h:132
#define SK_ScalarNegativeInfinity
Definition SkScalar.h:27
static SkUnichar utf8_next(const char **ptr, const char *end)
Definition SkShaper.cpp:84
#define HB_FEATURE_GLOBAL_END
static sk_sp< SkUnicode > get_unicode()
#define HB_FEATURE_GLOBAL_START
void sk_ignore_unused_variable(const T &)
Definition SkTemplates.h:37
constexpr unsigned SkToUInt(S x)
Definition SkTo.h:30
uint32_t SkTypefaceID
Definition SkTypeface.h:38
int32_t SkUnichar
Definition SkTypes.h:175
uint16_t SkGlyphID
Definition SkTypes.h:179
uint32_t SkFourByteTag
Definition SkTypes.h:166
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Definition SkTypes.h:167
int find(T *array, int N, T item)
uint8_t Level
Definition SkUnicode.h:46
virtual Position next()=0
virtual bool isDone()=0
void * writable_data()
Definition SkData.h:52
size_t size() const
Definition SkData.h:30
virtual void commitLine()=0
Definition shape.cpp:201
virtual void commitRunBuffer(const RunInfo &)=0
Definition shape.cpp:176
virtual void commitRunInfo()=0
Definition shape.cpp:150
virtual void runInfo(const RunInfo &)=0
Definition shape.cpp:142
virtual void beginLine()=0
Definition shape.cpp:135
virtual Buffer runBuffer(const RunInfo &)=0
Definition shape.cpp:154
virtual bool atEnd() const =0
virtual void consume()=0
virtual size_t endOfCurrentRun() const =0
virtual SkFourByteTag currentScript() const =0
virtual void shape(const char *utf8, size_t utf8Bytes, const SkFont &srcFont, bool leftToRight, SkScalar width, RunHandler *) const =0
bool equals(const SkString &) const
Definition SkString.cpp:324
const char * c_str() const
Definition SkString.h:133
std::unique_ptr< SkStreamAsset > openExistingStream(int *ttcIndex) const
sk_sp< SkData > copyTableData(SkFontTableTag tag) const
int getUnitsPerEm() const
int getVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
int size() const
Definition SkTArray.h:416
T & emplace_back(Args &&... args)
Definition SkTArray.h:243
static void append(char **dst, size_t *count, const char *src, size_t n)
Definition editor.cpp:211
bool operator==(const FlutterPoint &a, const FlutterPoint &b)
float SkScalar
Definition extension.cpp:12
static bool b
struct MyStruct a[10]
glong glong end
static const uint8_t buffer[]
SKSHAPER_API std::unique_ptr< SkShaper > ShapeDontWrapOrReorder(sk_sp< SkUnicode > unicode, sk_sp< SkFontMgr > fallback)
SKSHAPER_API std::unique_ptr< SkShaper > ShapeThenWrap(sk_sp< SkUnicode > unicode, sk_sp< SkFontMgr > fallback)
SKSHAPER_API std::unique_ptr< SkShaper > ShaperDrivenWrapper(sk_sp< SkUnicode > unicode, sk_sp< SkFontMgr > fallback)
SKSHAPER_API void PurgeCaches()
SKSHAPER_API std::unique_ptr< SkShaper::ScriptRunIterator > ScriptRunIterator(const char *utf8, size_t utf8Bytes)
SKSHAPER_API std::unique_ptr< SkShaper::BiDiRunIterator > BidiRunIterator(sk_sp< SkUnicode > unicode, const char *utf8, size_t utf8Bytes, uint8_t bidiLevel)
SK_SPI SkUnichar NextUTF8(const char **ptr, const char *end)
Definition SkUTF.cpp:118
SKUNICODE_API sk_sp< SkUnicode > Make()
SKUNICODE_API sk_sp< SkUnicode > Make()
SKUNICODE_API sk_sp< SkUnicode > Make()
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
Definition switches.h:191
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port fallback
Definition switches.h:154
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition switches.h:259
font
Font Metadata and Metrics.
Definition run.py:1
Definition ref_ptr.h:256
static sk_sp< SkUnicode > get_unicode()
int32_t width
const Scalar scale
static constexpr SkPoint Make(float x, float y)

Function Documentation

◆ get_unicode()

static sk_sp< SkUnicode > get_unicode ( )
static

Definition at line 1436 of file SkShaper_harfbuzz.cpp.

1436 {
1437#if defined(SK_UNICODE_ICU_IMPLEMENTATION)
1438 if (auto unicode = SkUnicodes::ICU::Make()) {
1439 return unicode;
1440 }
1441#endif // defined(SK_UNICODE_ICU_IMPLEMENTATION)
1442#if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
1443 if (auto unicode = SkUnicodes::Libgrapheme::Make()) {
1444 return unicode;
1445 }
1446#endif
1447#if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
1448 if (auto unicode = SkUnicodes::ICU4X::Make()) {
1449 return unicode;
1450 }
1451#endif
1452 return nullptr;
1453}