• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "Minikin"
18 
19 #include "minikin/FontCollection.h"
20 
21 #include <algorithm>
22 
23 #include <log/log.h>
24 #include <unicode/unorm2.h>
25 
26 #include "minikin/Emoji.h"
27 #include "minikin/FontFileParser.h"
28 
29 #include "Locale.h"
30 #include "LocaleListCache.h"
31 #include "MinikinInternal.h"
32 
33 using std::vector;
34 
35 namespace minikin {
36 
37 template <typename T>
max(T a,T b)38 static inline T max(T a, T b) {
39     return a > b ? a : b;
40 }
41 
42 const uint32_t EMOJI_STYLE_VS = 0xFE0F;
43 const uint32_t TEXT_STYLE_VS = 0xFE0E;
44 
45 static std::atomic<uint32_t> gNextCollectionId = {0};
46 
47 namespace {
48 
getGlyphCount(U16StringPiece text,uint32_t start,uint32_t end,const HbFontUniquePtr & font)49 uint32_t getGlyphCount(U16StringPiece text, uint32_t start, uint32_t end,
50                        const HbFontUniquePtr& font) {
51     HbBufferUniquePtr buffer(hb_buffer_create());
52     hb_buffer_set_direction(buffer.get(), HB_DIRECTION_LTR);
53     hb_buffer_add_utf16(buffer.get(), text.data() + start, end - start, 0, end - start);
54     hb_buffer_guess_segment_properties(buffer.get());
55 
56     unsigned int numGlyphs = -1;
57     hb_shape(font.get(), buffer.get(), nullptr, 0);
58     hb_buffer_get_glyph_infos(buffer.get(), &numGlyphs);
59     return numGlyphs;
60 }
61 
62 }  // namespace
63 
FontCollection(std::shared_ptr<FontFamily> && typeface)64 FontCollection::FontCollection(std::shared_ptr<FontFamily>&& typeface) : mMaxChar(0) {
65     std::vector<std::shared_ptr<FontFamily>> typefaces;
66     typefaces.push_back(typeface);
67     init(typefaces);
68 }
69 
FontCollection(const vector<std::shared_ptr<FontFamily>> & typefaces)70 FontCollection::FontCollection(const vector<std::shared_ptr<FontFamily>>& typefaces) : mMaxChar(0) {
71     init(typefaces);
72 }
73 
init(const vector<std::shared_ptr<FontFamily>> & typefaces)74 void FontCollection::init(const vector<std::shared_ptr<FontFamily>>& typefaces) {
75     mId = gNextCollectionId++;
76     vector<uint32_t> lastChar;
77     size_t nTypefaces = typefaces.size();
78     const FontStyle defaultStyle;
79     for (size_t i = 0; i < nTypefaces; i++) {
80         const std::shared_ptr<FontFamily>& family = typefaces[i];
81         if (family->getClosestMatch(defaultStyle).font == nullptr) {
82             continue;
83         }
84         const SparseBitSet& coverage = family->getCoverage();
85         mFamilies.push_back(family);  // emplace_back would be better
86         if (family->hasVSTable()) {
87             mVSFamilyVec.push_back(family);
88         }
89         mMaxChar = max(mMaxChar, coverage.length());
90         lastChar.push_back(coverage.nextSetBit(0));
91 
92         const std::unordered_set<AxisTag>& supportedAxes = family->supportedAxes();
93         mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end());
94     }
95     nTypefaces = mFamilies.size();
96     MINIKIN_ASSERT(nTypefaces > 0, "Font collection must have at least one valid typeface");
97     MINIKIN_ASSERT(nTypefaces <= MAX_FAMILY_COUNT,
98                    "Font collection may only have up to %d font families.", MAX_FAMILY_COUNT);
99     size_t nPages = (mMaxChar + kPageMask) >> kLogCharsPerPage;
100     // TODO: Use variation selector map for mRanges construction.
101     // A font can have a glyph for a base code point and variation selector pair but no glyph for
102     // the base code point without variation selector. The family won't be listed in the range in
103     // this case.
104     mOwnedRanges = std::make_unique<Range[]>(nPages);
105     mRanges = mOwnedRanges.get();
106     mRangesCount = nPages;
107     for (size_t i = 0; i < nPages; i++) {
108         Range* range = &mOwnedRanges[i];
109         range->start = mOwnedFamilyVec.size();
110         for (size_t j = 0; j < nTypefaces; j++) {
111             if (lastChar[j] < (i + 1) << kLogCharsPerPage) {
112                 const std::shared_ptr<FontFamily>& family = mFamilies[j];
113                 mOwnedFamilyVec.push_back(static_cast<uint8_t>(j));
114                 uint32_t nextChar = family->getCoverage().nextSetBit((i + 1) << kLogCharsPerPage);
115                 lastChar[j] = nextChar;
116             }
117         }
118         range->end = mOwnedFamilyVec.size();
119     }
120     // See the comment in Range for more details.
121     LOG_ALWAYS_FATAL_IF(mOwnedFamilyVec.size() >= 0xFFFF,
122                         "Exceeded the maximum indexable cmap coverage.");
123     mFamilyVec = mOwnedFamilyVec.data();
124     mFamilyVecCount = mOwnedFamilyVec.size();
125 }
126 
FontCollection(BufferReader * reader,const std::vector<std::shared_ptr<FontFamily>> & families)127 FontCollection::FontCollection(BufferReader* reader,
128                                const std::vector<std::shared_ptr<FontFamily>>& families) {
129     mId = gNextCollectionId++;
130     mMaxChar = reader->read<uint32_t>();
131     uint32_t familiesCount = reader->read<uint32_t>();
132     mFamilies.reserve(familiesCount);
133     for (uint32_t i = 0; i < familiesCount; i++) {
134         uint32_t index = reader->read<uint32_t>();
135         if (index >= families.size()) {
136             ALOGE("Invalid FontFamily index: %zu", (size_t)index);
137         } else {
138             mFamilies.push_back(families[index]);
139             if (families[index]->hasVSTable()) {
140                 mVSFamilyVec.push_back(families[index]);
141             }
142         }
143     }
144     // Range is two packed uint16_t
145     static_assert(sizeof(Range) == 4);
146     std::tie(mRanges, mRangesCount) = reader->readArray<Range>();
147     std::tie(mFamilyVec, mFamilyVecCount) = reader->readArray<uint8_t>();
148     const auto& [axesPtr, axesCount] = reader->readArray<AxisTag>();
149     mSupportedAxes.insert(axesPtr, axesPtr + axesCount);
150 }
151 
writeTo(BufferWriter * writer,const std::unordered_map<std::shared_ptr<FontFamily>,uint32_t> & fontFamilyToIndexMap) const152 void FontCollection::writeTo(BufferWriter* writer,
153                              const std::unordered_map<std::shared_ptr<FontFamily>, uint32_t>&
154                                      fontFamilyToIndexMap) const {
155     writer->write<uint32_t>(mMaxChar);
156     writer->write<uint32_t>(mFamilies.size());
157     for (const std::shared_ptr<FontFamily>& fontFamily : mFamilies) {
158         auto it = fontFamilyToIndexMap.find(fontFamily);
159         if (it == fontFamilyToIndexMap.end()) {
160             ALOGE("fontFamily not found in fontFamilyToIndexMap");
161             writer->write<uint32_t>(-1);
162         } else {
163             writer->write<uint32_t>(it->second);
164         }
165     }
166     writer->writeArray<Range>(mRanges, mRangesCount);
167     writer->writeArray<uint8_t>(mFamilyVec, mFamilyVecCount);
168     // No need to serialize mVSFamilyVec as it can be reconstructed easily from mFamilies.
169     std::vector<AxisTag> axes(mSupportedAxes.begin(), mSupportedAxes.end());
170     // Sort axes to be deterministic.
171     std::sort(axes.begin(), axes.end());
172     writer->writeArray<AxisTag>(axes.data(), axes.size());
173 }
174 
175 // static
collectAllFontFamilies(const std::vector<std::shared_ptr<FontCollection>> & fontCollections,std::vector<std::shared_ptr<FontFamily>> * outAllFontFamilies,std::unordered_map<std::shared_ptr<FontFamily>,uint32_t> * outFontFamilyToIndexMap)176 void FontCollection::collectAllFontFamilies(
177         const std::vector<std::shared_ptr<FontCollection>>& fontCollections,
178         std::vector<std::shared_ptr<FontFamily>>* outAllFontFamilies,
179         std::unordered_map<std::shared_ptr<FontFamily>, uint32_t>* outFontFamilyToIndexMap) {
180     for (const auto& fontCollection : fontCollections) {
181         for (const std::shared_ptr<FontFamily>& fontFamily : fontCollection->mFamilies) {
182             bool inserted =
183                     outFontFamilyToIndexMap->emplace(fontFamily, outAllFontFamilies->size()).second;
184             if (inserted) {
185                 outAllFontFamilies->push_back(fontFamily);
186             }
187         }
188     }
189 }
190 
191 // Special scores for the font fallback.
192 const uint32_t kUnsupportedFontScore = 0;
193 const uint32_t kFirstFontScore = UINT32_MAX;
194 
195 // Calculates a font score.
196 // The score of the font family is based on three subscores.
197 //  - Coverage Score: How well the font family covers the given character or variation sequence.
198 //  - Locale Score: How well the font family is appropriate for the locale.
199 //  - Variant Score: Whether the font family matches the variant. Note that this variant is not the
200 //    one in BCP47. This is our own font variant (e.g., elegant, compact).
201 //
202 // Then, there is a priority for these three subscores as follow:
203 //   Coverage Score > Locale Score > Variant Score
204 // The returned score reflects this priority order.
205 //
206 // Note that there are two special scores.
207 //  - kUnsupportedFontScore: When the font family doesn't support the variation sequence or even its
208 //    base character.
209 //  - kFirstFontScore: When the font is the first font family in the collection and it supports the
210 //    given character or variation sequence.
calcFamilyScore(uint32_t ch,uint32_t vs,FamilyVariant variant,uint32_t localeListId,const std::shared_ptr<FontFamily> & fontFamily) const211 uint32_t FontCollection::calcFamilyScore(uint32_t ch, uint32_t vs, FamilyVariant variant,
212                                          uint32_t localeListId,
213                                          const std::shared_ptr<FontFamily>& fontFamily) const {
214     const uint32_t coverageScore = calcCoverageScore(ch, vs, localeListId, fontFamily);
215     if (coverageScore == kFirstFontScore || coverageScore == kUnsupportedFontScore) {
216         // No need to calculate other scores.
217         return coverageScore;
218     }
219 
220     const uint32_t localeScore = calcLocaleMatchingScore(localeListId, *fontFamily);
221     const uint32_t variantScore = calcVariantMatchingScore(variant, *fontFamily);
222 
223     // Subscores are encoded into 31 bits representation to meet the subscore priority.
224     // The highest 2 bits are for coverage score, then following 28 bits are for locale score,
225     // then the last 1 bit is for variant score.
226     return coverageScore << 29 | localeScore << 1 | variantScore;
227 }
228 
229 // Calculates a font score based on variation sequence coverage.
230 // - Returns kUnsupportedFontScore if the font doesn't support the variation sequence or its base
231 //   character.
232 // - Returns kFirstFontScore if the font family is the first font family in the collection and it
233 //   supports the given character or variation sequence.
234 // - Returns 3 if the font family supports the variation sequence.
235 // - Returns 2 if the vs is a color variation selector (U+FE0F) and if the font is an emoji font.
236 // - Returns 2 if the vs is a text variation selector (U+FE0E) and if the font is not an emoji font.
237 // - Returns 1 if the variation selector is not specified or if the font family only supports the
238 //   variation sequence's base character.
calcCoverageScore(uint32_t ch,uint32_t vs,uint32_t localeListId,const std::shared_ptr<FontFamily> & fontFamily) const239 uint32_t FontCollection::calcCoverageScore(uint32_t ch, uint32_t vs, uint32_t localeListId,
240                                            const std::shared_ptr<FontFamily>& fontFamily) const {
241     const bool hasVSGlyph = (vs != 0) && fontFamily->hasGlyph(ch, vs);
242     if (!hasVSGlyph && !fontFamily->getCoverage().get(ch)) {
243         // The font doesn't support either variation sequence or even the base character.
244         return kUnsupportedFontScore;
245     }
246 
247     if ((vs == 0 || hasVSGlyph) && (mFamilies[0] == fontFamily || fontFamily->isCustomFallback())) {
248         // If the first font family supports the given character or variation sequence, always use
249         // it.
250         return kFirstFontScore;
251     }
252 
253     if (vs != 0 && hasVSGlyph) {
254         return 3;
255     }
256 
257     bool colorEmojiRequest;
258     if (vs == EMOJI_STYLE_VS) {
259         colorEmojiRequest = true;
260     } else if (vs == TEXT_STYLE_VS) {
261         colorEmojiRequest = false;
262     } else {
263         switch (LocaleListCache::getById(localeListId).getEmojiStyle()) {
264             case EmojiStyle::EMOJI:
265                 colorEmojiRequest = true;
266                 break;
267             case EmojiStyle::TEXT:
268                 colorEmojiRequest = false;
269                 break;
270             case EmojiStyle::EMPTY:
271             case EmojiStyle::DEFAULT:
272             default:
273                 // Do not give any extra score for the default emoji style.
274                 return 1;
275                 break;
276         }
277     }
278 
279     return colorEmojiRequest == fontFamily->isColorEmojiFamily() ? 2 : 1;
280 }
281 
282 // Calculate font scores based on the script matching, subtag matching and primary locale matching.
283 //
284 // 1. If only the font's language matches or there is no matches between requested font and
285 //    supported font, then the font obtains a score of 0.
286 // 2. Without a match in language, considering subtag may change font's EmojiStyle over script,
287 //    a match in subtag gets a score of 2 and a match in scripts gains a score of 1.
288 // 3. Regarding to two elements matchings, language-and-subtag matching has a score of 4, while
289 //    language-and-script obtains a socre of 3 with the same reason above.
290 //
291 // If two locales in the requested list have the same locale score, the font matching with higher
292 // priority locale gets a higher score. For example, in the case the user requested locale list is
293 // "ja-Jpan,en-Latn". The score of for the font of "ja-Jpan" gets a higher score than the font of
294 // "en-Latn".
295 //
296 // To achieve score calculation with priorities, the locale score is determined as follows:
297 //   LocaleScore = s(0) * 5^(m - 1) + s(1) * 5^(m - 2) + ... + s(m - 2) * 5 + s(m - 1)
298 // Here, m is the maximum number of locales to be compared, and s(i) is the i-th locale's matching
299 // score. The possible values of s(i) are 0, 1, 2, 3 and 4.
calcLocaleMatchingScore(uint32_t userLocaleListId,const FontFamily & fontFamily)300 uint32_t FontCollection::calcLocaleMatchingScore(uint32_t userLocaleListId,
301                                                  const FontFamily& fontFamily) {
302     const LocaleList& localeList = LocaleListCache::getById(userLocaleListId);
303     const LocaleList& fontLocaleList = LocaleListCache::getById(fontFamily.localeListId());
304 
305     const size_t maxCompareNum = std::min(localeList.size(), FONT_LOCALE_LIMIT);
306     uint32_t score = 0;
307     for (size_t i = 0; i < maxCompareNum; ++i) {
308         score = score * 5u + localeList[i].calcScoreFor(fontLocaleList);
309     }
310     return score;
311 }
312 
313 // Calculates a font score based on variant ("compact" or "elegant") matching.
314 //  - Returns 1 if the font doesn't have variant or the variant matches with the text style.
315 //  - No score if the font has a variant but it doesn't match with the text style.
calcVariantMatchingScore(FamilyVariant variant,const FontFamily & fontFamily)316 uint32_t FontCollection::calcVariantMatchingScore(FamilyVariant variant,
317                                                   const FontFamily& fontFamily) {
318     const FamilyVariant familyVariant = fontFamily.variant();
319     if (familyVariant == FamilyVariant::DEFAULT) {
320         return 1;
321     }
322     if (familyVariant == variant) {
323         return 1;
324     }
325     if (variant == FamilyVariant::DEFAULT && familyVariant == FamilyVariant::COMPACT) {
326         // If default is requested, prefer compat variation.
327         return 1;
328     }
329     return 0;
330 }
331 
332 // Implement heuristic for choosing best-match font. Here are the rules:
333 // 1. If first font in the collection has the character, it wins.
334 // 2. Calculate a score for the font family. See comments in calcFamilyScore for the detail.
335 // 3. Highest score wins, with ties resolved to the first font.
336 // This method never returns nullptr.
getFamilyForChar(uint32_t ch,uint32_t vs,uint32_t localeListId,FamilyVariant variant) const337 FontCollection::FamilyMatchResult FontCollection::getFamilyForChar(uint32_t ch, uint32_t vs,
338                                                                    uint32_t localeListId,
339                                                                    FamilyVariant variant) const {
340     if (ch >= mMaxChar) {
341         return FamilyMatchResult::Builder().add(0).build();
342     }
343 
344     Range range = mRanges[ch >> kLogCharsPerPage];
345 
346     if (vs != 0) {
347         range = {0, static_cast<uint16_t>(mFamilies.size())};
348     }
349 
350     uint32_t bestScore = kUnsupportedFontScore;
351     FamilyMatchResult::Builder builder;
352 
353     for (size_t i = range.start; i < range.end; i++) {
354         const uint8_t familyIndex = vs == 0 ? mFamilyVec[i] : i;
355         const std::shared_ptr<FontFamily>& family = mFamilies[familyIndex];
356         const uint32_t score = calcFamilyScore(ch, vs, variant, localeListId, family);
357         if (score == kFirstFontScore) {
358             // If the first font family supports the given character or variation sequence, always
359             // use it.
360             return builder.add(familyIndex).build();
361         }
362         if (score != kUnsupportedFontScore && score >= bestScore) {
363             if (score > bestScore) {
364                 builder.reset();
365                 bestScore = score;
366             }
367             builder.add(familyIndex);
368         }
369     }
370     if (builder.empty()) {
371         UErrorCode errorCode = U_ZERO_ERROR;
372         const UNormalizer2* normalizer = unorm2_getNFDInstance(&errorCode);
373         if (U_SUCCESS(errorCode)) {
374             UChar decomposed[4];
375             int len = unorm2_getRawDecomposition(normalizer, ch, decomposed, 4, &errorCode);
376             if (U_SUCCESS(errorCode) && len > 0) {
377                 int off = 0;
378                 U16_NEXT_UNSAFE(decomposed, off, ch);
379                 return getFamilyForChar(ch, vs, localeListId, variant);
380             }
381         }
382         return FamilyMatchResult::Builder().add(0).build();
383     }
384     return builder.build();
385 }
386 
387 // Characters where we want to continue using existing font run for (or stick to the next run if
388 // they start a string), even if the font does not support them explicitly. These are handled
389 // properly by Minikin or HarfBuzz even if the font does not explicitly support them and it's
390 // usually meaningless to switch to a different font to display them.
doesNotNeedFontSupport(uint32_t c)391 static bool doesNotNeedFontSupport(uint32_t c) {
392     return c == 0x00AD                      // SOFT HYPHEN
393            || c == 0x034F                   // COMBINING GRAPHEME JOINER
394            || c == 0x061C                   // ARABIC LETTER MARK
395            || (0x200C <= c && c <= 0x200F)  // ZERO WIDTH NON-JOINER..RIGHT-TO-LEFT MARK
396            || (0x202A <= c && c <= 0x202E)  // LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
397            || (0x2066 <= c && c <= 0x2069)  // LEFT-TO-RIGHT ISOLATE..POP DIRECTIONAL ISOLATE
398            || c == 0xFEFF                   // BYTE ORDER MARK
399            || isVariationSelector(c);
400 }
401 
402 // Characters where we want to continue using existing font run instead of
403 // recomputing the best match in the fallback list.
404 static const uint32_t stickyAllowlist[] = {
405         '!',    ',', '-', '.', ':', ';', '?',
406         0x00A0,  // NBSP
407         0x2010,  // HYPHEN
408         0x2011,  // NB_HYPHEN
409         0x202F,  // NNBSP
410         0x2640,  // FEMALE_SIGN,
411         0x2642,  // MALE_SIGN,
412         0x2695,  // STAFF_OF_AESCULAPIUS
413 };
414 
isStickyAllowlisted(uint32_t c)415 static bool isStickyAllowlisted(uint32_t c) {
416     for (size_t i = 0; i < sizeof(stickyAllowlist) / sizeof(stickyAllowlist[0]); i++) {
417         if (stickyAllowlist[i] == c) return true;
418     }
419     return false;
420 }
421 
isCombining(uint32_t c)422 static inline bool isCombining(uint32_t c) {
423     return (U_GET_GC_MASK(c) & U_GC_M_MASK) != 0;
424 }
425 
hasVariationSelector(uint32_t baseCodepoint,uint32_t variationSelector) const426 bool FontCollection::hasVariationSelector(uint32_t baseCodepoint,
427                                           uint32_t variationSelector) const {
428     if (!isVariationSelector(variationSelector)) {
429         return false;
430     }
431     if (baseCodepoint >= mMaxChar) {
432         return false;
433     }
434 
435     // Currently mRanges can not be used here since it isn't aware of the variation sequence.
436     for (size_t i = 0; i < mVSFamilyVec.size(); i++) {
437         if (mVSFamilyVec[i]->hasGlyph(baseCodepoint, variationSelector)) {
438             return true;
439         }
440     }
441 
442     // Even if there is no cmap format 14 subtable entry for the given sequence, should return true
443     // for <char, text presentation selector> case since we have special fallback rule for the
444     // sequence. Note that we don't need to restrict this to already standardized variation
445     // sequences, since Unicode is adding variation sequences more frequently now and may even move
446     // towards allowing text and emoji variation selectors on any character.
447     if (variationSelector == TEXT_STYLE_VS) {
448         for (size_t i = 0; i < mFamilies.size(); ++i) {
449             if (!mFamilies[i]->isColorEmojiFamily() && mFamilies[i]->hasGlyph(baseCodepoint, 0)) {
450                 return true;
451             }
452         }
453     }
454 
455     return false;
456 }
457 
458 constexpr uint32_t REPLACEMENT_CHARACTER = 0xFFFD;
459 
intersect(FontCollection::FamilyMatchResult l,FontCollection::FamilyMatchResult r)460 FontCollection::FamilyMatchResult FontCollection::FamilyMatchResult::intersect(
461         FontCollection::FamilyMatchResult l, FontCollection::FamilyMatchResult r) {
462     if (l == r) {
463         return l;
464     }
465 
466     uint32_t li = 0;
467     uint32_t ri = 0;
468     FamilyMatchResult::Builder b;
469     while (li < l.size() && ri < r.size()) {
470         if (l[li] < r[ri]) {
471             li++;
472         } else if (l[li] > r[ri]) {
473             ri++;
474         } else {  // l[li] == r[ri]
475             b.add(l[li]);
476             li++;
477             ri++;
478         }
479     }
480     return b.build();
481 }
482 
itemize(U16StringPiece text,FontStyle,uint32_t localeListId,FamilyVariant familyVariant,uint32_t runMax) const483 std::vector<FontCollection::Run> FontCollection::itemize(U16StringPiece text, FontStyle,
484                                                          uint32_t localeListId,
485                                                          FamilyVariant familyVariant,
486                                                          uint32_t runMax) const {
487     const uint16_t* string = text.data();
488     const uint32_t string_size = text.size();
489 
490     FamilyMatchResult lastFamilyIndices = FamilyMatchResult();
491 
492     if (string_size == 0) {
493         return std::vector<Run>();
494     }
495 
496     const uint32_t kEndOfString = 0xFFFFFFFF;
497     std::vector<Run> result;
498     Run* run = nullptr;
499 
500     uint32_t nextCh = 0;
501     uint32_t prevCh = 0;
502     size_t nextUtf16Pos = 0;
503     size_t readLength = 0;
504     U16_NEXT(string, readLength, string_size, nextCh);
505     if (U_IS_SURROGATE(nextCh)) {
506         nextCh = REPLACEMENT_CHARACTER;
507     }
508 
509     do {
510         const uint32_t ch = nextCh;
511         const size_t utf16Pos = nextUtf16Pos;
512         nextUtf16Pos = readLength;
513         if (readLength < string_size) {
514             U16_NEXT(string, readLength, string_size, nextCh);
515             if (U_IS_SURROGATE(nextCh)) {
516                 nextCh = REPLACEMENT_CHARACTER;
517             }
518         } else {
519             nextCh = kEndOfString;
520         }
521 
522         bool shouldContinueRun = false;
523         if (doesNotNeedFontSupport(ch)) {
524             // Always continue if the character is a format character not needed to be in the font.
525             shouldContinueRun = true;
526         } else if (!lastFamilyIndices.empty() && (isStickyAllowlisted(ch) || isCombining(ch))) {
527             // Continue using existing font as long as it has coverage and is whitelisted.
528 
529             const std::shared_ptr<FontFamily>& lastFamily = mFamilies[lastFamilyIndices[0]];
530             if (lastFamily->isColorEmojiFamily()) {
531                 // If the last family is color emoji font, find the longest family.
532                 shouldContinueRun = false;
533                 for (uint8_t ix : lastFamilyIndices) {
534                     shouldContinueRun |= mFamilies[ix]->getCoverage().get(ch);
535                 }
536             } else {
537                 shouldContinueRun = lastFamily->getCoverage().get(ch);
538             }
539         }
540 
541         if (!shouldContinueRun) {
542             FamilyMatchResult familyIndices = getFamilyForChar(
543                     ch, isVariationSelector(nextCh) ? nextCh : 0, localeListId, familyVariant);
544             bool breakRun;
545             if (utf16Pos == 0 || lastFamilyIndices.empty()) {
546                 breakRun = true;
547             } else {
548                 const std::shared_ptr<FontFamily>& lastFamily = mFamilies[lastFamilyIndices[0]];
549                 if (lastFamily->isColorEmojiFamily()) {
550                     FamilyMatchResult intersection =
551                             FamilyMatchResult::intersect(familyIndices, lastFamilyIndices);
552                     if (intersection.empty()) {
553                         breakRun = true;  // None of last family can draw the given char.
554                     } else {
555                         lastFamilyIndices = intersection;
556                         breakRun = false;
557                     }
558                 } else {
559                     breakRun = familyIndices[0] != lastFamilyIndices[0];
560                 }
561             }
562 
563             if (breakRun) {
564                 size_t start = utf16Pos;
565                 // Workaround for combining marks and emoji modifiers until we implement
566                 // per-cluster font selection: if a combining mark or an emoji modifier is found in
567                 // a different font that also supports the previous character, attach previous
568                 // character to the new run. U+20E3 COMBINING ENCLOSING KEYCAP, used in emoji, is
569                 // handled properly by this since it's a combining mark too.
570                 if (utf16Pos != 0 &&
571                     (isCombining(ch) || (isEmojiModifier(ch) && isEmojiBase(prevCh)))) {
572                     for (uint8_t ix : familyIndices) {
573                         if (mFamilies[ix]->getCoverage().get(prevCh)) {
574                             const size_t prevChLength = U16_LENGTH(prevCh);
575                             if (run != nullptr) {
576                                 run->end -= prevChLength;
577                                 if (run->start == run->end) {
578                                     result.pop_back();
579                                 }
580                             }
581                             start -= prevChLength;
582                             break;
583                         }
584                     }
585                 }
586                 if (lastFamilyIndices.empty()) {
587                     // This is the first family ever assigned. We are either seeing the very first
588                     // character (which means start would already be zero), or we have only seen
589                     // characters that don't need any font support (which means we need to adjust
590                     // start to be 0 to include those characters).
591                     start = 0;
592                 }
593                 result.push_back({familyIndices, static_cast<int>(start), 0});
594                 run = &result.back();
595                 lastFamilyIndices = run->familyMatch;
596             }
597         }
598         prevCh = ch;
599         if (run != nullptr) {
600             run->end = nextUtf16Pos;  // exclusive
601         }
602 
603         // Stop searching the remaining characters if the result length gets runMax + 2.
604         // When result.size gets runMax + 2 here, the run between [0, runMax) was finalized.
605         // If the result.size() equals to runMax, the run may be still expanding.
606         // if the result.size() equals to runMax + 2, the last run may be removed and the last run
607         // may be exntended the previous run with above workaround.
608         if (result.size() >= 2 && runMax == result.size() - 2) {
609             break;
610         }
611     } while (nextCh != kEndOfString);
612 
613     if (lastFamilyIndices.empty()) {
614         // No character needed any font support, so it doesn't really matter which font they end up
615         // getting displayed in. We put the whole string in one run, using the first font.
616         result.push_back(
617                 {FamilyMatchResult::Builder().add(0).build(), 0, static_cast<int>(string_size)});
618     }
619 
620     if (result.size() > runMax) {
621         // The itemization has terminated since it reaches the runMax. Remove last unfinalized runs.
622         return std::vector<Run>(result.begin(), result.begin() + runMax);
623     }
624 
625     return result;
626 }
627 
getBestFont(U16StringPiece text,const Run & run,FontStyle style)628 FakedFont FontCollection::getBestFont(U16StringPiece text, const Run& run, FontStyle style) {
629     uint8_t bestIndex = 0;
630     uint32_t bestGlyphCount = 0xFFFFFFFF;
631 
632     const std::shared_ptr<FontFamily>& family = mFamilies[run.familyMatch[0]];
633     if (family->isColorEmojiFamily() && run.familyMatch.size() > 1) {
634         for (size_t i = 0; i < run.familyMatch.size(); ++i) {
635             const std::shared_ptr<FontFamily>& family = mFamilies[run.familyMatch[i]];
636             const HbFontUniquePtr& font = family->getFont(0)->baseFont();
637             uint32_t glyphCount = getGlyphCount(text, run.start, run.end, font);
638             if (glyphCount < bestGlyphCount) {
639                 bestIndex = run.familyMatch[i];
640                 bestGlyphCount = glyphCount;
641             }
642         }
643     } else {
644         bestIndex = run.familyMatch[0];
645     }
646     return mFamilies[bestIndex]->getClosestMatch(style);
647 }
648 
baseFontFaked(FontStyle style)649 FakedFont FontCollection::baseFontFaked(FontStyle style) {
650     return mFamilies[0]->getClosestMatch(style);
651 }
652 
createCollectionWithVariation(const std::vector<FontVariation> & variations)653 std::shared_ptr<FontCollection> FontCollection::createCollectionWithVariation(
654         const std::vector<FontVariation>& variations) {
655     if (variations.empty() || mSupportedAxes.empty()) {
656         return nullptr;
657     }
658 
659     bool hasSupportedAxis = false;
660     for (const FontVariation& variation : variations) {
661         if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end()) {
662             hasSupportedAxis = true;
663             break;
664         }
665     }
666     if (!hasSupportedAxis) {
667         // None of variation axes are supported by this font collection.
668         return nullptr;
669     }
670 
671     std::vector<std::shared_ptr<FontFamily>> families;
672     for (const std::shared_ptr<FontFamily>& family : mFamilies) {
673         std::shared_ptr<FontFamily> newFamily = family->createFamilyWithVariation(variations);
674         if (newFamily) {
675             families.push_back(newFamily);
676         } else {
677             families.push_back(family);
678         }
679     }
680 
681     return std::shared_ptr<FontCollection>(new FontCollection(families));
682 }
683 
getId() const684 uint32_t FontCollection::getId() const {
685     return mId;
686 }
687 
688 }  // namespace minikin
689