• 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/FontFamily.h"
20 
21 #include <log/log.h>
22 
23 #include <algorithm>
24 #include <unordered_set>
25 #include <vector>
26 
27 #include "FontUtils.h"
28 #include "Locale.h"
29 #include "LocaleListCache.h"
30 #include "MinikinInternal.h"
31 #include "minikin/CmapCoverage.h"
32 #include "minikin/FamilyVariant.h"
33 #include "minikin/HbUtils.h"
34 #include "minikin/MinikinFont.h"
35 
36 namespace minikin {
37 
38 // static
create(std::vector<std::shared_ptr<Font>> && fonts)39 std::shared_ptr<FontFamily> FontFamily::create(std::vector<std::shared_ptr<Font>>&& fonts) {
40     return create(FamilyVariant::DEFAULT, std::move(fonts));
41 }
42 
43 // static
create(FamilyVariant variant,std::vector<std::shared_ptr<Font>> && fonts)44 std::shared_ptr<FontFamily> FontFamily::create(FamilyVariant variant,
45                                                std::vector<std::shared_ptr<Font>>&& fonts) {
46     return create(kEmptyLocaleListId, variant, std::move(fonts), false /* isCustomFallback */,
47                   false /* isDefaultFallback */);
48 }
49 
50 // static
create(uint32_t localeListId,FamilyVariant variant,std::vector<std::shared_ptr<Font>> && fonts,bool isCustomFallback,bool isDefaultFallback)51 std::shared_ptr<FontFamily> FontFamily::create(uint32_t localeListId, FamilyVariant variant,
52                                                std::vector<std::shared_ptr<Font>>&& fonts,
53                                                bool isCustomFallback, bool isDefaultFallback) {
54     // TODO(b/174672300): Revert back to make_shared.
55     return std::shared_ptr<FontFamily>(new FontFamily(localeListId, variant, std::move(fonts),
56                                                       isCustomFallback, isDefaultFallback));
57 }
58 
FontFamily(uint32_t localeListId,FamilyVariant variant,std::vector<std::shared_ptr<Font>> && fonts,bool isCustomFallback,bool isDefaultFallback)59 FontFamily::FontFamily(uint32_t localeListId, FamilyVariant variant,
60                        std::vector<std::shared_ptr<Font>>&& fonts, bool isCustomFallback,
61                        bool isDefaultFallback)
62         : mFonts(std::make_unique<std::shared_ptr<Font>[]>(fonts.size())),
63           // computeCoverage may update supported axes and coverages later.
64           mSupportedAxes(nullptr),
65           mCoverage(),
66           mCmapFmt14Coverage(nullptr),
67           mLocaleListId(localeListId),
68           mFontsCount(static_cast<uint32_t>(fonts.size())),
69           mSupportedAxesCount(0),
70           mCmapFmt14CoverageCount(0),
71           mVariant(variant),
72           mIsColorEmoji(LocaleListCache::getById(localeListId).getEmojiStyle() ==
73                         EmojiStyle::EMOJI),
74           mIsCustomFallback(isCustomFallback),
75           mIsDefaultFallback(isDefaultFallback) {
76     MINIKIN_ASSERT(!fonts.empty(), "FontFamily must contain at least one font.");
77     MINIKIN_ASSERT(fonts.size() <= std::numeric_limits<uint32_t>::max(),
78                    "Number of fonts must be less than 2^32.");
79     for (size_t i = 0; i < mFontsCount; i++) {
80         mFonts[i] = std::move(fonts[i]);
81     }
82     computeCoverage();
83 }
84 
FontFamily(BufferReader * reader,const std::shared_ptr<std::vector<Font>> & allFonts)85 FontFamily::FontFamily(BufferReader* reader, const std::shared_ptr<std::vector<Font>>& allFonts)
86         : mSupportedAxes(nullptr), mCmapFmt14Coverage(nullptr) {
87     mLocaleListId = LocaleListCache::readFrom(reader);
88     mFontsCount = reader->read<uint32_t>();
89     mFonts = std::make_unique<std::shared_ptr<Font>[]>(mFontsCount);
90     for (size_t i = 0; i < mFontsCount; i++) {
91         uint32_t fontIndex = reader->read<uint32_t>();
92         // Use aliasing constructor to save memory.
93         // See the comments on FontFamily::readVector for details.
94         mFonts[i] = std::shared_ptr<Font>(allFonts, &(*allFonts)[fontIndex]);
95     }
96     // FamilyVariant is uint8_t
97     static_assert(sizeof(FamilyVariant) == 1);
98     mVariant = reader->read<FamilyVariant>();
99     // AxisTag is uint32_t
100     static_assert(sizeof(AxisTag) == 4);
101     const auto& [axesPtr, axesCount] = reader->readArray<AxisTag>();
102     mSupportedAxesCount = axesCount;
103     if (axesCount > 0) {
104         mSupportedAxes = std::unique_ptr<AxisTag[]>(new AxisTag[axesCount]);
105         std::copy(axesPtr, axesPtr + axesCount, mSupportedAxes.get());
106     }
107     mIsColorEmoji = static_cast<bool>(reader->read<uint8_t>());
108     mIsCustomFallback = static_cast<bool>(reader->read<uint8_t>());
109     mIsDefaultFallback = static_cast<bool>(reader->read<uint8_t>());
110     mCoverage = SparseBitSet(reader);
111     // Read mCmapFmt14Coverage. As it can have null entries, it is stored in the buffer as a sparse
112     // array (size, non-null entry count, array of (index, entry)).
113     mCmapFmt14CoverageCount = reader->read<uint32_t>();
114     if (mCmapFmt14CoverageCount > 0) {
115         mCmapFmt14Coverage = std::make_unique<SparseBitSet[]>(mCmapFmt14CoverageCount);
116         uint32_t cmapFmt14CoverageEntryCount = reader->read<uint32_t>();
117         for (uint32_t i = 0; i < cmapFmt14CoverageEntryCount; i++) {
118             uint32_t index = reader->read<uint32_t>();
119             mCmapFmt14Coverage[index] = SparseBitSet(reader);
120         }
121     }
122 }
123 
writeTo(BufferWriter * writer,uint32_t * fontIndex) const124 void FontFamily::writeTo(BufferWriter* writer, uint32_t* fontIndex) const {
125     LocaleListCache::writeTo(writer, mLocaleListId);
126     writer->write<uint32_t>(mFontsCount);
127     for (size_t i = 0; i < mFontsCount; i++) {
128         writer->write<uint32_t>(*fontIndex);
129         (*fontIndex)++;
130     }
131     writer->write<FamilyVariant>(mVariant);
132     writer->writeArray<AxisTag>(mSupportedAxes.get(), mSupportedAxesCount);
133     writer->write<uint8_t>(mIsColorEmoji);
134     writer->write<uint8_t>(mIsCustomFallback);
135     writer->write<uint8_t>(mIsDefaultFallback);
136     mCoverage.writeTo(writer);
137     // Write mCmapFmt14Coverage as a sparse array (size, non-null entry count,
138     // array of (index, entry))
139     writer->write<uint32_t>(mCmapFmt14CoverageCount);
140     // Skip writing the sparse entries if the size is zero
141     if (mCmapFmt14CoverageCount > 0) {
142         uint32_t cmapFmt14CoverageEntryCount = 0;
143         for (size_t i = 0; i < mCmapFmt14CoverageCount; i++) {
144             if (!mCmapFmt14Coverage[i].empty()) cmapFmt14CoverageEntryCount++;
145         }
146         writer->write<uint32_t>(cmapFmt14CoverageEntryCount);
147         for (size_t i = 0; i < mCmapFmt14CoverageCount; i++) {
148             if (!mCmapFmt14Coverage[i].empty()) {
149                 writer->write<uint32_t>(i);
150                 mCmapFmt14Coverage[i].writeTo(writer);
151             }
152         }
153     }
154 }
155 
156 // static
readVector(BufferReader * reader)157 std::vector<std::shared_ptr<FontFamily>> FontFamily::readVector(BufferReader* reader) {
158     // To save memory used for reference counting objects, we store
159     // Font / FontFamily in shared_ptr<vector<Font / FontFamily>>, and use
160     // shared_ptr's aliasing constructor to create shared_ptr<Font / FontFamily>
161     // that share the reference counting objects with
162     // the shared_ptr<vector<Font / FontFamily>>.
163     // We can do this because we know that all Font and FontFamily
164     // instances based on the same BufferReader share the same life span.
165     uint32_t fontsCount = reader->read<uint32_t>();
166     std::shared_ptr<std::vector<Font>> fonts = std::make_shared<std::vector<Font>>();
167     fonts->reserve(fontsCount);
168     for (uint32_t i = 0; i < fontsCount; i++) {
169         fonts->emplace_back(reader);
170     }
171     uint32_t count = reader->read<uint32_t>();
172     std::shared_ptr<std::vector<FontFamily>> families = std::make_shared<std::vector<FontFamily>>();
173     families->reserve(count);
174     std::vector<std::shared_ptr<FontFamily>> pointers;
175     pointers.reserve(count);
176     for (uint32_t i = 0; i < count; i++) {
177         // TODO(b/174672300): Revert back to emplace_back.
178         families->push_back(FontFamily(reader, fonts));
179         // Use aliasing constructor.
180         pointers.emplace_back(families, &families->back());
181     }
182     return pointers;
183 }
184 
185 // static
writeVector(BufferWriter * writer,const std::vector<std::shared_ptr<FontFamily>> & families)186 void FontFamily::writeVector(BufferWriter* writer,
187                              const std::vector<std::shared_ptr<FontFamily>>& families) {
188     std::vector<std::shared_ptr<Font>> fonts;
189     for (const auto& fontFamily : families) {
190         for (uint32_t i = 0; i < fontFamily->getNumFonts(); i++) {
191             fonts.emplace_back(fontFamily->getFontRef(i));
192         }
193     }
194     writer->write<uint32_t>(fonts.size());
195     for (const auto& font : fonts) {
196         font->writeTo(writer);
197     }
198     uint32_t fontIndex = 0;
199     writer->write<uint32_t>(families.size());
200     for (const auto& fontFamily : families) {
201         fontFamily->writeTo(writer, &fontIndex);
202     }
203 }
204 
205 // Compute a matching metric between two styles - 0 is an exact match
computeMatch(FontStyle style1,FontStyle style2)206 static int computeMatch(FontStyle style1, FontStyle style2) {
207     if (style1 == style2) return 0;
208     int score = abs(style1.weight() / 100 - style2.weight() / 100);
209     if (style1.slant() != style2.slant()) {
210         score += 2;
211     }
212     return score;
213 }
214 
computeFakery(FontStyle wanted,FontStyle actual)215 static FontFakery computeFakery(FontStyle wanted, FontStyle actual) {
216     // If desired weight is semibold or darker, and 2 or more grades
217     // higher than actual (for example, medium 500 -> bold 700), then
218     // select fake bold.
219     bool isFakeBold = wanted.weight() >= 600 && (wanted.weight() - actual.weight()) >= 200;
220     bool isFakeItalic = wanted.slant() == FontStyle::Slant::ITALIC &&
221                         actual.slant() == FontStyle::Slant::UPRIGHT;
222     return FontFakery(isFakeBold, isFakeItalic);
223 }
224 
getClosestMatch(FontStyle style) const225 FakedFont FontFamily::getClosestMatch(FontStyle style) const {
226     int bestIndex = 0;
227     Font* bestFont = mFonts[bestIndex].get();
228     int bestMatch = computeMatch(bestFont->style(), style);
229     for (size_t i = 1; i < mFontsCount; i++) {
230         Font* font = mFonts[i].get();
231         int match = computeMatch(font->style(), style);
232         if (i == 0 || match < bestMatch) {
233             bestFont = font;
234             bestIndex = i;
235             bestMatch = match;
236         }
237     }
238     return FakedFont{mFonts[bestIndex], computeFakery(style, bestFont->style())};
239 }
240 
computeCoverage()241 void FontFamily::computeCoverage() {
242     const std::shared_ptr<Font>& font = getClosestMatch(FontStyle()).font;
243     HbBlob cmapTable(font->baseFont(), MinikinFont::MakeTag('c', 'm', 'a', 'p'));
244     if (cmapTable.get() == nullptr) {
245         ALOGE("Could not get cmap table size!\n");
246         return;
247     }
248 
249     std::vector<SparseBitSet> cmapFmt14Coverage;
250     mCoverage = CmapCoverage::getCoverage(cmapTable.get(), cmapTable.size(), &cmapFmt14Coverage);
251     static_assert(INVALID_VS_INDEX <= std::numeric_limits<uint16_t>::max());
252     // cmapFmt14Coverage maps VS index to coverage.
253     // cmapFmt14Coverage's size cannot exceed INVALID_VS_INDEX.
254     MINIKIN_ASSERT(cmapFmt14Coverage.size() <= INVALID_VS_INDEX,
255                    "cmapFmt14Coverage's size must not exceed INVALID_VS_INDEX.");
256     mCmapFmt14CoverageCount = static_cast<uint16_t>(cmapFmt14Coverage.size());
257     if (mCmapFmt14CoverageCount > 0) {
258         mCmapFmt14Coverage = std::make_unique<SparseBitSet[]>(mCmapFmt14CoverageCount);
259         for (size_t i = 0; i < mCmapFmt14CoverageCount; i++) {
260             mCmapFmt14Coverage[i] = std::move(cmapFmt14Coverage[i]);
261         }
262     }
263 
264     std::unordered_set<AxisTag> supportedAxesSet;
265     for (size_t i = 0; i < mFontsCount; ++i) {
266         std::unordered_set<AxisTag> supportedAxes = mFonts[i]->getSupportedAxes();
267         supportedAxesSet.insert(supportedAxes.begin(), supportedAxes.end());
268     }
269     MINIKIN_ASSERT(supportedAxesSet.size() <= std::numeric_limits<uint32_t>::max(),
270                    "Number of supported axes must be less than 2^16.");
271     mSupportedAxesCount = static_cast<uint16_t>(supportedAxesSet.size());
272     if (mSupportedAxesCount > 0) {
273         mSupportedAxes = sortedArrayFromSet(supportedAxesSet);
274     }
275 }
276 
hasGlyph(uint32_t codepoint,uint32_t variationSelector) const277 bool FontFamily::hasGlyph(uint32_t codepoint, uint32_t variationSelector) const {
278     if (variationSelector == 0) {
279         return mCoverage.get(codepoint);
280     }
281 
282     if (mCmapFmt14CoverageCount == 0) {
283         return false;
284     }
285 
286     const uint16_t vsIndex = getVsIndex(variationSelector);
287 
288     if (vsIndex >= mCmapFmt14CoverageCount) {
289         // Even if vsIndex is INVALID_VS_INDEX, we reach here since INVALID_VS_INDEX is defined to
290         // be at the maximum end of the range.
291         return false;
292     }
293 
294     const SparseBitSet& bitset = mCmapFmt14Coverage[vsIndex];
295     if (bitset.empty()) {
296         return false;
297     }
298 
299     return bitset.get(codepoint);
300 }
301 
createFamilyWithVariation(const std::vector<FontVariation> & variations) const302 std::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation(
303         const std::vector<FontVariation>& variations) const {
304     if (variations.empty() || mSupportedAxesCount == 0) {
305         return nullptr;
306     }
307 
308     bool hasSupportedAxis = false;
309     for (const FontVariation& variation : variations) {
310         if (std::binary_search(mSupportedAxes.get(), mSupportedAxes.get() + mSupportedAxesCount,
311                                variation.axisTag)) {
312             hasSupportedAxis = true;
313             break;
314         }
315     }
316     if (!hasSupportedAxis) {
317         // None of variation axes are suppored by this family.
318         return nullptr;
319     }
320 
321     std::vector<std::shared_ptr<Font>> fonts;
322     for (size_t i = 0; i < mFontsCount; i++) {
323         const std::shared_ptr<Font>& font = mFonts[i];
324         bool supportedVariations = false;
325         std::unordered_set<AxisTag> supportedAxes = font->getSupportedAxes();
326         if (!supportedAxes.empty()) {
327             for (const FontVariation& variation : variations) {
328                 if (supportedAxes.find(variation.axisTag) != supportedAxes.end()) {
329                     supportedVariations = true;
330                     break;
331                 }
332             }
333         }
334         std::shared_ptr<MinikinFont> minikinFont;
335         if (supportedVariations) {
336             minikinFont = font->typeface()->createFontWithVariation(variations);
337         }
338         if (minikinFont == nullptr) {
339             fonts.push_back(font);
340         } else {
341             fonts.push_back(Font::Builder(minikinFont).setStyle(font->style()).build());
342         }
343     }
344 
345     return create(mLocaleListId, mVariant, std::move(fonts), mIsCustomFallback, mIsDefaultFallback);
346 }
347 
348 }  // namespace minikin
349