FontFamily.cpp 8.1 KB
Newer Older
R
Raph Levien 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "Minikin"

#include <stdint.h>
20
#include <stdlib.h>
21
#include <string.h>
22

23
#include <log/log.h>
24 25
#include <utils/JenkinsHash.h>

26 27 28
#include <hb.h>
#include <hb-ot.h>

29
#include "FontLanguage.h"
S
Seigo Nonaka 已提交
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>
R
Raph Levien 已提交
36
#include <minikin/FontFamily.h>
37
#include <minikin/MinikinFont.h>
R
Raph Levien 已提交
38 39 40

using std::vector;

S
Seigo Nonaka 已提交
41
namespace minikin {
R
Raph Levien 已提交
42

S
Seigo Nonaka 已提交
43
FontStyle::FontStyle(int variant, int weight, bool italic)
44
        : FontStyle(FontLanguageListCache::kEmptyListId, variant, weight, italic) {
S
Seigo Nonaka 已提交
45 46 47 48 49 50
}

FontStyle::FontStyle(uint32_t languageListId, int variant, int weight, bool italic)
        : bits(pack(variant, weight, italic)), mLanguageListId(languageListId) {
}

S
Seigo Nonaka 已提交
51 52 53 54
android::hash_t FontStyle::hash() const {
    uint32_t hash = android::JenkinsHashMix(0, bits);
    hash = android::JenkinsHashMix(hash, mLanguageListId);
    return android::JenkinsHashWhiten(hash);
S
Seigo Nonaka 已提交
55 56 57 58
}

// static
uint32_t FontStyle::registerLanguageList(const std::string& languages) {
59 60
    android::AutoMutex _l(gMinikinLock);
    return FontLanguageListCache::getId(languages);
S
Seigo Nonaka 已提交
61 62 63 64 65 66 67
}

// static
uint32_t FontStyle::pack(int variant, int weight, bool italic) {
    return (weight & kWeightMask) | (italic ? kItalicMask : 0) | (variant << kVariantShift);
}

68
Font::Font(const std::shared_ptr<MinikinFont>& typeface, FontStyle style)
69
    : typeface(typeface), style(style) {
70 71 72 73 74
}

Font::Font(std::shared_ptr<MinikinFont>&& typeface, FontStyle style)
    : typeface(typeface), style(style) {
}
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 91
    style = o.style;
    o.typeface = nullptr;
92 93
}

94 95 96
Font::Font(const Font& o) {
    typeface = o.typeface;
    style = o.style;
97 98
}

99
// static
100 101 102 103
FontFamily::FontFamily(std::vector<Font>&& fonts) : FontFamily(0 /* variant */, std::move(fonts)) {
}

FontFamily::FontFamily(int variant, std::vector<Font>&& fonts)
104
    : FontFamily(FontLanguageListCache::kEmptyListId, variant, std::move(fonts)) {
105 106 107 108 109 110 111
}

FontFamily::FontFamily(uint32_t langId, int variant, std::vector<Font>&& fonts)
    : mLangId(langId), mVariant(variant), mFonts(std::move(fonts)), mHasVSTable(false) {
    computeCoverage();
}

112 113
bool FontFamily::analyzeStyle(const std::shared_ptr<MinikinFont>& typeface, int* weight,
        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 118
    if (os2Table.get() == nullptr) return false;
    return ::minikin::analyzeStyle(os2Table.get(), os2Table.size(), weight, italic);
R
Raph Levien 已提交
119 120 121
}

// Compute a matching metric between two styles - 0 is an exact match
R
Raph Levien 已提交
122
static int computeMatch(FontStyle style1, FontStyle style2) {
R
Raph Levien 已提交
123 124 125 126 127 128 129 130
    if (style1 == style2) return 0;
    int score = abs(style1.getWeight() - style2.getWeight());
    if (style1.getItalic() != style2.getItalic()) {
        score += 2;
    }
    return score;
}

R
Raph Levien 已提交
131
static FontFakery computeFakery(FontStyle wanted, FontStyle actual) {
R
Raph Levien 已提交
132 133 134
    // If desired weight is semibold or darker, and 2 or more grades
    // higher than actual (for example, medium 500 -> bold 700), then
    // select fake bold.
R
Raph Levien 已提交
135
    int wantedWeight = wanted.getWeight();
R
Raph Levien 已提交
136
    bool isFakeBold = wantedWeight >= 6 && (wantedWeight - actual.getWeight()) >= 2;
R
Raph Levien 已提交
137 138 139 140 141
    bool isFakeItalic = wanted.getItalic() && !actual.getItalic();
    return FontFakery(isFakeBold, isFakeItalic);
}

