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 43 FontStyle::FontStyle(int variant, int weight, bool italic) 44 : FontStyle(FontLanguageListCache::kEmptyListId, variant, weight, italic) { 45 } 46 47 FontStyle::FontStyle(uint32_t languageListId, int variant, int weight, bool italic) 48 : bits(pack(variant, weight, italic)), mLanguageListId(languageListId) { 49 } 50 51 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 58 uint32_t FontStyle::registerLanguageList(const std::string& languages) { 59 android::AutoMutex _l(gMinikinLock); 60 return FontLanguageListCache::getId(languages); 61 } 62 63 // static 64 uint32_t FontStyle::pack(int variant, int weight, bool italic) { 65 return (weight & kWeightMask) | (italic ? kItalicMask : 0) | (variant << kVariantShift); 66 } 67 68 Font::Font(const std::shared_ptr<MinikinFont>& typeface, FontStyle style) 69 : typeface(typeface), style(style) { 70 } 71 72 Font::Font(std::shared_ptr<MinikinFont>&& typeface, FontStyle style) 73 : typeface(typeface), style(style) { 74 } 75 76 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 88 Font::Font(Font&& o) { 89 typeface = std::move(o.typeface); 90 style = o.style; 91 o.typeface = nullptr; 92 } 93 94 Font::Font(const Font& o) { 95 typeface = o.typeface; 96 style = o.style; 97 } 98 99 // static 100 FontFamily::FontFamily(std::vector<Font>&& fonts) : FontFamily(0 /* variant */, std::move(fonts)) { 101 } 102 103 FontFamily::FontFamily(int variant, std::vector<Font>&& fonts) 104 : FontFamily(FontLanguageListCache::kEmptyListId, variant, std::move(fonts)) { 105 } 106 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 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 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 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 141 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 158 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 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 186 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 211 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