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 <cstdint> 22 #include <vector> 23 24 #include <hb-ot.h> 25 #include <hb.h> 26 #include <log/log.h> 27 #include <utils/JenkinsHash.h> 28 29 #include "minikin/CmapCoverage.h" 30 #include "minikin/HbUtils.h" 31 #include "minikin/MinikinFont.h" 32 33 #include "FontUtils.h" 34 #include "Locale.h" 35 #include "LocaleListCache.h" 36 #include "MinikinInternal.h" 37 38 namespace minikin { 39 40 Font Font::Builder::build() { 41 if (mIsWeightSet && mIsSlantSet) { 42 // No need to read OS/2 header of the font file. 43 return Font(std::move(mTypeface), FontStyle(mWeight, mSlant), prepareFont(mTypeface)); 44 } 45 46 HbFontUniquePtr font = prepareFont(mTypeface); 47 FontStyle styleFromFont = analyzeStyle(font); 48 if (!mIsWeightSet) { 49 mWeight = styleFromFont.weight(); 50 } 51 if (!mIsSlantSet) { 52 mSlant = styleFromFont.slant(); 53 } 54 return Font(std::move(mTypeface), FontStyle(mWeight, mSlant), std::move(font)); 55 } 56 57 // static 58 HbFontUniquePtr Font::prepareFont(const std::shared_ptr<MinikinFont>& typeface) { 59 const char* buf = reinterpret_cast<const char*>(typeface->GetFontData()); 60 size_t size = typeface->GetFontSize(); 61 uint32_t ttcIndex = typeface->GetFontIndex(); 62 63 HbBlobUniquePtr blob(hb_blob_create(buf, size, HB_MEMORY_MODE_READONLY, nullptr, nullptr)); 64 HbFaceUniquePtr face(hb_face_create(blob.get(), ttcIndex)); 65 HbFontUniquePtr parent(hb_font_create(face.get())); 66 hb_ot_font_set_funcs(parent.get()); 67 68 uint32_t upem = hb_face_get_upem(face.get()); 69 hb_font_set_scale(parent.get(), upem, upem); 70 71 HbFontUniquePtr font(hb_font_create_sub_font(parent.get())); 72 std::vector<hb_variation_t> variations; 73 variations.reserve(typeface->GetAxes().size()); 74 for (const FontVariation& variation : typeface->GetAxes()) { 75 variations.push_back({variation.axisTag, variation.value}); 76 } 77 hb_font_set_variations(font.get(), variations.data(), variations.size()); 78 return font; 79 } 80 81 // static 82 FontStyle Font::analyzeStyle(const HbFontUniquePtr& font) { 83 HbBlob os2Table(font, MinikinFont::MakeTag('O', 'S', '/', '2')); 84 if (!os2Table) { 85 return FontStyle(); 86 } 87 88 int weight; 89 bool italic; 90 if (!::minikin::analyzeStyle(os2Table.get(), os2Table.size(), &weight, &italic)) { 91 return FontStyle(); 92 } 93 // TODO: Update weight/italic based on fvar value. 94 return FontStyle(static_cast<uint16_t>(weight), static_cast<FontStyle::Slant>(italic)); 95 } 96 97 std::unordered_set<AxisTag> Font::getSupportedAxes() const { 98 HbBlob fvarTable(mBaseFont, MinikinFont::MakeTag('f', 'v', 'a', 'r')); 99 if (!fvarTable) { 100 return std::unordered_set<AxisTag>(); 101 } 102 std::unordered_set<AxisTag> supportedAxes; 103 analyzeAxes(fvarTable.get(), fvarTable.size(), &supportedAxes); 104 return supportedAxes; 105 } 106 107 FontFamily::FontFamily(std::vector<Font>&& fonts) 108 : FontFamily(Variant::DEFAULT, std::move(fonts)) {} 109 110 FontFamily::FontFamily(Variant variant, std::vector<Font>&& fonts) 111 : FontFamily(LocaleListCache::kEmptyListId, variant, std::move(fonts)) {} 112 113 FontFamily::FontFamily(uint32_t localeListId, Variant variant, std::vector<Font>&& fonts) 114 : mLocaleListId(localeListId), 115 mVariant(variant), 116 mFonts(std::move(fonts)), 117 mIsColorEmoji(LocaleListCache::getById(localeListId).getEmojiStyle() == 118 EmojiStyle::EMOJI) { 119 MINIKIN_ASSERT(!mFonts.empty(), "FontFamily must contain at least one font."); 120 computeCoverage(); 121 } 122 123 // Compute a matching metric between two styles - 0 is an exact match 124 static int computeMatch(FontStyle style1, FontStyle style2) { 125 if (style1 == style2) return 0; 126 int score = abs(style1.weight() / 100 - style2.weight() / 100); 127 if (style1.slant() != style2.slant()) { 128 score += 2; 129 } 130 return score; 131 } 132 133 static FontFakery computeFakery(FontStyle wanted, FontStyle actual) { 134 // If desired weight is semibold or darker, and 2 or more grades 135 // higher than actual (for example, medium 500 -> bold 700), then 136 // select fake bold. 137 bool isFakeBold = wanted.weight() >= 600 && (wanted.weight() - actual.weight()) >= 200; 138 bool isFakeItalic = wanted.slant() == FontStyle::Slant::ITALIC && 139 actual.slant() == FontStyle::Slant::UPRIGHT; 140 return FontFakery(isFakeBold, isFakeItalic); 141 } 142 143 FakedFont FontFamily::getClosestMatch(FontStyle style) const { 144 const Font* bestFont = &mFonts[0]; 145 int bestMatch = computeMatch(bestFont->style(), style); 146 for (size_t i = 1; i < mFonts.size(); i++) { 147 const Font& font = mFonts[i]; 148 int match = computeMatch(font.style(), style); 149 if (i == 0 || match < bestMatch) { 150 bestFont = &font; 151 bestMatch = match; 152 } 153 } 154 return FakedFont{bestFont, computeFakery(style, bestFont->style())}; 155 } 156 157 void FontFamily::computeCoverage() { 158 const Font* font = getClosestMatch(FontStyle()).font; 159 HbBlob cmapTable(font->baseFont(), MinikinFont::MakeTag('c', 'm', 'a', 'p')); 160 if (cmapTable.get() == nullptr) { 161 ALOGE("Could not get cmap table size!\n"); 162 return; 163 } 164 165 mCoverage = CmapCoverage::getCoverage(cmapTable.get(), cmapTable.size(), &mCmapFmt14Coverage); 166 167 for (size_t i = 0; i < mFonts.size(); ++i) { 168 std::unordered_set<AxisTag> supportedAxes = mFonts[i].getSupportedAxes(); 169 mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end()); 170 } 171 } 172 173 bool FontFamily::hasGlyph(uint32_t codepoint, uint32_t variationSelector) const { 174 if (variationSelector == 0) { 175 return mCoverage.get(codepoint); 176 } 177 178 if (mCmapFmt14Coverage.empty()) { 179 return false; 180 } 181 182 const uint16_t vsIndex = getVsIndex(variationSelector); 183 184 if (vsIndex >= mCmapFmt14Coverage.size()) { 185 // Even if vsIndex is INVALID_VS_INDEX, we reach here since INVALID_VS_INDEX is defined to 186 // be at the maximum end of the range. 187 return false; 188 } 189 190 const std::unique_ptr<SparseBitSet>& bitset = mCmapFmt14Coverage[vsIndex]; 191 if (bitset.get() == nullptr) { 192 return false; 193 } 194 195 return bitset->get(codepoint); 196 } 197 198 std::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation( 199 const std::vector<FontVariation>& variations) const { 200 if (variations.empty() || mSupportedAxes.empty()) { 201 return nullptr; 202 } 203 204 bool hasSupportedAxis = false; 205 for (const FontVariation& variation : variations) { 206 if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end()) { 207 hasSupportedAxis = true; 208 break; 209 } 210 } 211 if (!hasSupportedAxis) { 212 // None of variation axes are suppored by this family. 213 return nullptr; 214 } 215 216 std::vector<Font> fonts; 217 for (const Font& font : mFonts) { 218 bool supportedVariations = false; 219 std::unordered_set<AxisTag> supportedAxes = font.getSupportedAxes(); 220 if (!supportedAxes.empty()) { 221 for (const FontVariation& variation : variations) { 222 if (supportedAxes.find(variation.axisTag) != supportedAxes.end()) { 223 supportedVariations = true; 224 break; 225 } 226 } 227 } 228 std::shared_ptr<MinikinFont> minikinFont; 229 if (supportedVariations) { 230 minikinFont = font.typeface()->createFontWithVariation(variations); 231 } 232 if (minikinFont == nullptr) { 233 minikinFont = font.typeface(); 234 } 235 fonts.push_back(Font::Builder(minikinFont).setStyle(font.style()).build()); 236 } 237 238 return std::shared_ptr<FontFamily>(new FontFamily(mLocaleListId, mVariant, std::move(fonts))); 239 } 240 241 } // namespace minikin 242