xref: /aosp_15_r20/frameworks/minikin/libs/minikin/FontFamily.cpp (revision 834a2baab5fdfc28e9a428ee87c7ea8f6a06a53d)
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 #include "minikin/FontFamily.h"
18 
19 #include <log/log.h>
20 
21 #include <algorithm>
22 #include <unordered_set>
23 #include <vector>
24 
25 #include "FeatureFlags.h"
26 #include "FontUtils.h"
27 #include "Locale.h"
28 #include "LocaleListCache.h"
29 #include "MinikinInternal.h"
30 #include "minikin/CmapCoverage.h"
31 #include "minikin/Constants.h"
32 #include "minikin/FamilyVariant.h"
33 #include "minikin/HbUtils.h"
34 #include "minikin/MinikinFont.h"
35 
36 namespace minikin {
37 
38 namespace {
getAncestor(const std::shared_ptr<FontFamily> & family)39 const std::shared_ptr<FontFamily>& getAncestor(const std::shared_ptr<FontFamily>& family) {
40     return !family->getParent() ? family : getAncestor(family->getParent());
41 }
42 }  // namespace
43 
44 // static
create(std::vector<std::shared_ptr<Font>> && fonts)45 std::shared_ptr<FontFamily> FontFamily::create(std::vector<std::shared_ptr<Font>>&& fonts) {
46     return create(FamilyVariant::DEFAULT, std::move(fonts));
47 }
48 
49 // static
create(FamilyVariant variant,std::vector<std::shared_ptr<Font>> && fonts)50 std::shared_ptr<FontFamily> FontFamily::create(FamilyVariant variant,
51                                                std::vector<std::shared_ptr<Font>>&& fonts) {
52     return create(kEmptyLocaleListId, variant, std::move(fonts), false /* isCustomFallback */,
53                   false /* isDefaultFallback */, VariationFamilyType::None);
54 }
55 
56 // static
create(uint32_t localeListId,FamilyVariant variant,std::vector<std::shared_ptr<Font>> && fonts,bool isCustomFallback,bool isDefaultFallback,VariationFamilyType varFamilyType)57 std::shared_ptr<FontFamily> FontFamily::create(uint32_t localeListId, FamilyVariant variant,
58                                                std::vector<std::shared_ptr<Font>>&& fonts,
59                                                bool isCustomFallback, bool isDefaultFallback,
60                                                VariationFamilyType varFamilyType) {
61     // TODO(b/174672300): Revert back to make_shared.
62     return std::shared_ptr<FontFamily>(new FontFamily(localeListId, variant, std::move(fonts),
63                                                       isCustomFallback, isDefaultFallback,
64                                                       varFamilyType));
65 }
66 
create(const std::shared_ptr<FontFamily> & parent,const VariationSettings & axes)67 std::shared_ptr<FontFamily> FontFamily::create(const std::shared_ptr<FontFamily>& parent,
68                                                const VariationSettings& axes) {
69     if (axes.empty() || parent->getSupportedAxesCount() == 0) {
70         return nullptr;
71     }
72 
73     bool hasSupportedAxis = false;
74     for (const auto& axis : axes) {
75         for (uint32_t i = 0; i < parent->getSupportedAxesCount(); ++i) {
76             if (axis.axisTag == parent->getSupportedAxisAt(i)) {
77                 hasSupportedAxis = true;
78                 break;
79             }
80         }
81     }
82     if (!hasSupportedAxis) {
83         // None of variation axes are suppored by this family.
84         return nullptr;
85     }
86 
87     return std::shared_ptr<FontFamily>(new FontFamily(parent, axes));
88 }
89 
FontFamily(const std::shared_ptr<FontFamily> & parent,const VariationSettings & axesOverride)90 FontFamily::FontFamily(const std::shared_ptr<FontFamily>& parent,
91                        const VariationSettings& axesOverride)
92         : mFonts(),
93           mSupportedAxes(std::make_unique<AxisTag[]>(parent->getSupportedAxesCount())),
94           mCoverage(),
95           mCmapFmt14Coverage(nullptr),
96           mParent(getAncestor(parent)),  // Use ancestor as parent.
97           mVarOverride(axesOverride),
98           mLocaleListId(parent->mLocaleListId),
99           mFontsCount(parent->mFontsCount),
100           mSupportedAxesCount(parent->mSupportedAxesCount),
101           mCmapFmt14CoverageCount(parent->mCmapFmt14CoverageCount),
102           mVariant(parent->mVariant),
103           mIsColorEmoji(parent->mIsColorEmoji),
104           mIsCustomFallback(parent->mIsCustomFallback),
105           mIsDefaultFallback(parent->mIsDefaultFallback),
106           mVarFamilyType(VariationFamilyType::None),
107           mIsVariationFamily(true) {
108     // Filter only the axis supported font.
109     std::vector<std::shared_ptr<Font>> overriddenFonts;
110     for (uint16_t i = 0; i < mFontsCount; ++i) {
111         const auto& font = parent->mFonts[i];
112         bool isSupported = false;
113         for (const auto& axis : axesOverride) {
114             if (font->isAxisSupported(axis.axisTag)) {
115                 isSupported = true;
116                 break;
117             }
118         }
119         if (isSupported) {
120             overriddenFonts.emplace_back(std::make_shared<Font>(font, axesOverride));
121         }
122     }
123     mFonts = std::make_unique<std::shared_ptr<Font>[]>(overriddenFonts.size());
124     for (uint16_t i = 0; i < overriddenFonts.size(); ++i) {
125         mFonts[i] = std::move(overriddenFonts[i]);
126     }
127 
128     // Copy the supported axes
129     const AxisTag* src = parent->mSupportedAxes.get();
130     std::copy(src, src + mSupportedAxesCount, mSupportedAxes.get());
131 }
132 
FontFamily(uint32_t localeListId,FamilyVariant variant,std::vector<std::shared_ptr<Font>> && fonts,bool isCustomFallback,bool isDefaultFallback,VariationFamilyType varFamilyType)133 FontFamily::FontFamily(uint32_t localeListId, FamilyVariant variant,
134                        std::vector<std::shared_ptr<Font>>&& fonts, bool isCustomFallback,
135                        bool isDefaultFallback, VariationFamilyType varFamilyType)
136         : mFonts(std::make_unique<std::shared_ptr<Font>[]>(fonts.size())),
137           // computeCoverage may update supported axes and coverages later.
138           mSupportedAxes(nullptr),
139           mCoverage(),
140           mCmapFmt14Coverage(nullptr),
141           mParent(nullptr),
142           mVarOverride(),
143           mLocaleListId(localeListId),
144           mFontsCount(static_cast<uint32_t>(fonts.size())),
145           mSupportedAxesCount(0),
146           mCmapFmt14CoverageCount(0),
147           mVariant(variant),
148           mIsColorEmoji(LocaleListCache::getById(localeListId).getEmojiStyle() ==
149                         EmojiStyle::EMOJI),
150           mIsCustomFallback(isCustomFallback),
151           mIsDefaultFallback(isDefaultFallback),
152           mVarFamilyType(varFamilyType),
153           mIsVariationFamily(false) {
154     MINIKIN_ASSERT(!fonts.empty(), "FontFamily must contain at least one font.");
155     MINIKIN_ASSERT(fonts.size() <= std::numeric_limits<uint32_t>::max(),
156                    "Number of fonts must be less than 2^32.");
157     for (size_t i = 0; i < mFontsCount; i++) {
158         mFonts[i] = std::move(fonts[i]);
159     }
160     computeCoverage();
161 }
162 
FontFamily(BufferReader * reader,const std::shared_ptr<std::vector<Font>> & allFonts)163 FontFamily::FontFamily(BufferReader* reader, const std::shared_ptr<std::vector<Font>>& allFonts)
164         : mSupportedAxes(nullptr), mCmapFmt14Coverage(nullptr), mParent(nullptr), mVarOverride() {
165     mLocaleListId = LocaleListCache::readFrom(reader);
166     mFontsCount = reader->read<uint32_t>();
167     mFonts = std::make_unique<std::shared_ptr<Font>[]>(mFontsCount);
168     for (size_t i = 0; i < mFontsCount; i++) {
169         uint32_t fontIndex = reader->read<uint32_t>();
170         // Use aliasing constructor to save memory.
171         // See the comments on FontFamily::readVector for details.
172         mFonts[i] = std::shared_ptr<Font>(allFonts, &(*allFonts)[fontIndex]);
173     }
174     // FamilyVariant is uint8_t
175     static_assert(sizeof(FamilyVariant) == 1);
176     mVariant = reader->read<FamilyVariant>();
177     // AxisTag is uint32_t
178     static_assert(sizeof(AxisTag) == 4);
179     const auto& [axesPtr, axesCount] = reader->readArray<AxisTag>();
180     mSupportedAxesCount = axesCount;
181     if (axesCount > 0) {
182         mSupportedAxes = std::unique_ptr<AxisTag[]>(new AxisTag[axesCount]);
183         std::copy(axesPtr, axesPtr + axesCount, mSupportedAxes.get());
184     }
185     mIsColorEmoji = static_cast<bool>(reader->read<uint8_t>());
186     mIsCustomFallback = static_cast<bool>(reader->read<uint8_t>());
187     mIsDefaultFallback = static_cast<bool>(reader->read<uint8_t>());
188     mVarFamilyType = reader->read<VariationFamilyType>();
189     mIsVariationFamily = false;
190     mCoverage = SparseBitSet(reader);
191     // Read mCmapFmt14Coverage. As it can have null entries, it is stored in the buffer as a sparse
192     // array (size, non-null entry count, array of (index, entry)).
193     mCmapFmt14CoverageCount = reader->read<uint32_t>();
194     if (mCmapFmt14CoverageCount > 0) {
195         mCmapFmt14Coverage = std::make_unique<SparseBitSet[]>(mCmapFmt14CoverageCount);
196         uint32_t cmapFmt14CoverageEntryCount = reader->read<uint32_t>();
197         for (uint32_t i = 0; i < cmapFmt14CoverageEntryCount; i++) {
198             uint32_t index = reader->read<uint32_t>();
199             mCmapFmt14Coverage[index] = SparseBitSet(reader);
200         }
201     }
202 }
203 
writeTo(BufferWriter * writer,uint32_t * fontIndex) const204 void FontFamily::writeTo(BufferWriter* writer, uint32_t* fontIndex) const {
205     MINIKIN_ASSERT(mParent == nullptr, "Do not serialize variation overridden font families.");
206     LocaleListCache::writeTo(writer, mLocaleListId);
207     writer->write<uint32_t>(mFontsCount);
208     for (size_t i = 0; i < mFontsCount; i++) {
209         writer->write<uint32_t>(*fontIndex);
210         (*fontIndex)++;
211     }
212     writer->write<FamilyVariant>(mVariant);
213     writer->writeArray<AxisTag>(mSupportedAxes.get(), mSupportedAxesCount);
214     writer->write<uint8_t>(mIsColorEmoji);
215     writer->write<uint8_t>(mIsCustomFallback);
216     writer->write<uint8_t>(mIsDefaultFallback);
217     writer->write<VariationFamilyType>(mVarFamilyType);
218     mCoverage.writeTo(writer);
219     // Write mCmapFmt14Coverage as a sparse array (size, non-null entry count,
220     // array of (index, entry))
221     writer->write<uint32_t>(mCmapFmt14CoverageCount);
222     // Skip writing the sparse entries if the size is zero
223     if (mCmapFmt14CoverageCount > 0) {
224         uint32_t cmapFmt14CoverageEntryCount = 0;
225         for (size_t i = 0; i < mCmapFmt14CoverageCount; i++) {
226             if (!mCmapFmt14Coverage[i].empty()) cmapFmt14CoverageEntryCount++;
227         }
228         writer->write<uint32_t>(cmapFmt14CoverageEntryCount);
229         for (size_t i = 0; i < mCmapFmt14CoverageCount; i++) {
230             if (!mCmapFmt14Coverage[i].empty()) {
231                 writer->write<uint32_t>(i);
232                 mCmapFmt14Coverage[i].writeTo(writer);
233             }
234         }
235     }
236 }
237 
238 // static
readVector(BufferReader * reader)239 std::vector<std::shared_ptr<FontFamily>> FontFamily::readVector(BufferReader* reader) {
240     // To save memory used for reference counting objects, we store
241     // Font / FontFamily in shared_ptr<vector<Font / FontFamily>>, and use
242     // shared_ptr's aliasing constructor to create shared_ptr<Font / FontFamily>
243     // that share the reference counting objects with
244     // the shared_ptr<vector<Font / FontFamily>>.
245     // We can do this because we know that all Font and FontFamily
246     // instances based on the same BufferReader share the same life span.
247     uint32_t fontsCount = reader->read<uint32_t>();
248     std::shared_ptr<std::vector<Font>> fonts = std::make_shared<std::vector<Font>>();
249     fonts->reserve(fontsCount);
250     for (uint32_t i = 0; i < fontsCount; i++) {
251         fonts->emplace_back(reader);
252     }
253     uint32_t count = reader->read<uint32_t>();
254     std::shared_ptr<std::vector<FontFamily>> families = std::make_shared<std::vector<FontFamily>>();
255     families->reserve(count);
256     std::vector<std::shared_ptr<FontFamily>> pointers;
257     pointers.reserve(count);
258     for (uint32_t i = 0; i < count; i++) {
259         // TODO(b/174672300): Revert back to emplace_back.
260         families->push_back(FontFamily(reader, fonts));
261         // Use aliasing constructor.
262         pointers.emplace_back(families, &families->back());
263     }
264     return pointers;
265 }
266 
267 // static
writeVector(BufferWriter * writer,const std::vector<std::shared_ptr<FontFamily>> & families)268 void FontFamily::writeVector(BufferWriter* writer,
269                              const std::vector<std::shared_ptr<FontFamily>>& families) {
270     std::vector<std::shared_ptr<Font>> fonts;
271     for (const auto& fontFamily : families) {
272         for (uint32_t i = 0; i < fontFamily->getNumFonts(); i++) {
273             fonts.emplace_back(fontFamily->getFontRef(i));
274         }
275     }
276     writer->write<uint32_t>(fonts.size());
277     for (const auto& font : fonts) {
278         font->writeTo(writer);
279     }
280     uint32_t fontIndex = 0;
281     writer->write<uint32_t>(families.size());
282     for (const auto& fontFamily : families) {
283         fontFamily->writeTo(writer, &fontIndex);
284     }
285 }
286 
287 // Compute a matching metric between two styles - 0 is an exact match
computeMatch(FontStyle style1,FontStyle style2)288 static int computeMatch(FontStyle style1, FontStyle style2) {
289     if (style1 == style2) return 0;
290     int score = abs(style1.weight() / 100 - style2.weight() / 100);
291     if (style1.slant() != style2.slant()) {
292         score += 2;
293     }
294     return score;
295 }
296 
computeFakery(FontStyle wanted,FontStyle actual)297 static FontFakery computeFakery(FontStyle wanted, FontStyle actual) {
298     // If desired weight is semibold or darker, and 2 or more grades
299     // higher than actual (for example, medium 500 -> bold 700), then
300     // select fake bold.
301     bool isFakeBold = wanted.weight() >= 600 && (wanted.weight() - actual.weight()) >= 200;
302     bool isFakeItalic = wanted.slant() == FontStyle::Slant::ITALIC &&
303                         actual.slant() == FontStyle::Slant::UPRIGHT;
304     return FontFakery(isFakeBold, isFakeItalic);
305 }
306 
getClosestMatch(FontStyle style,const VariationSettings & axes) const307 FakedFont FontFamily::getClosestMatch(FontStyle style, const VariationSettings& axes) const {
308     if (features::typeface_redesign_readonly()) {
309         int bestIndex = 0;
310         Font* bestFont = mFonts[bestIndex].get();
311         int bestMatch = computeMatch(bestFont->style(), style);
312         for (size_t i = 1; i < mFontsCount; i++) {
313             Font* font = mFonts[i].get();
314             int match = computeMatch(font->style(), style);
315             if (i == 0 || match < bestMatch) {
316                 bestFont = font;
317                 bestIndex = i;
318                 bestMatch = match;
319             }
320         }
321 
322         if (mIsVariationFamily) {
323             // For backward compatibility reasons, we don't merge the variation settings because it
324             // is developer provided configuration.
325             return FakedFont{mFonts[bestIndex], computeFakery(style, bestFont->style())};
326         }
327 
328         if (axes.empty() && style == bestFont->style()) {
329             // Easy case, no merge is necessary.
330             return FakedFont{mFonts[bestIndex], FontFakery(false, false)};
331         }
332         FontFakery fakery = merge(bestFont->getFVarTable(), bestFont->baseTypeface()->GetAxes(),
333                                   axes, bestFont->style(), style);
334         return FakedFont(mFonts[bestIndex], fakery);
335     }
336 
337     if (mVarFamilyType != VariationFamilyType::None) {
338         return getVariationFamilyAdjustment(style);
339     }
340     int bestIndex = 0;
341     Font* bestFont = mFonts[bestIndex].get();
342     int bestMatch = computeMatch(bestFont->style(), style);
343     for (size_t i = 1; i < mFontsCount; i++) {
344         Font* font = mFonts[i].get();
345         int match = computeMatch(font->style(), style);
346         if (i == 0 || match < bestMatch) {
347             bestFont = font;
348             bestIndex = i;
349             bestMatch = match;
350         }
351     }
352     return FakedFont{mFonts[bestIndex], computeFakery(style, bestFont->style())};
353 }
354 
getVariationFamilyAdjustment(FontStyle style) const355 FakedFont FontFamily::getVariationFamilyAdjustment(FontStyle style) const {
356     const bool italic = style.slant() == FontStyle::Slant::ITALIC;
357     switch (mVarFamilyType) {
358         case VariationFamilyType::SingleFont_wghtOnly:
359             return FakedFont{mFonts[0], FontFakery(false, italic, style.weight(), -1)};
360         case VariationFamilyType::SingleFont_wght_ital:
361             return FakedFont{mFonts[0], FontFakery(false, false, style.weight(), italic ? 1 : 0)};
362         case VariationFamilyType::TwoFont_wght:
363             return FakedFont{mFonts[italic ? 1 : 0], FontFakery(false, false, style.weight(), -1)};
364         case VariationFamilyType::None:
365             return FakedFont{mFonts[0], FontFakery()};
366     }
367 }
368 
computeCoverage()369 void FontFamily::computeCoverage() {
370     const std::shared_ptr<Font>& font = getClosestMatch(FontStyle(), VariationSettings()).font;
371     HbBlob cmapTable(font->baseFont(), MakeTag('c', 'm', 'a', 'p'));
372     if (cmapTable.get() == nullptr) {
373         ALOGE("Could not get cmap table size!\n");
374         return;
375     }
376 
377     std::vector<SparseBitSet> cmapFmt14Coverage;
378     mCoverage = CmapCoverage::getCoverage(cmapTable.get(), cmapTable.size(), &cmapFmt14Coverage);
379     static_assert(INVALID_VS_INDEX <= std::numeric_limits<uint16_t>::max());
380     // cmapFmt14Coverage maps VS index to coverage.
381     // cmapFmt14Coverage's size cannot exceed INVALID_VS_INDEX.
382     MINIKIN_ASSERT(cmapFmt14Coverage.size() <= INVALID_VS_INDEX,
383                    "cmapFmt14Coverage's size must not exceed INVALID_VS_INDEX.");
384     mCmapFmt14CoverageCount = static_cast<uint16_t>(cmapFmt14Coverage.size());
385     if (mCmapFmt14CoverageCount > 0) {
386         mCmapFmt14Coverage = std::make_unique<SparseBitSet[]>(mCmapFmt14CoverageCount);
387         for (size_t i = 0; i < mCmapFmt14CoverageCount; i++) {
388             mCmapFmt14Coverage[i] = std::move(cmapFmt14Coverage[i]);
389         }
390     }
391 
392     std::unordered_set<AxisTag> supportedAxesSet;
393     for (size_t i = 0; i < mFontsCount; ++i) {
394         const uint16_t axesCount = mFonts[i]->getSupportedAxesCount();
395         if (axesCount != 0) {
396             const AxisTag* axesPtr = mFonts[i]->getSupportedAxes();
397             supportedAxesSet.insert(axesPtr, axesPtr + axesCount);
398         }
399     }
400     MINIKIN_ASSERT(supportedAxesSet.size() <= std::numeric_limits<uint32_t>::max(),
401                    "Number of supported axes must be less than 2^16.");
402     mSupportedAxesCount = static_cast<uint16_t>(supportedAxesSet.size());
403     if (mSupportedAxesCount > 0) {
404         mSupportedAxes = sortedArrayFromSet(supportedAxesSet);
405     }
406 }
407 
hasGlyph(uint32_t codepoint,uint32_t variationSelector) const408 bool FontFamily::hasGlyph(uint32_t codepoint, uint32_t variationSelector) const {
409     if (variationSelector == 0) {
410         return getCoverage().get(codepoint);
411     }
412 
413     if (mCmapFmt14CoverageCount == 0) {
414         return false;
415     }
416 
417     const uint16_t vsIndex = getVsIndex(variationSelector);
418 
419     if (vsIndex >= mCmapFmt14CoverageCount) {
420         // Even if vsIndex is INVALID_VS_INDEX, we reach here since INVALID_VS_INDEX is defined to
421         // be at the maximum end of the range.
422         return false;
423     }
424 
425     const SparseBitSet& bitset = getCmap14Coverage(vsIndex);
426     if (bitset.empty()) {
427         return false;
428     }
429 
430     return bitset.get(codepoint);
431 }
432 
createFamilyWithVariation(const VariationSettings & variations) const433 std::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation(
434         const VariationSettings& variations) const {
435     if (variations.empty() || mSupportedAxesCount == 0) {
436         return nullptr;
437     }
438 
439     bool hasSupportedAxis = false;
440     for (const FontVariation& variation : variations) {
441         if (std::binary_search(mSupportedAxes.get(), mSupportedAxes.get() + mSupportedAxesCount,
442                                variation.axisTag)) {
443             hasSupportedAxis = true;
444             break;
445         }
446     }
447     if (!hasSupportedAxis) {
448         // None of variation axes are suppored by this family.
449         return nullptr;
450     }
451 
452     std::vector<std::shared_ptr<Font>> fonts;
453     for (size_t i = 0; i < mFontsCount; i++) {
454         const std::shared_ptr<Font>& font = mFonts[i];
455         bool supportedVariations = false;
456         if (font->getSupportedAxesCount() != 0) {
457             for (const FontVariation& variation : variations) {
458                 if (font->isAxisSupported(variation.axisTag)) {
459                     supportedVariations = true;
460                     break;
461                 }
462             }
463         }
464         std::shared_ptr<MinikinFont> minikinFont;
465         if (supportedVariations) {
466             minikinFont = font->baseTypeface()->createFontWithVariation(variations);
467         }
468         if (minikinFont == nullptr) {
469             fonts.push_back(font);
470         } else {
471             fonts.push_back(Font::Builder(minikinFont).setStyle(font->style()).build());
472         }
473     }
474 
475     return create(mLocaleListId, mVariant, std::move(fonts), mIsCustomFallback, mIsDefaultFallback,
476                   VariationFamilyType::None);
477 }
478 
479 }  // namespace minikin
480