FakedFont FontFamily::getClosestMatch(FontStyle style) const {
142
    const Font* bestFont = nullptr;
R
Raph Levien 已提交
143 144 145 146 147 148 149 150 151
    int bestMatch = 0;
    for (size_t i = 0; i < mFonts.size(); i++) {
        const Font& font = mFonts[i];
        int match = computeMatch(font.style, style);
        if (i == 0 || match < bestMatch) {
            bestFont = &font;
            bestMatch = match;
        }
    }
152 153
    if (bestFont != nullptr) {
        return FakedFont{ bestFont->typeface.get(), computeFakery(style, bestFont->style) };
R
Raph Levien 已提交
154
    }
155
    return FakedFont{ nullptr, FontFakery() };
R
Raph Levien 已提交
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 163 164 165 166 167
            return true;
        }
    }
    return false;
}

168
void FontFamily::computeCoverage() {
169
    android::AutoMutex _l(gMinikinLock);
170
    const FontStyle defaultStyle;
171
    const MinikinFont* typeface = getClosestMatch(defaultStyle).font;
172 173 174 175 176 177 178 179
    const uint32_t cmapTag = MinikinFont::MakeTag('c', 'm', 'a', 'p');
    HbBlob cmapTable(getFontTable(typeface, cmapTag));
    if (cmapTable.get() == nullptr) {
        ALOGE("Could not get cmap table size!\n");
        return;
    }
    // TODO: Error check?
    CmapCoverage::getCoverage(mCoverage, cmapTable.get(), cmapTable.size(), &mHasVSTable);
180 181

    for (size_t i = 0; i < mFonts.size(); ++i) {
182 183
        std::unordered_set<AxisTag> supportedAxes = mFonts[i].getSupportedAxesLocked();
        mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end());
184
    }
185 186
}

187
bool FontFamily::hasGlyph(uint32_t codepoint, uint32_t variationSelector) const {
188
    assertMinikinLocked();
189 190 191
    if (variationSelector != 0 && !mHasVSTable) {
        // Early exit if the variation selector is specified but the font doesn't have a cmap format
        // 14 subtable.
192 193 194
        return false;
    }

195
    const FontStyle defaultStyle;
196
    hb_font_t* font = getHbFontLocked(getClosestMatch(defaultStyle).font);
197
    uint32_t unusedGlyph;
R
Raph Levien 已提交
198 199 200
    bool result = hb_font_get_glyph(font, codepoint, variationSelector, &unusedGlyph);
    hb_font_destroy(font);
    return result;
201 202
}

203
std::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation(
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
        const std::vector<FontVariation>& variations) const {
    if (variations.empty() || mSupportedAxes.empty()) {
        return nullptr;
    }

    bool hasSupportedAxis = false;
    for (const FontVariation& variation : variations) {
        if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end()) {
            hasSupportedAxis = true;
            break;
        }
    }
    if (!hasSupportedAxis) {
        // None of variation axes are suppored by this family.
        return nullptr;
    }

    std::vector<Font> fonts;
    for (const Font& font : mFonts) {
        bool supportedVariations = false;
224 225 226
        android::AutoMutex _l(gMinikinLock);
        std::unordered_set<AxisTag> supportedAxes = font.getSupportedAxesLocked();
        if (!supportedAxes.empty()) {
227
            for (const FontVariation& variation : variations) {
228
                if (supportedAxes.find(variation.axisTag) != supportedAxes.end()) {
229 230 231 232 233
                    supportedVariations = true;
                    break;
                }
            }
        }
234
        std::shared_ptr<MinikinFont> minikinFont;
235 236 237 238 239 240
        if (supportedVariations) {
            minikinFont = font.typeface->createFontWithVariation(variations);
        }
        if (minikinFont == nullptr) {
            minikinFont = font.typeface;
        }
241
        fonts.push_back(Font(std::move(minikinFont), font.style));
242 243
    }

244
    return std::shared_ptr<FontFamily>(new FontFamily(mLangId, mVariant, std::move(fonts)));
245 246
}

S
Seigo Nonaka 已提交
247
}  // namespace minikin