• 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 <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include <log/log.h>
24 #include <utils/JenkinsHash.h>
25 
26 #include <hb.h>
27 #include <hb-ot.h>
28 
29 #include "FontLanguage.h"
30 #include "FontLanguageListCache.h"
31 #include "FontUtils.h"
32 #include "HbFontCache.h"
33 #include "MinikinInternal.h"
34 #include <minikin/CmapCoverage.h>
35 #include <minikin/MinikinFont.h>
36 #include <minikin/FontFamily.h>
37 #include <minikin/MinikinFont.h>
38 
39 using std::vector;
40 
41 namespace minikin {
42 
FontStyle(int variant,int weight,bool italic)43 FontStyle::FontStyle(int variant, int weight, bool italic)
44         : FontStyle(FontLanguageListCache::kEmptyListId, variant, weight, italic) {
45 }
46 
FontStyle(uint32_t languageListId,int variant,int weight,bool italic)47 FontStyle::FontStyle(uint32_t languageListId, int variant, int weight, bool italic)
48         : bits(pack(variant, weight, italic)), mLanguageListId(languageListId) {
49 }
50 
hash() const51 android::hash_t FontStyle::hash() const {
52     uint32_t hash = android::JenkinsHashMix(0, bits);
53     hash = android::JenkinsHashMix(hash, mLanguageListId);
54     return android::JenkinsHashWhiten(hash);
55 }
56 
57 // static
registerLanguageList(const std::string & languages)58 uint32_t FontStyle::registerLanguageList(const std::string& languages) {
59     android::AutoMutex _l(gMinikinLock);
60     return FontLanguageListCache::getId(languages);
61 }
62 
63 // static
pack(int variant,int weight,bool italic)64 uint32_t FontStyle::pack(int variant, int weight, bool italic) {
65     return (weight & kWeightMask) | (italic ? kItalicMask : 0) | (variant << kVariantShift);
66 }
67 
Font(const std::shared_ptr<MinikinFont> & typeface,FontStyle style)68 Font::Font(const std::shared_ptr<MinikinFont>& typeface, FontStyle style)
69     : typeface(typeface), style(style) {
70 }
71 
Font(std::shared_ptr<MinikinFont> && typeface,FontStyle style)72 Font::Font(std::shared_ptr<MinikinFont>&& typeface, FontStyle style)
73     : typeface(typeface), style(style) {
74 }
75 
getSupportedAxesLocked() const76 std::unordered_set<AxisTag> Font::getSupportedAxesLocked() const {
77     const uint32_t fvarTag = MinikinFont::MakeTag('f', 'v', 'a', 'r');
78     HbBlob fvarTable(getFontTable(typeface.get(), fvarTag));
79     if (fvarTable.size() == 0) {
80         return std::unordered_set<AxisTag>();
81     }
82 
83     std::unordered_set<AxisTag> supportedAxes;
84     analyzeAxes(fvarTable.get(), fvarTable.size(), &supportedAxes);
85     return supportedAxes;
86 }
87 
Font(Font && o)88 Font::Font(Font&& o) {
89     typeface = std::move(o.typeface);
90     style = o.style;
91     o.typeface = nullptr;
92 }
93 
Font(const Font & o)94 Font::Font(const Font& o) {
95     typeface = o.typeface;
96     style = o.style;
97 }
98 
99 // static
FontFamily(std::vector<Font> && fonts)100 FontFamily::FontFamily(std::vector<Font>&& fonts) : FontFamily(0 /* variant */, std::move(fonts)) {
101 }
102 
FontFamily(int variant,std::vector<Font> && fonts)103 FontFamily::FontFamily(int variant, std::vector<Font>&& fonts)
104     : FontFamily(FontLanguageListCache::kEmptyListId, variant, std::move(fonts)) {
105 }
106 
FontFamily(uint32_t langId,int variant,std::vector<Font> && fonts)107 FontFamily::FontFamily(uint32_t langId, int variant, std::vector<Font>&& fonts)
108     : mLangId(langId), mVariant(variant), mFonts(std::move(fonts)) {
109     computeCoverage();
110 }
111 
analyzeStyle(const std::shared_ptr<MinikinFont> & typeface,int * weight,bool * italic)112 bool FontFamily::analyzeStyle(const std::shared_ptr<MinikinFont>& typeface, int* weight,
113         bool* italic) {
114     android::AutoMutex _l(gMinikinLock);
115     const uint32_t os2Tag = MinikinFont::MakeTag('O', 'S', '/', '2');
116     HbBlob os2Table(getFontTable(typeface.get(), os2Tag));
117     if (os2Table.get() == nullptr) return false;
118     return ::minikin::analyzeStyle(os2Table.get(), os2Table.size(), weight, italic);
119 }
120 
121 // Compute a matching metric between two styles - 0 is an exact match
computeMatch(FontStyle style1,FontStyle style2)122 static int computeMatch(FontStyle style1, FontStyle style2) {
123     if (style1 == style2) return 0;
124     int score = abs(style1.getWeight() - style2.getWeight());
125     if (style1.getItalic() != style2.getItalic()) {
126         score += 2;
127     }
128     return score;
129 }
130 
computeFakery(FontStyle wanted,FontStyle actual)131 static FontFakery computeFakery(FontStyle wanted, FontStyle actual) {
132     // If desired weight is semibold or darker, and 2 or more grades
133     // higher than actual (for example, medium 500 -> bold 700), then
134     // select fake bold.
135     int wantedWeight = wanted.getWeight();
136     bool isFakeBold = wantedWeight >= 6 && (wantedWeight - actual.getWeight()) >= 2;
137     bool isFakeItalic = wanted.getItalic() && !actual.getItalic();
138     return FontFakery(isFakeBold, isFakeItalic);
139 }
140 
getClosestMatch(FontStyle style) const141 FakedFont FontFamily::getClosestMatch(FontStyle style) const {
142     const Font* bestFont = nullptr;
143     int bestMatch = 0;
144     for (size_t i = 0; i < mFonts.size(); i++) {
145         const Font& font = mFonts[i];
146         int match = computeMatch(font.style, style);
147         if (i == 0 || match < bestMatch) {
148             bestFont = &font;
149             bestMatch = match;
150         }
151     }
152     if (bestFont != nullptr) {
153         return FakedFont{ bestFont->typeface.get(), computeFakery(style, bestFont->style) };
154     }
155     return FakedFont{ nullptr, FontFakery() };
156 }
157 
isColorEmojiFamily() const158 bool FontFamily::isColorEmojiFamily() const {
159     const FontLanguages& languageList = FontLanguageListCache::getById(mLangId);
160     for (size_t i = 0; i < languageList.size(); ++i) {
161         if (languageList[i].getEmojiStyle() == FontLanguage::EMSTYLE_EMOJI) {
162             return true;
163         }
164     }
165     return false;
166 }
167 
computeCoverage()168 void FontFamily::computeCoverage() {
169     android::AutoMutex _l(gMinikinLock);
170     const FontStyle defaultStyle;
171     const MinikinFont* typeface = getClosestMatch(defaultStyle).font;
172     const uint32_t cmapTag = MinikinFont::MakeTag('c', 'm', 'a', 'p');
173     HbBlob cmapTable(getFontTable(typeface, cmapTag));
174     if (cmapTable.get() == nullptr) {
175         ALOGE("Could not get cmap table size!\n");
176         return;
177     }
178     mCoverage = CmapCoverage::getCoverage(cmapTable.get(), cmapTable.size(), &mCmapFmt14Coverage);
179 
180     for (size_t i = 0; i < mFonts.size(); ++i) {
181         std::unordered_set<AxisTag> supportedAxes = mFonts[i].getSupportedAxesLocked();
182         mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end());
183     }
184 }
185 
hasGlyph(uint32_t codepoint,uint32_t variationSelector) const186 bool FontFamily::hasGlyph(uint32_t codepoint, uint32_t variationSelector) const {
187     if (variationSelector == 0) {
188         return mCoverage.get(codepoint);
189     }
190 
191     if (mCmapFmt14Coverage.empty()) {
192         return false;
193     }
194 
195     const uint16_t vsIndex = getVsIndex(variationSelector);
196 
197     if (vsIndex >= mCmapFmt14Coverage.size()) {
198         // Even if vsIndex is INVALID_VS_INDEX, we reach here since INVALID_VS_INDEX is defined to
199         // be at the maximum end of the range.
200         return false;
201     }
202 
203     const std::unique_ptr<SparseBitSet>& bitset = mCmapFmt14Coverage[vsIndex];
204     if (bitset.get() == nullptr) {
205         return false;
206     }
207 
208     return bitset->get(codepoint);
209 }
210 
createFamilyWithVariation(const std::vector<FontVariation> & variations) const211 std::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation(
212         const std::vector<FontVariation>& variations) const {
213     if (variations.empty() || mSupportedAxes.empty()) {
214         return nullptr;
215     }
216 
217     bool hasSupportedAxis = false;
218     for (const FontVariation& variation : variations) {
219         if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end()) {
220             hasSupportedAxis = true;
221             break;
222         }
223     }
224     if (!hasSupportedAxis) {
225         // None of variation axes are suppored by this family.
226         return nullptr;
227     }
228 
229     std::vector<Font> fonts;
230     for (const Font& font : mFonts) {
231         bool supportedVariations = false;
232         android::AutoMutex _l(gMinikinLock);
233         std::unordered_set<AxisTag> supportedAxes = font.getSupportedAxesLocked();
234         if (!supportedAxes.empty()) {
235             for (const FontVariation& variation : variations) {
236                 if (supportedAxes.find(variation.axisTag) != supportedAxes.end()) {
237                     supportedVariations = true;
238                     break;
239                 }
240             }
241         }
242         std::shared_ptr<MinikinFont> minikinFont;
243         if (supportedVariations) {
244             minikinFont = font.typeface->createFontWithVariation(variations);
245         }
246         if (minikinFont == nullptr) {
247             minikinFont = font.typeface;
248         }
249         fonts.push_back(Font(std::move(minikinFont), font.style));
250     }
251 
252     return std::shared_ptr<FontFamily>(new FontFamily(mLangId, mVariant, std::move(fonts)));
253 }
254 
255 }  // namespace minikin
256