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