• 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-ot.h>
27 #include <hb.h>
28 
29 #include <minikin/CmapCoverage.h>
30 #include <minikin/FontFamily.h>
31 #include <minikin/MinikinFont.h>
32 #include "FontLanguage.h"
33 #include "FontLanguageListCache.h"
34 #include "FontUtils.h"
35 #include "HbFontCache.h"
36 #include "MinikinInternal.h"
37 
38 using std::vector;
39 
40 namespace minikin {
41 
FontStyle(int variant,int weight,bool italic)42 FontStyle::FontStyle(int variant, int weight, bool italic)
43     : FontStyle(FontLanguageListCache::kEmptyListId, variant, weight, italic) {}
44 
FontStyle(uint32_t languageListId,int variant,int weight,bool italic)45 FontStyle::FontStyle(uint32_t languageListId,
46                      int variant,
47                      int weight,
48                      bool italic)
49     : bits(pack(variant, weight, italic)), mLanguageListId(languageListId) {}
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   std::scoped_lock _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) |
66          (variant << kVariantShift);
67 }
68 
Font(const std::shared_ptr<MinikinFont> & typeface,FontStyle style)69 Font::Font(const std::shared_ptr<MinikinFont>& typeface, FontStyle style)
70     : typeface(typeface), style(style) {}
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 
getSupportedAxesLocked() const75 std::unordered_set<AxisTag> Font::getSupportedAxesLocked() const {
76   const uint32_t fvarTag = MinikinFont::MakeTag('f', 'v', 'a', 'r');
77   HbBlob fvarTable(getFontTable(typeface.get(), fvarTag));
78   if (fvarTable.size() == 0) {
79     return std::unordered_set<AxisTag>();
80   }
81 
82   std::unordered_set<AxisTag> supportedAxes;
83   analyzeAxes(fvarTable.get(), fvarTable.size(), &supportedAxes);
84   return supportedAxes;
85 }
86 
Font(Font && o)87 Font::Font(Font&& o) {
88   typeface = std::move(o.typeface);
89   style = o.style;
90   o.typeface = nullptr;
91 }
92 
Font(const Font & o)93 Font::Font(const Font& o) {
94   typeface = o.typeface;
95   style = o.style;
96 }
97 
98 // static
FontFamily(std::vector<Font> && fonts)99 FontFamily::FontFamily(std::vector<Font>&& fonts)
100     : FontFamily(0 /* variant */, std::move(fonts)) {}
101 
FontFamily(int variant,std::vector<Font> && fonts)102 FontFamily::FontFamily(int variant, std::vector<Font>&& fonts)
103     : FontFamily(FontLanguageListCache::kEmptyListId,
104                  variant,
105                  std::move(fonts)) {}
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),
109       mVariant(variant),
110       mFonts(std::move(fonts)),
111       mHasVSTable(false) {
112   computeCoverage();
113 }
114 
analyzeStyle(const std::shared_ptr<MinikinFont> & typeface,int * weight,bool * italic)115 bool FontFamily::analyzeStyle(const std::shared_ptr<MinikinFont>& typeface,
116                               int* weight,
117                               bool* italic) {
118   std::scoped_lock _l(gMinikinLock);
119   const uint32_t os2Tag = MinikinFont::MakeTag('O', 'S', '/', '2');
120   HbBlob os2Table(getFontTable(typeface.get(), os2Tag));
121   if (os2Table.get() == nullptr)
122     return false;
123   return ::minikin::analyzeStyle(os2Table.get(), os2Table.size(), weight,
124                                  italic);
125 }
126 
getHwFontFamilyType()127 int FontFamily::getHwFontFamilyType() {
128   return mHwFontFamilyType;
129 }
130 
setHwFontFamilyType(int HwFontFamilyType)131 void FontFamily::setHwFontFamilyType(int HwFontFamilyType) {
132   mHwFontFamilyType = HwFontFamilyType;
133 }
134 
135 // Compute a matching metric between two styles - 0 is an exact match
computeMatch(FontStyle style1,FontStyle style2)136 static int computeMatch(FontStyle style1, FontStyle style2) {
137   if (style1 == style2)
138     return 0;
139   int score = abs(style1.getWeight() - style2.getWeight());
140   if (style1.getItalic() != style2.getItalic()) {
141     score += 2;
142   }
143   return score;
144 }
145 
computeFakery(FontStyle wanted,FontStyle actual)146 static FontFakery computeFakery(FontStyle wanted, FontStyle actual) {
147   // If desired weight is semibold or darker, and 2 or more grades
148   // higher than actual (for example, medium 500 -> bold 700), then
149   // select fake bold.
150   int wantedWeight = wanted.getWeight();
151   bool isFakeBold =
152       wantedWeight >= 6 && (wantedWeight - actual.getWeight()) >= 2;
153   bool isFakeItalic = wanted.getItalic() && !actual.getItalic();
154   return FontFakery(isFakeBold, isFakeItalic);
155 }
156 
getClosestMatch(FontStyle style) const157 FakedFont FontFamily::getClosestMatch(FontStyle style) const {
158   const Font* bestFont = nullptr;
159   int bestMatch = 0;
160   for (size_t i = 0; i < mFonts.size(); i++) {
161     const Font& font = mFonts[i];
162     int match = computeMatch(font.style, style);
163     if (i == 0 || match < bestMatch) {
164       bestFont = &font;
165       bestMatch = match;
166     }
167   }
168   if (bestFont != nullptr) {
169     return FakedFont{bestFont->typeface.get(),
170                      computeFakery(style, bestFont->style)};
171   }
172   return FakedFont{nullptr, FontFakery()};
173 }
174 
isColorEmojiFamily() const175 bool FontFamily::isColorEmojiFamily() const {
176   const FontLanguages& languageList = FontLanguageListCache::getById(mLangId);
177   for (size_t i = 0; i < languageList.size(); ++i) {
178     if (languageList[i].getEmojiStyle() == FontLanguage::EMSTYLE_EMOJI) {
179       return true;
180     }
181   }
182   return false;
183 }
184 
computeCoverage()185 void FontFamily::computeCoverage() {
186   std::scoped_lock _l(gMinikinLock);
187   const FontStyle defaultStyle;
188   const MinikinFont* typeface = getClosestMatch(defaultStyle).font;
189   const uint32_t cmapTag = MinikinFont::MakeTag('c', 'm', 'a', 'p');
190   HbBlob cmapTable(getFontTable(typeface, cmapTag));
191   if (cmapTable.get() == nullptr) {
192     ALOGE("Could not get cmap table size!\n");
193     return;
194   }
195   mCoverage = CmapCoverage::getCoverage(cmapTable.get(), cmapTable.size(),
196                                         &mHasVSTable);
197 
198   for (size_t i = 0; i < mFonts.size(); ++i) {
199     std::unordered_set<AxisTag> supportedAxes =
200         mFonts[i].getSupportedAxesLocked();
201     mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end());
202   }
203 }
204 
hasGlyph(uint32_t codepoint,uint32_t variationSelector) const205 bool FontFamily::hasGlyph(uint32_t codepoint,
206                           uint32_t variationSelector) const {
207   assertMinikinLocked();
208   if (variationSelector != 0 && !mHasVSTable) {
209     // Early exit if the variation selector is specified but the font doesn't
210     // have a cmap format 14 subtable.
211     return false;
212   }
213 
214   const FontStyle defaultStyle;
215   hb_font_t* font = getHbFontLocked(getClosestMatch(defaultStyle).font);
216   uint32_t unusedGlyph;
217   bool result =
218       hb_font_get_glyph(font, codepoint, variationSelector, &unusedGlyph);
219   hb_font_destroy(font);
220   return result;
221 }
222 
createFamilyWithVariation(const std::vector<FontVariation> & variations) const223 std::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation(
224     const std::vector<FontVariation>& variations) const {
225   if (variations.empty() || mSupportedAxes.empty()) {
226     return nullptr;
227   }
228 
229   bool hasSupportedAxis = false;
230   for (const FontVariation& variation : variations) {
231     if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end()) {
232       hasSupportedAxis = true;
233       break;
234     }
235   }
236   if (!hasSupportedAxis) {
237     // None of variation axes are suppored by this family.
238     return nullptr;
239   }
240 
241   std::vector<Font> fonts;
242   for (const Font& font : mFonts) {
243     bool supportedVariations = false;
244     std::scoped_lock _l(gMinikinLock);
245     std::unordered_set<AxisTag> supportedAxes = font.getSupportedAxesLocked();
246     if (!supportedAxes.empty()) {
247       for (const FontVariation& variation : variations) {
248         if (supportedAxes.find(variation.axisTag) != supportedAxes.end()) {
249           supportedVariations = true;
250           break;
251         }
252       }
253     }
254     std::shared_ptr<MinikinFont> minikinFont;
255     if (supportedVariations) {
256       minikinFont = font.typeface->createFontWithVariation(variations);
257     }
258     if (minikinFont == nullptr) {
259       minikinFont = font.typeface;
260     }
261     fonts.push_back(Font(std::move(minikinFont), font.style));
262   }
263 
264   return std::shared_ptr<FontFamily>(
265       new FontFamily(mLangId, mVariant, std::move(fonts)));
266 }
267 
268 }  // namespace minikin
269