• 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 <algorithm>
22 #include <vector>
23 
24 #include <log/log.h>
25 
26 #include "minikin/CmapCoverage.h"
27 #include "minikin/FamilyVariant.h"
28 #include "minikin/HbUtils.h"
29 #include "minikin/MinikinFont.h"
30 
31 #include "FontUtils.h"
32 #include "Locale.h"
33 #include "LocaleListCache.h"
34 #include "MinikinInternal.h"
35 
36 namespace minikin {
37 
FontFamily(std::vector<std::shared_ptr<Font>> && fonts)38 FontFamily::FontFamily(std::vector<std::shared_ptr<Font>>&& fonts)
39         : FontFamily(FamilyVariant::DEFAULT, std::move(fonts)) {}
40 
FontFamily(FamilyVariant variant,std::vector<std::shared_ptr<Font>> && fonts)41 FontFamily::FontFamily(FamilyVariant variant, std::vector<std::shared_ptr<Font>>&& fonts)
42         : FontFamily(kEmptyLocaleListId, variant, std::move(fonts), false /* isCustomFallback */) {}
43 
FontFamily(uint32_t localeListId,FamilyVariant variant,std::vector<std::shared_ptr<Font>> && fonts,bool isCustomFallback)44 FontFamily::FontFamily(uint32_t localeListId, FamilyVariant variant,
45                        std::vector<std::shared_ptr<Font>>&& fonts, bool isCustomFallback)
46         : mLocaleListId(localeListId),
47           mVariant(variant),
48           mFonts(std::move(fonts)),
49           mIsColorEmoji(LocaleListCache::getById(localeListId).getEmojiStyle() ==
50                         EmojiStyle::EMOJI),
51           mIsCustomFallback(isCustomFallback) {
52     MINIKIN_ASSERT(!mFonts.empty(), "FontFamily must contain at least one font.");
53     computeCoverage();
54 }
55 
FontFamily(uint32_t localeListId,FamilyVariant variant,std::vector<std::shared_ptr<Font>> && fonts,std::unordered_set<AxisTag> && supportedAxes,bool isColorEmoji,bool isCustomFallback,SparseBitSet && coverage,std::vector<std::unique_ptr<SparseBitSet>> && cmapFmt14Coverage)56 FontFamily::FontFamily(uint32_t localeListId, FamilyVariant variant,
57                        std::vector<std::shared_ptr<Font>>&& fonts,
58                        std::unordered_set<AxisTag>&& supportedAxes, bool isColorEmoji,
59                        bool isCustomFallback, SparseBitSet&& coverage,
60                        std::vector<std::unique_ptr<SparseBitSet>>&& cmapFmt14Coverage)
61         : mLocaleListId(localeListId),
62           mVariant(variant),
63           mFonts(std::move(fonts)),
64           mSupportedAxes(std::move(supportedAxes)),
65           mIsColorEmoji(isColorEmoji),
66           mIsCustomFallback(isCustomFallback),
67           mCoverage(std::move(coverage)),
68           mCmapFmt14Coverage(std::move(cmapFmt14Coverage)) {}
69 
70 // Read fields other than mFonts, mLocaleList.
71 // static
readFromInternal(BufferReader * reader,std::vector<std::shared_ptr<Font>> && fonts,uint32_t localeListId)72 std::shared_ptr<FontFamily> FontFamily::readFromInternal(BufferReader* reader,
73                                                          std::vector<std::shared_ptr<Font>>&& fonts,
74                                                          uint32_t localeListId) {
75     // FamilyVariant is uint8_t
76     static_assert(sizeof(FamilyVariant) == 1);
77     FamilyVariant variant = reader->read<FamilyVariant>();
78     // AxisTag is uint32_t
79     static_assert(sizeof(AxisTag) == 4);
80     const auto& [axesPtr, axesCount] = reader->readArray<AxisTag>();
81     std::unordered_set<AxisTag> supportedAxes(axesPtr, axesPtr + axesCount);
82     bool isColorEmoji = static_cast<bool>(reader->read<uint8_t>());
83     bool isCustomFallback = static_cast<bool>(reader->read<uint8_t>());
84     SparseBitSet coverage(reader);
85     // Read mCmapFmt14Coverage. As it can have null entries, it is stored in the buffer as a sparse
86     // array (size, non-null entry count, array of (index, entry)).
87     uint32_t cmapFmt14CoverageSize = reader->read<uint32_t>();
88     std::vector<std::unique_ptr<SparseBitSet>> cmapFmt14Coverage(cmapFmt14CoverageSize);
89     uint32_t cmapFmt14CoverageEntryCount = reader->read<uint32_t>();
90     for (uint32_t i = 0; i < cmapFmt14CoverageEntryCount; i++) {
91         uint32_t index = reader->read<uint32_t>();
92         cmapFmt14Coverage[index] = std::make_unique<SparseBitSet>(reader);
93     }
94     return std::shared_ptr<FontFamily>(new FontFamily(
95             localeListId, variant, std::move(fonts), std::move(supportedAxes), isColorEmoji,
96             isCustomFallback, std::move(coverage), std::move(cmapFmt14Coverage)));
97 }
98 
99 // static
readLocaleListInternal(BufferReader * reader)100 uint32_t FontFamily::readLocaleListInternal(BufferReader* reader) {
101     return LocaleListCache::readFrom(reader);
102 }
103 
104 // Write fields other than mFonts.
writeToInternal(BufferWriter * writer) const105 void FontFamily::writeToInternal(BufferWriter* writer) const {
106     writer->write<FamilyVariant>(mVariant);
107     std::vector<AxisTag> axes(mSupportedAxes.begin(), mSupportedAxes.end());
108     // Sort axes to be deterministic.
109     std::sort(axes.begin(), axes.end());
110     writer->writeArray<AxisTag>(axes.data(), axes.size());
111     writer->write<uint8_t>(mIsColorEmoji);
112     writer->write<uint8_t>(mIsCustomFallback);
113     mCoverage.writeTo(writer);
114     // Write mCmapFmt14Coverage as a sparse array (size, non-null entry count,
115     // array of (index, entry))
116     writer->write<uint32_t>(mCmapFmt14Coverage.size());
117     uint32_t cmapFmt14CoverageEntryCount = 0;
118     for (const std::unique_ptr<SparseBitSet>& coverage : mCmapFmt14Coverage) {
119         if (coverage != nullptr) cmapFmt14CoverageEntryCount++;
120     }
121     writer->write<uint32_t>(cmapFmt14CoverageEntryCount);
122     for (size_t i = 0; i < mCmapFmt14Coverage.size(); i++) {
123         if (mCmapFmt14Coverage[i] != nullptr) {
124             writer->write<uint32_t>(i);
125             mCmapFmt14Coverage[i]->writeTo(writer);
126         }
127     }
128 }
129 
writeLocaleListInternal(BufferWriter * writer) const130 void FontFamily::writeLocaleListInternal(BufferWriter* writer) const {
131     LocaleListCache::writeTo(writer, mLocaleListId);
132 }
133 // Compute a matching metric between two styles - 0 is an exact match
computeMatch(FontStyle style1,FontStyle style2)134 static int computeMatch(FontStyle style1, FontStyle style2) {
135     if (style1 == style2) return 0;
136     int score = abs(style1.weight() / 100 - style2.weight() / 100);
137     if (style1.slant() != style2.slant()) {
138         score += 2;
139     }
140     return score;
141 }
142 
computeFakery(FontStyle wanted,FontStyle actual)143 static FontFakery computeFakery(FontStyle wanted, FontStyle actual) {
144     // If desired weight is semibold or darker, and 2 or more grades
145     // higher than actual (for example, medium 500 -> bold 700), then
146     // select fake bold.
147     bool isFakeBold = wanted.weight() >= 600 && (wanted.weight() - actual.weight()) >= 200;
148     bool isFakeItalic = wanted.slant() == FontStyle::Slant::ITALIC &&
149                         actual.slant() == FontStyle::Slant::UPRIGHT;
150     return FontFakery(isFakeBold, isFakeItalic);
151 }
152 
getClosestMatch(FontStyle style) const153 FakedFont FontFamily::getClosestMatch(FontStyle style) const {
154     int bestIndex = 0;
155     Font* bestFont = mFonts[bestIndex].get();
156     int bestMatch = computeMatch(bestFont->style(), style);
157     for (size_t i = 1; i < mFonts.size(); i++) {
158         Font* font = mFonts[i].get();
159         int match = computeMatch(font->style(), style);
160         if (i == 0 || match < bestMatch) {
161             bestFont = font;
162             bestIndex = i;
163             bestMatch = match;
164         }
165     }
166     return FakedFont{mFonts[bestIndex], computeFakery(style, bestFont->style())};
167 }
168 
computeCoverage()169 void FontFamily::computeCoverage() {
170     const std::shared_ptr<Font>& font = getClosestMatch(FontStyle()).font;
171     HbBlob cmapTable(font->baseFont(), MinikinFont::MakeTag('c', 'm', 'a', 'p'));
172     if (cmapTable.get() == nullptr) {
173         ALOGE("Could not get cmap table size!\n");
174         return;
175     }
176 
177     mCoverage = CmapCoverage::getCoverage(cmapTable.get(), cmapTable.size(), &mCmapFmt14Coverage);
178 
179     for (size_t i = 0; i < mFonts.size(); ++i) {
180         std::unordered_set<AxisTag> supportedAxes = mFonts[i]->getSupportedAxes();
181         mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end());
182     }
183 }
184 
hasGlyph(uint32_t codepoint,uint32_t variationSelector) const185 bool FontFamily::hasGlyph(uint32_t codepoint, uint32_t variationSelector) const {
186     if (variationSelector == 0) {
187         return mCoverage.get(codepoint);
188     }
189 
190     if (mCmapFmt14Coverage.empty()) {
191         return false;
192     }
193 
194     const uint16_t vsIndex = getVsIndex(variationSelector);
195 
196     if (vsIndex >= mCmapFmt14Coverage.size()) {
197         // Even if vsIndex is INVALID_VS_INDEX, we reach here since INVALID_VS_INDEX is defined to
198         // be at the maximum end of the range.
199         return false;
200     }
201 
202     const std::unique_ptr<SparseBitSet>& bitset = mCmapFmt14Coverage[vsIndex];
203     if (bitset.get() == nullptr) {
204         return false;
205     }
206 
207     return bitset->get(codepoint);
208 }
209 
createFamilyWithVariation(const std::vector<FontVariation> & variations) const210 std::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation(
211         const std::vector<FontVariation>& variations) const {
212     if (variations.empty() || mSupportedAxes.empty()) {
213         return nullptr;
214     }
215 
216     bool hasSupportedAxis = false;
217     for (const FontVariation& variation : variations) {
218         if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end()) {
219             hasSupportedAxis = true;
220             break;
221         }
222     }
223     if (!hasSupportedAxis) {
224         // None of variation axes are suppored by this family.
225         return nullptr;
226     }
227 
228     std::vector<std::shared_ptr<Font>> fonts;
229     for (const auto& font : mFonts) {
230         bool supportedVariations = false;
231         std::unordered_set<AxisTag> supportedAxes = font->getSupportedAxes();
232         if (!supportedAxes.empty()) {
233             for (const FontVariation& variation : variations) {
234                 if (supportedAxes.find(variation.axisTag) != supportedAxes.end()) {
235                     supportedVariations = true;
236                     break;
237                 }
238             }
239         }
240         std::shared_ptr<MinikinFont> minikinFont;
241         if (supportedVariations) {
242             minikinFont = font->typeface()->createFontWithVariation(variations);
243         }
244         if (minikinFont == nullptr) {
245             fonts.push_back(font);
246         } else {
247             fonts.push_back(Font::Builder(minikinFont).setStyle(font->style()).build());
248         }
249     }
250 
251     return std::shared_ptr<FontFamily>(
252             new FontFamily(mLocaleListId, mVariant, std::move(fonts), mIsCustomFallback));
253 }
254 
255 }  // namespace minikin
256