Home | History | Annotate | Download | only in minikin
      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