210 {
211 static hb_font_funcs_t* const funcs = []{
212
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
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
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 }();
232 return funcs;
233}
234
235hb_blob_t* skhb_get_table(hb_face_t* face, hb_tag_t tag,
void*
user_data) {
237
239 if (!data) {
240 return nullptr;
241 }
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
259 asset->read(ptr, size);
260 blob.reset(hb_blob_create((
char*)ptr,
SkToUInt(size),
261 HB_MEMORY_MODE_READONLY, ptr,
sk_free));
262 }
264 hb_blob_make_immutable(blob.get());
265 return blob;
266}
267
269
270HBFace create_hb_face(
const SkTypeface& typeface) {
271 int index = 0;
273 HBFace face;
274 if (typefaceAsset && typefaceAsset->getMemoryBase()) {
275 HBBlob blob(stream_to_blob(std::move(typefaceAsset)));
276
277
278
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
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,
293 hb_face_set_index(face.get(), (unsigned)index);
294 }
296 if (!face) {
297 return nullptr;
298 }
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()));
317 if (!otFont) {
318 return nullptr;
319 }
320 hb_ot_font_set_funcs(otFont.get());
322 if (axis_count > 0) {
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);
339 )
340
341
342
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)),
347 int scale = skhb_position(
font.getSize());
348 hb_font_set_scale(skFont.get(),
scale,
scale);
349
350 return skFont;
351}
352
353
356 return val < 0 ? 0xFFFD : val;
357}
358
360public:
361 SkUnicodeHbScriptRunIterator(const char* utf8,
362 size_t utf8Bytes,
363 hb_script_t defaultScript)
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 }
374 fCurrentScript = hb_script_for_unichar(u);
375 while (fCurrent < fEnd) {
376 const char*
prev = fCurrent;
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) {
382 } else if (script == HB_SCRIPT_INHERITED || script == HB_SCRIPT_COMMON) {
383 continue;
384 } else {
386 break;
387 }
388 }
389 }
390 if (fCurrentScript == HB_SCRIPT_INHERITED) {
391 fCurrentScript = HB_SCRIPT_COMMON;
392 }
393 }
395 return fCurrent - fBegin;
396 }
397 bool atEnd()
const override {
398 return fCurrent == fEnd;
399 }
400
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:
414 fEntries.insert({runIterator, priority});
415 }
416
417 bool advanceRuns() {
419 if (leastRun->
atEnd()) {
421 return false;
422 }
426 while ((currentRun = fEntries.peek().runIterator)->endOfCurrentRun() <= leastEnd) {
427 int priority = fEntries.peek().priority;
428 fEntries.pop();
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
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 {
465 uint32_t fCluster;
468 bool fMayLineBreakBefore;
469 bool fMustLineBreakBefore;
470 bool fHasVisual;
471 bool fGraphemeBreakBefore;
472 bool fUnsafeToBreak;
473};
474struct ShapedRun {
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
484 std::unique_ptr<ShapedGlyph[]> fGlyphs;
485 size_t fNumGlyphs;
487
493
495};
496struct ShapedLine {
499};
500
502 return (level & 1) == 0;
503}
504
506 const ShapedRun&
run,
size_t startGlyphIndex,
size_t endGlyphIndex) {
507 SkASSERT(startGlyphIndex <= endGlyphIndex);
508 const size_t glyphLen = endGlyphIndex - startGlyphIndex;
509
513
515 for (size_t i = 0; i < glyphLen; i++) {
516
517 const ShapedGlyph& glyph =
run.fGlyphs[is_LTR(
run.fLevel) ? startGlyphIndex + i
518 : endGlyphIndex - 1 - i];
519 buffer.glyphs[i] = glyph.fID;
522 buffer.offsets[i] = glyph.fOffset;
523 } else {
524 buffer.positions[i] = advance +
buffer.point + glyph.fOffset;
525 }
527 buffer.clusters[i] = glyph.fCluster;
528 }
529 advance += glyph.fAdvance;
530 }
532}
533
535
537
538 int numRuns =
line.runs.size();
540 for (int i = 0; i < numRuns; ++i) {
541 runLevels[i] =
line.runs[i].fLevel;
542 }
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];
556 };
558 }
560 for (int i = 0; i < numRuns; ++i) {
561 int logicalIndex = logicalFromVisual[i];
562
563 const auto&
run =
line.runs[logicalIndex];
570 };
572 }
573
575}
576
577struct ShapedRunGlyphIterator {
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() {
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() {
613 if (fRunIndex >= runs.
size()) {
614 return nullptr;
615 }
616 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
617 }
618
620 int fRunIndex;
621 size_t fGlyphIndex;
622};
623
624class ShaperHarfBuzz :
public SkShaper {
625public:
627 HBBuffer,
629
630protected:
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:
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,
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
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
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
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
733 , fUndefinedLanguage(hb_language_from_string("und", -1)) {
734#if defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
736#endif
737}
738
739#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
740void ShaperHarfBuzz::shape(const char* utf8,
741 size_t utf8Bytes,
743 bool leftToRight,
745 RunHandler* handler) const {
747 std::unique_ptr<BiDiRunIterator> bidi(
749
750 if (!bidi) {
751 return;
752 }
753
754 std::unique_ptr<LanguageRunIterator> language(MakeStdLanguageRunIterator(utf8, utf8Bytes));
755 if (!language) {
756 return;
757 }
758
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
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 {
796 RunIteratorQueue runSegmenter;
797 runSegmenter.insert(&font, 3);
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{
817
818 const char* utf8Start = nullptr;
819 const char* utf8End =
utf8;
820 SkUnicodeBreak lineBreakIterator;
822 while (runSegmenter.advanceRuns()) {
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;
833 };
834
835 std::unique_ptr<TextProps[]> modelText;
836 int modelTextOffset = 0;
837 SkVector modelAdvanceOffset = {0, 0};
838
839 while (utf8Start < utf8End) {
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
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
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
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
875
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 }
888
889 ShapedRun best(RunHandler::Range(),
SkFont(), 0,
nullptr, 0,
891 bool bestIsInvalid = true;
892 bool bestUsesModelForGlyphs = false;
894
895 for (int32_t breakIteratorCurrent = breakIterator.
next();
897 breakIteratorCurrent = breakIterator.
next())
898 {
899
900
901
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
933 if (
width <
line.fAdvance.fX + best.fAdvance.fX && !
line.runs.empty()) {
934 emit(fUnicode.get(), line, handler);
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
953 if (utf8Start != utf8End) {
954 emit(fUnicode.get(), line, handler);
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{
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
987 utf8Start, utf8End,
988 bidi, language, script, font,
989 features, featuresSize));
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
1041{
1042
1043 ShapedRunGlyphIterator beginning(runs);
1044
1045
1046 ShapedRunGlyphIterator candidateLineBreak(runs);
1047 SkScalar candidateLineBreakWidth = 0;
1048
1049
1050 ShapedRunGlyphIterator candidateGraphemeBreak(runs);
1051 SkScalar candidateGraphemeBreakWidth = 0;
1052
1053
1054 ShapedRunGlyphIterator current(runs);
1056 while (ShapedGlyph* glyph = current.current()) {
1057
1058
1059 if (current != beginning) {
1060 if (glyph->fGraphemeBreakBefore || glyph->fMayLineBreakBefore) {
1061
1062
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
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 {
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
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) {
1122 runs[current.fRunIndex].fFont.getMetrics(&metrics);
1123 previousRunIndex = current.fRunIndex;
1124 }
1125
1126
1127 if (!(nextGlyph == nullptr || nextGlyph->fMustLineBreakBefore)) {
1128 continue;
1129 }
1130
1131 int numRuns = current.fRunIndex - previousBreak.fRunIndex + 1;
1133 for (int i = 0; i < numRuns; ++i) {
1134 runLevels[i] = runs[previousBreak.fRunIndex + i].fLevel;
1135 }
1137 fUnicode->reorderVisual(runLevels, numRuns, logicalFromVisual);
1138
1139
1140
1141
1142 handler->beginLine();
1143
1144 struct SubRun {
const ShapedRun&
run;
size_t startGlyphIndex;
size_t endGlyphIndex; };
1145 auto makeSubRun = [&runs, &previousBreak, ¤t, &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
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
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{
1205
1206 const char* utf8Start = nullptr;
1207 const char* utf8End =
utf8;
1208 while (runSegmenter.advanceRuns()) {
1209 utf8Start = utf8End;
1210 utf8End =
utf8 + runSegmenter.endOfCurrentRun();
1211
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 = {
1226 };
1227 handler->runInfo(
info);
1228 }
1229 handler->commitRunInfo();
1230 for (
const auto&
run : runs) {
1231 const RunHandler::RunInfo
info = {
1237 };
1239 }
1240 handler->commitLine();
1241}
1242
1243class HBLockedFaceCache {
1244public:
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
1259 return fLRUCache.find(fontId);
1260 }
1262 return fLRUCache.insert(fontId, std::move(hbFont));
1263 }
1265 fLRUCache.reset();
1266 }
1267private:
1269 SkMutex& fMutex;
1270};
1271static HBLockedFaceCache get_hbFace_cache() {
1272 static SkMutex gHBFaceCacheMutex;
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
1297
1298
1299
1300
1301
1302 hb_buffer_add_utf8(
buffer, utf8, utf8Start - utf8, utf8Start - utf8, 0);
1303
1304
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
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
1319
1320
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
1329
1330
1331
1332
1333 HBFont hbFont;
1334 {
1335 HBLockedFaceCache
cache = get_hbFace_cache();
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) {
1346 }
1347
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) {
1370 }
1371
1372 if (direction == HB_DIRECTION_RTL) {
1373
1374
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
1386 for (
unsigned i = 0; i <
len; i++) {
1387 glyphIDs[i] =
info[i].codepoint;
1388 }
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);
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();
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
1418}
1419}
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)
1439 }
1440#endif
1441#if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
1444 }
1445#endif
1446#if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
1449 }
1450#endif
1451 return nullptr;
1452}
1453
1454std::unique_ptr<SkShaper::ScriptRunIterator>
1455SkShaper::MakeHbIcuScriptRunIterator(const char* utf8, size_t utf8Bytes) {
1457}
1458
1459std::unique_ptr<SkShaper::ScriptRunIterator>
1460SkShaper::MakeSkUnicodeHbScriptRunIterator(const char* utf8, size_t utf8Bytes) {
1462}
1463
1464std::unique_ptr<SkShaper::ScriptRunIterator> SkShaper::MakeSkUnicodeHbScriptRunIterator(
1467}
1468
1469std::unique_ptr<SkShaper> SkShaper::MakeShaperDrivenWrapper(
sk_sp<SkFontMgr> fontmgr) {
1471}
1472
1473std::unique_ptr<SkShaper> SkShaper::MakeShapeThenWrap(
sk_sp<SkFontMgr> fontmgr) {
1475}
1476
1478#endif
1479
1483 if (!unicode) {
1484 return nullptr;
1485 }
1486 HBBuffer
buffer(hb_buffer_create());
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
1497 if (!unicode) {
1498 return nullptr;
1499 }
1500 HBBuffer
buffer(hb_buffer_create());
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
1511 if (!unicode) {
1512 return nullptr;
1513 }
1514 HBBuffer
buffer(hb_buffer_create());
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}
1527 size_t utf8Bytes,
1529 return std::make_unique<SkUnicodeHbScriptRunIterator>(
1530 utf8, utf8Bytes, hb_script_from_iso15924_tag((hb_tag_t)script));
1531}
1532
1534 HBLockedFaceCache
cache = get_hbFace_cache();
1536}
1537}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static float next(float f)
static float prev(float f)
#define SK_ABORT(message,...)
SK_API void sk_free(void *)
static void * sk_malloc_throw(size_t size)
bool operator!=(const sk_sp< T > &a, const sk_sp< U > &b)
static void SkSafeUnref(T *obj)
#define SK_ScalarNegativeInfinity
static SkUnichar utf8_next(const char **ptr, const char *end)
#define HB_FEATURE_GLOBAL_END
static sk_sp< SkUnicode > get_unicode()
#define HB_FEATURE_GLOBAL_START
void sk_ignore_unused_variable(const T &)
constexpr unsigned SkToUInt(S x)
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
int find(T *array, int N, T item)
virtual Position next()=0
virtual void commitLine()=0
virtual void commitRunBuffer(const RunInfo &)=0
virtual void commitRunInfo()=0
virtual void runInfo(const RunInfo &)=0
virtual void beginLine()=0
virtual Buffer runBuffer(const RunInfo &)=0
virtual bool atEnd() const =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
const char * c_str() const
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
T & emplace_back(Args &&... args)
static void append(char **dst, size_t *count, const char *src, size_t n)
bool operator==(const FlutterPoint &a, const FlutterPoint &b)
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)
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
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
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
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
font
Font Metadata and Metrics.
static sk_sp< SkUnicode > get_unicode()
static constexpr SkPoint Make(float x, float y)