39#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
56#if !defined(HB_FEATURE_GLOBAL_START)
57# define HB_FEATURE_GLOBAL_START 0
59#if !defined(HB_FEATURE_GLOBAL_END)
60# define HB_FEATURE_GLOBAL_END ((unsigned int) -1)
64using HBBlob = std::unique_ptr<hb_blob_t , SkFunctionObject<hb_blob_destroy> >;
65using HBFace = std::unique_ptr<hb_face_t , SkFunctionObject<hb_face_destroy> >;
66using HBFont = std::unique_ptr<hb_font_t , SkFunctionObject<hb_font_destroy> >;
67using HBBuffer = std::unique_ptr<hb_buffer_t, SkFunctionObject<hb_buffer_destroy>>;
69using SkUnicodeBreak = std::unique_ptr<SkBreakIterator>;
73 constexpr int kHbPosition1 = 1 << 16;
77hb_bool_t skhb_glyph(hb_font_t* hb_font,
80 hb_codepoint_t variation_selector,
81 hb_codepoint_t* glyph,
89hb_bool_t skhb_nominal_glyph(hb_font_t* hb_font,
92 hb_codepoint_t* glyph,
97unsigned skhb_nominal_glyphs(hb_font_t *hb_font,
void *font_data,
99 const hb_codepoint_t *unicodes,
100 unsigned int unicode_stride,
102 unsigned int glyph_stride,
109 for (
unsigned i = 0;
i <
count;
i++) {
111 unicodes = SkTAddOffset<const hb_codepoint_t>(unicodes, unicode_stride);
121 glyphs = SkTAddOffset<hb_codepoint_t>(
glyphs, glyph_stride);
127hb_position_t skhb_glyph_h_advance(hb_font_t* hb_font,
129 hb_codepoint_t hbGlyph,
134 SkGlyphID skGlyph = SkTo<SkGlyphID>(hbGlyph);
136 font.getWidths(&skGlyph, 1, &advance);
137 if (!
font.isSubpixel()) {
140 return skhb_position(advance);
143void skhb_glyph_h_advances(hb_font_t* hb_font,
146 const hb_codepoint_t*
glyphs,
147 unsigned int glyph_stride,
148 hb_position_t* advances,
149 unsigned int advance_stride,
156 for (
unsigned i = 0;
i <
count;
i++) {
158 glyphs = SkTAddOffset<const hb_codepoint_t>(
glyphs, glyph_stride);
163 if (!
font.isSubpixel()) {
164 for (
unsigned i = 0;
i <
count;
i++) {
170 for (
unsigned i = 0;
i <
count;
i++) {
171 *advances = skhb_position(advance[
i]);
172 advances = SkTAddOffset<hb_position_t>(advances, advance_stride);
182hb_bool_t skhb_glyph_extents(hb_font_t* hb_font,
184 hb_codepoint_t hbGlyph,
185 hb_glyph_extents_t* extents,
191 SkGlyphID skGlyph = SkTo<SkGlyphID>(hbGlyph);
193 font.getWidths(&skGlyph, 1,
nullptr, &sk_bounds);
194 if (!
font.isSubpixel()) {
199 extents->x_bearing = skhb_position(sk_bounds.
fLeft);
200 extents->y_bearing = skhb_position(-sk_bounds.
fTop);
201 extents->width = skhb_position(sk_bounds.
width());
202 extents->height = skhb_position(-sk_bounds.
height());
206#define SK_HB_VERSION_CHECK(x, y, z) \
207 (HB_VERSION_MAJOR > (x)) || \
208 (HB_VERSION_MAJOR == (x) && HB_VERSION_MINOR > (y)) || \
209 (HB_VERSION_MAJOR == (x) && HB_VERSION_MINOR == (y) && HB_VERSION_MICRO >= (z))
211hb_font_funcs_t* skhb_get_font_funcs() {
212 static hb_font_funcs_t*
const funcs = []{
214 hb_font_funcs_t*
const funcs = hb_font_funcs_create();
215 hb_font_funcs_set_variation_glyph_func(funcs, skhb_glyph,
nullptr,
nullptr);
216 hb_font_funcs_set_nominal_glyph_func(funcs, skhb_nominal_glyph,
nullptr,
nullptr);
217#if SK_HB_VERSION_CHECK(2, 0, 0)
218 hb_font_funcs_set_nominal_glyphs_func(funcs, skhb_nominal_glyphs,
nullptr,
nullptr);
222 hb_font_funcs_set_glyph_h_advance_func(funcs, skhb_glyph_h_advance,
nullptr,
nullptr);
223#if SK_HB_VERSION_CHECK(1, 8, 6)
224 hb_font_funcs_set_glyph_h_advances_func(funcs, skhb_glyph_h_advances,
nullptr,
nullptr);
228 hb_font_funcs_set_glyph_extents_func(funcs, skhb_glyph_extents,
nullptr,
nullptr);
229 hb_font_funcs_make_immutable(funcs);
236hb_blob_t* skhb_get_table(hb_face_t* face, hb_tag_t tag,
void*
user_data) {
244 return hb_blob_create(
reinterpret_cast<char*
>(rawData->
writable_data()), rawData->
size(),
245 HB_MEMORY_MODE_READONLY, rawData, [](
void* ctx) {
246 SkSafeUnref(((SkData*)ctx));
250HBBlob stream_to_blob(std::unique_ptr<SkStreamAsset> asset) {
251 size_t size = asset->getLength();
253 if (
const void*
base = asset->getMemoryBase()) {
255 HB_MEMORY_MODE_READONLY, asset.release(),
256 [](
void*
p) { delete (SkStreamAsset*)p; }));
260 asset->read(ptr,
size);
262 HB_MEMORY_MODE_READONLY, ptr,
sk_free));
265 hb_blob_make_immutable(blob.get());
271HBFace create_hb_face(
const SkTypeface& typeface) {
275 if (typefaceAsset && typefaceAsset->getMemoryBase()) {
276 HBBlob blob(stream_to_blob(std::move(typefaceAsset)));
280 unsigned int num_hb_faces = hb_face_count(blob.get());
281 if (0 < num_hb_faces && (
unsigned)index < num_hb_faces) {
282 face.reset(hb_face_create(blob.get(), (
unsigned)index));
284 if (face && hb_face_get_glyph_count(face.get()) == 0) {
290 face.reset(hb_face_create_for_tables(
294 hb_face_set_index(face.get(), (
unsigned)index);
303 hb_face_set_user_data(face.get(), &gDataIdKey,
const_cast<SkTypeface*
>(&typeface),
310HBFont create_typeface_hb_font(const
SkTypeface& typeface) {
311 HBFace face(create_hb_face(typeface));
316 HBFont otFont(hb_font_create(face.get()));
321 hb_ot_font_set_funcs(otFont.get());
322 int axis_count = typeface.getVariationDesignPosition(
nullptr, 0);
323 if (axis_count > 0) {
325 if (typeface.getVariationDesignPosition(axis_values, axis_count) == axis_count) {
326 hb_font_set_variations(otFont.get(),
327 reinterpret_cast<hb_variation_t*
>(axis_values.get()),
335HBFont create_sub_hb_font(
const SkFont&
font,
const HBFont& typefaceFont) {
337 hb_face_t* face = hb_font_get_face(typefaceFont.get());
338 void* dataId = hb_face_get_user_data(face, &gDataIdKey);
344 HBFont skFont(hb_font_create_sub_font(typefaceFont.get()));
345 hb_font_set_funcs(skFont.get(), skhb_get_font_funcs(),
348 int scale = skhb_position(
font.getSize());
349 hb_font_set_scale(skFont.get(),
scale,
scale);
357 return val < 0 ? 0xFFFD : val;
362 SkUnicodeHbScriptRunIterator(
const char*
utf8,
364 hb_script_t defaultScript)
367 , fEnd(fCurrent + utf8Bytes)
368 , fCurrentScript(defaultScript) {}
369 hb_script_t hb_script_for_unichar(
SkUnichar u) {
370 return hb_unicode_script(hb_unicode_funcs_get_default(), u);
375 fCurrentScript = hb_script_for_unichar(u);
376 while (fCurrent < fEnd) {
377 const char*
prev = fCurrent;
379 const hb_script_t
script = hb_script_for_unichar(u);
380 if (
script != fCurrentScript) {
381 if (fCurrentScript == HB_SCRIPT_INHERITED || fCurrentScript == HB_SCRIPT_COMMON) {
383 }
else if (
script == HB_SCRIPT_INHERITED ||
script == HB_SCRIPT_COMMON) {
391 if (fCurrentScript == HB_SCRIPT_INHERITED) {
392 fCurrentScript = HB_SCRIPT_COMMON;
396 return fCurrent - fBegin;
398 bool atEnd()
const override {
399 return fCurrent == fEnd;
406 char const * fCurrent;
407 char const *
const fBegin;
408 char const *
const fEnd;
409 hb_script_t fCurrentScript;
412class RunIteratorQueue {
415 fEntries.insert({runIterator, priority});
420 if (leastRun->
atEnd()) {
427 while ((currentRun = fEntries.peek().runIterator)->endOfCurrentRun() <= leastEnd) {
428 int priority = fEntries.peek().priority;
432 SkASSERT(previousEndOfCurrentRun < currentRun->endOfCurrentRun());
433 fEntries.insert({currentRun, priority});
438 size_t endOfCurrentRun()
const {
439 return fEntries.peek().runIterator->endOfCurrentRun();
443 bool allRunsAreAtEnd()
const {
444 for (
int i = 0;
i < fEntries.count(); ++
i) {
445 if (!fEntries.at(
i).runIterator->atEnd()) {
456 static bool CompareEntry(
Entry const&
a,
Entry const&
b) {
457 size_t aEnd =
a.runIterator->endOfCurrentRun();
458 size_t bEnd =
b.runIterator->endOfCurrentRun();
459 return aEnd < bEnd || (aEnd == bEnd &&
a.priority <
b.priority);
469 bool fMayLineBreakBefore;
470 bool fMustLineBreakBefore;
472 bool fGraphemeBreakBefore;
477 std::unique_ptr<ShapedGlyph[]>
glyphs,
size_t numGlyphs,
SkVector advance = {0, 0})
478 : fUtf8Range(utf8Range), fFont(
font), fLevel(
level)
479 , fGlyphs(std::move(
glyphs)), fNumGlyphs(numGlyphs), fAdvance(advance)
485 std::unique_ptr<ShapedGlyph[]> fGlyphs;
503 return (
level & 1) == 0;
507 const ShapedRun&
run,
size_t startGlyphIndex,
size_t endGlyphIndex) {
508 SkASSERT(startGlyphIndex <= endGlyphIndex);
509 const size_t glyphLen = endGlyphIndex - startGlyphIndex;
516 for (
size_t i = 0;
i < glyphLen;
i++) {
518 const ShapedGlyph& glyph =
run.fGlyphs[is_LTR(
run.fLevel) ? startGlyphIndex +
i
519 : endGlyphIndex - 1 -
i];
523 buffer.offsets[
i] = glyph.fOffset;
525 buffer.positions[
i] = advance +
buffer.point + glyph.fOffset;
528 buffer.clusters[
i] = glyph.fCluster;
530 advance += glyph.fAdvance;
539 int numRuns =
line.runs.size();
541 for (
int i = 0;
i < numRuns; ++
i) {
542 runLevels[
i] =
line.runs[
i].fLevel;
545 unicode->reorderVisual(runLevels, numRuns, logicalFromVisual);
547 for (
int i = 0;
i < numRuns; ++
i) {
548 int logicalIndex = logicalFromVisual[
i];
550 const auto&
run =
line.runs[logicalIndex];
561 for (
int i = 0;
i < numRuns; ++
i) {
562 int logicalIndex = logicalFromVisual[
i];
564 const auto&
run =
line.runs[logicalIndex];
578struct ShapedRunGlyphIterator {
580 : fRuns(&origRuns), fRunIndex(0), fGlyphIndex(0)
583 ShapedRunGlyphIterator(
const ShapedRunGlyphIterator& that) =
default;
584 ShapedRunGlyphIterator& operator=(
const ShapedRunGlyphIterator& that) =
default;
585 bool operator==(
const ShapedRunGlyphIterator& that)
const {
586 return fRuns == that.fRuns &&
587 fRunIndex == that.fRunIndex &&
588 fGlyphIndex == that.fGlyphIndex;
590 bool operator!=(
const ShapedRunGlyphIterator& that)
const {
591 return fRuns != that.fRuns ||
592 fRunIndex != that.fRunIndex ||
593 fGlyphIndex != that.fGlyphIndex;
596 ShapedGlyph*
next() {
599 SkASSERT(fGlyphIndex < runs[fRunIndex].fNumGlyphs);
602 if (fGlyphIndex == runs[fRunIndex].fNumGlyphs) {
605 if (fRunIndex >= runs.
size()) {
609 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
612 ShapedGlyph* current() {
614 if (fRunIndex >= runs.
size()) {
617 return &runs[fRunIndex].fGlyphs[fGlyphIndex];
625class ShaperHarfBuzz :
public SkShaper {
634 ShapedRun
shape(
const char*
utf8,
size_t utf8Bytes,
635 const char* utf8Start,
637 const BiDiRunIterator&,
638 const LanguageRunIterator&,
640 const FontRunIterator&,
641 const Feature*,
size_t featuresSize)
const;
645 hb_language_t fUndefinedLanguage;
647#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
648 void shape(
const char*
utf8,
size_t utf8Bytes,
652 RunHandler*)
const override;
654 void shape(
const char* utf8Text,
size_t textBytes,
658 LanguageRunIterator&,
660 RunHandler*)
const override;
663 void shape(
const char* utf8Text,
size_t textBytes,
667 LanguageRunIterator&,
668 const Feature*,
size_t featuresSize,
670 RunHandler*)
const override;
672 virtual void wrap(
char const *
const utf8,
size_t utf8Bytes,
673 const BiDiRunIterator&,
674 const LanguageRunIterator&,
676 const FontRunIterator&,
677 RunIteratorQueue& runSegmenter,
678 const Feature*,
size_t featuresSize,
680 RunHandler*)
const = 0;
685 using ShaperHarfBuzz::ShaperHarfBuzz;
687 void wrap(
char const *
const utf8,
size_t utf8Bytes,
688 const BiDiRunIterator&,
689 const LanguageRunIterator&,
691 const FontRunIterator&,
692 RunIteratorQueue& runSegmenter,
693 const Feature*,
size_t featuresSize,
695 RunHandler*)
const override;
700 using ShaperHarfBuzz::ShaperHarfBuzz;
702 void wrap(
char const *
const utf8,
size_t utf8Bytes,
703 const BiDiRunIterator&,
704 const LanguageRunIterator&,
706 const FontRunIterator&,
707 RunIteratorQueue& runSegmenter,
708 const Feature*,
size_t featuresSize,
710 RunHandler*)
const override;
715 using ShaperHarfBuzz::ShaperHarfBuzz;
717 void wrap(
char const *
const utf8,
size_t utf8Bytes,
718 const BiDiRunIterator&,
719 const LanguageRunIterator&,
721 const FontRunIterator&,
722 RunIteratorQueue& runSegmenter,
723 const Feature*,
size_t featuresSize,
725 RunHandler*)
const override;
734 , fUndefinedLanguage(hb_language_from_string(
"und", -1)) {
735#if defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
740#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
741void ShaperHarfBuzz::shape(
const char*
utf8,
746 RunHandler* handler)
const {
748 std::unique_ptr<BiDiRunIterator> bidi(
755 std::unique_ptr<LanguageRunIterator> language(MakeStdLanguageRunIterator(
utf8, utf8Bytes));
765 std::unique_ptr<FontRunIterator>
font(
766 MakeFontMgrRunIterator(
utf8, utf8Bytes, srcFont, fFontMgr));
774void ShaperHarfBuzz::shape(
const char*
utf8,
776 FontRunIterator&
font,
777 BiDiRunIterator& bidi,
779 LanguageRunIterator& language,
781 RunHandler* handler)
const {
786void ShaperHarfBuzz::shape(
const char*
utf8,
788 FontRunIterator&
font,
789 BiDiRunIterator& bidi,
791 LanguageRunIterator& language,
792 const Feature* features,
795 RunHandler* handler)
const {
797 RunIteratorQueue runSegmenter;
798 runSegmenter.insert(&
font, 3);
799 runSegmenter.insert(&bidi, 2);
800 runSegmenter.insert(&
script, 1);
801 runSegmenter.insert(&language, 0);
803 this->wrap(
utf8, utf8Bytes, bidi, language,
script,
font, runSegmenter,
804 features, featuresSize,
width, handler);
807void ShaperDrivenWrapper::wrap(
char const *
const utf8,
size_t utf8Bytes,
808 const BiDiRunIterator& bidi,
809 const LanguageRunIterator& language,
811 const FontRunIterator&
font,
812 RunIteratorQueue& runSegmenter,
813 const Feature* features,
size_t featuresSize,
815 RunHandler* handler)
const
819 const char* utf8Start =
nullptr;
820 const char* utf8End =
utf8;
821 SkUnicodeBreak lineBreakIterator;
823 while (runSegmenter.advanceRuns()) {
825 utf8End =
utf8 + runSegmenter.endOfCurrentRun();
827 ShapedRun model(RunHandler::Range(),
SkFont(), 0,
nullptr, 0);
828 bool modelNeedsRegenerated =
true;
829 int modelGlyphOffset = 0;
836 std::unique_ptr<TextProps[]> modelText;
837 int modelTextOffset = 0;
838 SkVector modelAdvanceOffset = {0, 0};
840 while (utf8Start < utf8End) {
841 size_t utf8runLength = utf8End - utf8Start;
842 if (modelNeedsRegenerated) {
843 model = shape(
utf8, utf8Bytes,
846 features, featuresSize);
847 modelGlyphOffset = 0;
850 modelText = std::make_unique<TextProps[]>(utf8runLength + 1);
851 size_t modelStartCluster = utf8Start -
utf8;
852 size_t previousCluster = 0;
853 for (
size_t i = 0;
i < model.fNumGlyphs; ++
i) {
854 SkASSERT(modelStartCluster <= model.fGlyphs[
i].fCluster);
855 SkASSERT( model.fGlyphs[
i].fCluster < (
size_t)(utf8End -
utf8));
856 if (!model.fGlyphs[
i].fUnsafeToBreak) {
858 size_t currentCluster = model.fGlyphs[
i].fCluster - modelStartCluster;
859 if (previousCluster != currentCluster) {
860 previousCluster = currentCluster;
861 modelText[currentCluster].glyphLen =
i;
862 modelText[currentCluster].advance = advance;
865 advance += model.fGlyphs[
i].fAdvance;
868 modelText[utf8runLength].glyphLen = model.fNumGlyphs;
869 modelText[utf8runLength].advance = model.fAdvance;
871 modelAdvanceOffset = {0, 0};
872 modelNeedsRegenerated =
false;
877 if (!lineBreakIterator || !currentLanguage.
equals(language.currentLanguage())) {
878 currentLanguage = language.currentLanguage();
879 lineBreakIterator = fUnicode->makeBreakIterator(currentLanguage.
c_str(),
881 if (!lineBreakIterator) {
885 if (!lineBreakIterator->setText(utf8Start, utf8runLength)) {
890 ShapedRun best(RunHandler::Range(),
SkFont(), 0,
nullptr, 0,
892 bool bestIsInvalid =
true;
893 bool bestUsesModelForGlyphs =
false;
896 for (int32_t breakIteratorCurrent = breakIterator.
next();
898 breakIteratorCurrent = breakIterator.
next())
903 bool candidateUsesModelForGlyphs =
false;
904 ShapedRun candidate = [&](
const TextProps& props){
905 if (props.glyphLen) {
906 candidateUsesModelForGlyphs =
true;
907 return ShapedRun(RunHandler::Range(utf8Start -
utf8, breakIteratorCurrent),
908 font.currentFont(), bidi.currentLevel(),
909 std::unique_ptr<ShapedGlyph[]>(),
910 props.glyphLen - modelGlyphOffset,
911 props.advance - modelAdvanceOffset);
913 return shape(
utf8, utf8Bytes,
914 utf8Start, utf8Start + breakIteratorCurrent,
916 features, featuresSize);
918 }(modelText[breakIteratorCurrent + modelTextOffset]);
919 auto score = [widthLeft](
const ShapedRun&
run) ->
SkScalar {
920 if (
run.fAdvance.fX < widthLeft) {
921 return run.fUtf8Range.size();
923 return widthLeft -
run.fAdvance.fX;
926 if (bestIsInvalid || score(best) < score(candidate)) {
927 best = std::move(candidate);
928 bestIsInvalid =
false;
929 bestUsesModelForGlyphs = candidateUsesModelForGlyphs;
934 if (
width <
line.fAdvance.fX + best.fAdvance.fX && !
line.runs.empty()) {
935 emit(fUnicode.get(),
line, handler);
937 line.fAdvance = {0, 0};
939 if (bestUsesModelForGlyphs) {
940 best.fGlyphs = std::make_unique<ShapedGlyph[]>(best.fNumGlyphs);
941 memcpy(best.fGlyphs.get(), model.fGlyphs.get() + modelGlyphOffset,
942 best.fNumGlyphs *
sizeof(ShapedGlyph));
943 modelGlyphOffset += best.fNumGlyphs;
944 modelTextOffset += best.fUtf8Range.size();
945 modelAdvanceOffset += best.fAdvance;
947 modelNeedsRegenerated =
true;
949 utf8Start += best.fUtf8Range.size();
950 line.fAdvance += best.fAdvance;
951 line.runs.emplace_back(std::move(best));
954 if (utf8Start != utf8End) {
955 emit(fUnicode.get(),
line, handler);
957 line.fAdvance = {0, 0};
962 emit(fUnicode.get(),
line, handler);
965void ShapeThenWrap::wrap(
char const *
const utf8,
size_t utf8Bytes,
966 const BiDiRunIterator& bidi,
967 const LanguageRunIterator& language,
969 const FontRunIterator&
font,
970 RunIteratorQueue& runSegmenter,
971 const Feature* features,
size_t featuresSize,
973 RunHandler* handler)
const
978 SkUnicodeBreak lineBreakIterator;
979 SkUnicodeBreak graphemeBreakIterator;
980 bool needIteratorInit =
true;
981 const char* utf8Start =
nullptr;
982 const char* utf8End =
utf8;
983 while (runSegmenter.advanceRuns()) {
985 utf8End =
utf8 + runSegmenter.endOfCurrentRun();
990 features, featuresSize));
993 if (needIteratorInit || !currentLanguage.
equals(language.currentLanguage())) {
994 currentLanguage = language.currentLanguage();
995 lineBreakIterator = fUnicode->makeBreakIterator(currentLanguage.
c_str(),
997 if (!lineBreakIterator) {
1000 graphemeBreakIterator = fUnicode->makeBreakIterator(currentLanguage.
c_str(),
1002 if (!graphemeBreakIterator) {
1005 needIteratorInit =
false;
1007 size_t utf8runLength = utf8End - utf8Start;
1008 if (!lineBreakIterator->setText(utf8Start, utf8runLength)) {
1011 if (!graphemeBreakIterator->setText(utf8Start, utf8runLength)) {
1015 uint32_t previousCluster = 0xFFFFFFFF;
1016 for (
size_t i = 0;
i <
run.fNumGlyphs; ++
i) {
1017 ShapedGlyph& glyph =
run.fGlyphs[
i];
1018 int32_t glyphCluster = glyph.fCluster;
1020 int32_t lineBreakIteratorCurrent = lineBreakIterator->current();
1021 while (!lineBreakIterator->isDone() && lineBreakIteratorCurrent < glyphCluster)
1023 lineBreakIteratorCurrent = lineBreakIterator->next();
1025 glyph.fMayLineBreakBefore = glyph.fCluster != previousCluster &&
1026 lineBreakIteratorCurrent == glyphCluster;
1028 int32_t graphemeBreakIteratorCurrent = graphemeBreakIterator->current();
1029 while (!graphemeBreakIterator->isDone() && graphemeBreakIteratorCurrent < glyphCluster)
1031 graphemeBreakIteratorCurrent = graphemeBreakIterator->next();
1033 glyph.fGraphemeBreakBefore = glyph.fCluster != previousCluster &&
1034 graphemeBreakIteratorCurrent == glyphCluster;
1036 previousCluster = glyph.fCluster;
1044 ShapedRunGlyphIterator beginning(runs);
1047 ShapedRunGlyphIterator candidateLineBreak(runs);
1048 SkScalar candidateLineBreakWidth = 0;
1051 ShapedRunGlyphIterator candidateGraphemeBreak(runs);
1052 SkScalar candidateGraphemeBreakWidth = 0;
1055 ShapedRunGlyphIterator current(runs);
1057 while (ShapedGlyph* glyph = current.current()) {
1060 if (current != beginning) {
1061 if (glyph->fGraphemeBreakBefore || glyph->fMayLineBreakBefore) {
1064 candidateGraphemeBreak = current;
1065 candidateGraphemeBreakWidth = currentWidth;
1066 if (glyph->fMayLineBreakBefore) {
1067 candidateLineBreak = current;
1068 candidateLineBreakWidth = currentWidth;
1073 SkScalar glyphWidth = glyph->fAdvance.fX;
1075 if (width < currentWidth + glyphWidth && glyph->fHasVisual && candidateGraphemeBreakWidth > 0){
1076 if (candidateLineBreak != beginning) {
1077 beginning = candidateLineBreak;
1078 currentWidth -= candidateLineBreakWidth;
1079 candidateGraphemeBreakWidth -= candidateLineBreakWidth;
1080 candidateLineBreakWidth = 0;
1081 }
else if (candidateGraphemeBreak != beginning) {
1082 beginning = candidateGraphemeBreak;
1083 candidateLineBreak = beginning;
1084 currentWidth -= candidateGraphemeBreakWidth;
1085 candidateGraphemeBreakWidth = 0;
1086 candidateLineBreakWidth = 0;
1091 if (
width < currentWidth) {
1092 if (
width < candidateGraphemeBreakWidth) {
1093 candidateGraphemeBreak = candidateLineBreak;
1094 candidateGraphemeBreakWidth = candidateLineBreakWidth;
1096 current = candidateGraphemeBreak;
1097 currentWidth = candidateGraphemeBreakWidth;
1100 glyph = beginning.current();
1102 glyph->fMustLineBreakBefore =
true;
1107 currentWidth += glyphWidth;
1114 ShapedRunGlyphIterator previousBreak(runs);
1115 ShapedRunGlyphIterator glyphIterator(runs);
1116 int previousRunIndex = -1;
1117 while (glyphIterator.current()) {
1118 const ShapedRunGlyphIterator current = glyphIterator;
1119 ShapedGlyph* nextGlyph = glyphIterator.next();
1121 if (previousRunIndex != current.fRunIndex) {
1123 runs[current.fRunIndex].fFont.getMetrics(&metrics);
1124 previousRunIndex = current.fRunIndex;
1128 if (!(nextGlyph ==
nullptr || nextGlyph->fMustLineBreakBefore)) {
1132 int numRuns = current.fRunIndex - previousBreak.fRunIndex + 1;
1134 for (
int i = 0;
i < numRuns; ++
i) {
1135 runLevels[
i] = runs[previousBreak.fRunIndex +
i].fLevel;
1138 fUnicode->reorderVisual(runLevels, numRuns, logicalFromVisual);
1143 handler->beginLine();
1145 struct SubRun {
const ShapedRun&
run;
size_t startGlyphIndex;
size_t endGlyphIndex; };
1146 auto makeSubRun = [&runs, &previousBreak, ¤t, &logicalFromVisual](
size_t visualIndex){
1147 int logicalIndex = previousBreak.fRunIndex + logicalFromVisual[visualIndex];
1148 const auto&
run = runs[logicalIndex];
1149 size_t startGlyphIndex = (logicalIndex == previousBreak.fRunIndex)
1150 ? previousBreak.fGlyphIndex
1152 size_t endGlyphIndex = (logicalIndex == current.fRunIndex)
1153 ? current.fGlyphIndex + 1
1155 return SubRun{
run, startGlyphIndex, endGlyphIndex };
1157 auto makeRunInfo = [](
const SubRun& sub) {
1158 uint32_t startUtf8 = sub.run.fGlyphs[sub.startGlyphIndex].fCluster;
1159 uint32_t endUtf8 = (sub.endGlyphIndex < sub.run.fNumGlyphs)
1160 ? sub.run.fGlyphs[sub.endGlyphIndex].fCluster
1161 : sub.run.fUtf8Range.end();
1164 for (
size_t i = sub.startGlyphIndex;
i < sub.endGlyphIndex; ++
i) {
1165 advance += sub.run.fGlyphs[
i].fAdvance;
1168 return RunHandler::RunInfo{
1172 sub.endGlyphIndex - sub.startGlyphIndex,
1173 RunHandler::Range(startUtf8, endUtf8 - startUtf8)
1177 for (
int i = 0;
i < numRuns; ++
i) {
1178 handler->runInfo(makeRunInfo(makeSubRun(
i)));
1180 handler->commitRunInfo();
1181 for (
int i = 0;
i < numRuns; ++
i) {
1182 SubRun sub = makeSubRun(
i);
1183 append(handler, makeRunInfo(sub), sub.run, sub.startGlyphIndex, sub.endGlyphIndex);
1186 handler->commitLine();
1188 previousRunIndex = -1;
1189 previousBreak = glyphIterator;
1194void ShapeDontWrapOrReorder::wrap(
char const *
const utf8,
size_t utf8Bytes,
1195 const BiDiRunIterator& bidi,
1196 const LanguageRunIterator& language,
1198 const FontRunIterator&
font,
1199 RunIteratorQueue& runSegmenter,
1200 const Feature* features,
size_t featuresSize,
1202 RunHandler* handler)
const
1207 const char* utf8Start =
nullptr;
1208 const char* utf8End =
utf8;
1209 while (runSegmenter.advanceRuns()) {
1210 utf8Start = utf8End;
1211 utf8End =
utf8 + runSegmenter.endOfCurrentRun();
1216 features, featuresSize));
1219 handler->beginLine();
1220 for (
const auto&
run : runs) {
1221 const RunHandler::RunInfo
info = {
1228 handler->runInfo(
info);
1230 handler->commitRunInfo();
1231 for (
const auto&
run : runs) {
1232 const RunHandler::RunInfo
info = {
1241 handler->commitLine();
1244class HBLockedFaceCache {
1247 : fLRUCache(lruCache), fMutex(mutex)
1251 HBLockedFaceCache(
const HBLockedFaceCache&) =
delete;
1252 HBLockedFaceCache& operator=(
const HBLockedFaceCache&) =
delete;
1253 HBLockedFaceCache& operator=(HBLockedFaceCache&&) =
delete;
1255 ~HBLockedFaceCache() {
1260 return fLRUCache.find(fontId);
1263 return fLRUCache.insert(fontId, std::move(hbFont));
1272static HBLockedFaceCache get_hbFace_cache() {
1273 static SkMutex gHBFaceCacheMutex;
1275 return HBLockedFaceCache(gHBFaceCache, gHBFaceCacheMutex);
1278ShapedRun ShaperHarfBuzz::shape(
char const *
const utf8,
1279 size_t const utf8Bytes,
1280 char const *
const utf8Start,
1281 char const *
const utf8End,
1282 const BiDiRunIterator& bidi,
1283 const LanguageRunIterator& language,
1285 const FontRunIterator&
font,
1286 Feature
const *
const features,
size_t const featuresSize)
const
1288 size_t utf8runLength = utf8End - utf8Start;
1289 ShapedRun
run(RunHandler::Range(utf8Start -
utf8, utf8runLength),
1290 font.currentFont(), bidi.currentLevel(),
nullptr, 0);
1292 hb_buffer_t*
buffer = fBuffer.get();
1294 hb_buffer_set_content_type(
buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
1295 hb_buffer_set_cluster_level(
buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
1306 const char* utf8Current = utf8Start;
1307 while (utf8Current < utf8End) {
1308 unsigned int cluster = utf8Current -
utf8;
1309 hb_codepoint_t u =
utf8_next(&utf8Current, utf8End);
1310 hb_buffer_add(
buffer, u, cluster);
1314 hb_buffer_add_utf8(
buffer, utf8Current,
utf8 + utf8Bytes - utf8Current, 0, 0);
1316 hb_direction_t direction = is_LTR(bidi.currentLevel()) ? HB_DIRECTION_LTR:HB_DIRECTION_RTL;
1317 hb_buffer_set_direction(
buffer, direction);
1318 hb_buffer_set_script(
buffer, hb_script_from_iso15924_tag((hb_tag_t)
script.currentScript()));
1322 hb_language_t hbLanguage = hb_language_from_string(language.currentLanguage(), -1);
1323 if (hbLanguage == HB_LANGUAGE_INVALID) {
1324 hbLanguage = fUndefinedLanguage;
1326 hb_buffer_set_language(
buffer, hbLanguage);
1327 hb_buffer_guess_segment_properties(
buffer);
1336 HBLockedFaceCache
cache = get_hbFace_cache();
1338 HBFont* typefaceFontCached =
cache.find(dataId);
1339 if (!typefaceFontCached) {
1340 HBFont typefaceFont(create_typeface_hb_font(*
font.currentFont().getTypeface()));
1341 typefaceFontCached =
cache.insert(dataId, std::move(typefaceFont));
1343 hbFont = create_sub_hb_font(
font.currentFont(), *typefaceFontCached);
1350 for (
const auto& feature :
SkSpan(features, featuresSize)) {
1351 if (feature.end < SkTo<size_t>(utf8Start -
utf8) ||
1352 SkTo<size_t>(utf8End -
utf8) <= feature.start)
1356 if (feature.start <= SkTo<size_t>(utf8Start -
utf8) &&
1357 SkTo<size_t>(utf8End -
utf8) <= feature.end)
1359 hbFeatures.
push_back({ (hb_tag_t)feature.tag, feature.value,
1362 hbFeatures.
push_back({ (hb_tag_t)feature.tag, feature.value,
1363 SkTo<unsigned>(feature.start), SkTo<unsigned>(feature.end)});
1367 hb_shape(hbFont.get(),
buffer, hbFeatures.
data(), hbFeatures.
size());
1368 unsigned len = hb_buffer_get_length(
buffer);
1373 if (direction == HB_DIRECTION_RTL) {
1376 hb_buffer_reverse(
buffer);
1378 hb_glyph_info_t*
info = hb_buffer_get_glyph_infos(
buffer,
nullptr);
1379 hb_glyph_position_t*
pos = hb_buffer_get_glyph_positions(
buffer,
nullptr);
1381 run = ShapedRun(RunHandler::Range(utf8Start -
utf8, utf8runLength),
1382 font.currentFont(), bidi.currentLevel(),
1383 std::unique_ptr<ShapedGlyph[]>(
new ShapedGlyph[
len]),
len);
1387 for (
unsigned i = 0;
i <
len;
i++) {
1388 glyphIDs[
i] =
info[
i].codepoint;
1392 run.fFont.getBounds(glyphIDs.get(),
len, glyphBounds.get(), &
p);
1394 double SkScalarFromHBPosX = +(1.52587890625e-5) *
run.fFont.getScaleX();
1395 double SkScalarFromHBPosY = -(1.52587890625e-5);
1397 for (
unsigned i = 0;
i <
len;
i++) {
1398 ShapedGlyph& glyph =
run.fGlyphs[
i];
1399 glyph.fID =
info[
i].codepoint;
1400 glyph.fCluster =
info[
i].cluster;
1401 glyph.fOffset.fX =
pos[
i].x_offset * SkScalarFromHBPosX;
1402 glyph.fOffset.
fY =
pos[
i].y_offset * SkScalarFromHBPosY;
1403 glyph.fAdvance.
fX =
pos[
i].x_advance * SkScalarFromHBPosX;
1404 glyph.fAdvance.
fY =
pos[
i].y_advance * SkScalarFromHBPosY;
1406 glyph.fHasVisual = !glyphBounds[
i].isEmpty();
1407#if SK_HB_VERSION_CHECK(1, 5, 0)
1408 glyph.fUnsafeToBreak =
info[
i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
1410 glyph.fUnsafeToBreak =
false;
1412 glyph.fMustLineBreakBefore =
false;
1414 runAdvance += glyph.fAdvance;
1416 run.fAdvance = runAdvance;
1422#if !defined(SK_DISABLE_LEGACY_SKSHAPER_FUNCTIONS)
1424#if defined(SK_UNICODE_ICU_IMPLEMENTATION)
1428#if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
1432#if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
1437#if defined(SK_UNICODE_ICU_IMPLEMENTATION)
1442#if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
1447#if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
1455std::unique_ptr<SkShaper::ScriptRunIterator>
1456SkShaper::MakeHbIcuScriptRunIterator(
const char*
utf8,
size_t utf8Bytes) {
1460std::unique_ptr<SkShaper::ScriptRunIterator>
1461SkShaper::MakeSkUnicodeHbScriptRunIterator(
const char*
utf8,
size_t utf8Bytes) {
1465std::unique_ptr<SkShaper::ScriptRunIterator> SkShaper::MakeSkUnicodeHbScriptRunIterator(
1470std::unique_ptr<SkShaper> SkShaper::MakeShaperDrivenWrapper(
sk_sp<SkFontMgr> fontmgr) {
1474std::unique_ptr<SkShaper> SkShaper::MakeShapeThenWrap(
sk_sp<SkFontMgr> fontmgr) {
1487 HBBuffer
buffer(hb_buffer_create());
1489 SkDEBUGF(
"Could not create hb_buffer");
1492 return std::make_unique<::ShaperDrivenWrapper>(
1501 HBBuffer
buffer(hb_buffer_create());
1503 SkDEBUGF(
"Could not create hb_buffer");
1506 return std::make_unique<::ShapeThenWrap>(
1515 HBBuffer
buffer(hb_buffer_create());
1517 SkDEBUGF(
"Could not create hb_buffer");
1520 return std::make_unique<::ShapeDontWrapOrReorder>(
1525 return std::make_unique<SkUnicodeHbScriptRunIterator>(
utf8, utf8Bytes, HB_SCRIPT_UNKNOWN);
1530 return std::make_unique<SkUnicodeHbScriptRunIterator>(
1531 utf8, utf8Bytes, hb_script_from_iso15924_tag((hb_tag_t)
script));
1535 HBLockedFaceCache
cache = get_hbFace_cache();
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static float next(float f)
static float prev(float f)
#define SK_ABORT(message,...)
@ kUTF32
uses four byte words to represent all of Unicode
SK_API void sk_free(void *)
static void * sk_malloc_throw(size_t size)
static void SkSafeUnref(T *obj)
#define SkScalarRoundToInt(x)
#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
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
void sk_ignore_unused_variable(const T &)
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
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
T & emplace_back(Args &&... args)
static void append(char **dst, size_t *count, const char *src, size_t n)
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 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 buffer
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
bool operator==(C p1, const scoped_nsprotocol< C > &p2)
bool operator!=(C p1, const scoped_nsprotocol< C > &p2)
font
Font Metadata and Metrics.
static constexpr SkPoint Make(float x, float y)
SkScalar fLeft
smaller x-axis bounds
void roundOut(SkIRect *dst) const
constexpr float height() const
constexpr float width() const
void set(const SkIRect &src)
SkScalar fTop
smaller y-axis bounds
std::shared_ptr< const fml::Mapping > data