FontCollection.cpp 20.5 KB
Newer Older
R
Raph Levien 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * 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.
 */

17 18 19
// #define VERBOSE_DEBUG

#define LOG_TAG "Minikin"
20

21
#include <algorithm>
R
Raph Levien 已提交
22

23
#include <log/log.h>
24 25 26
#include "unicode/unistr.h"
#include "unicode/unorm2.h"

27
#include "FontLanguage.h"
S
Seigo Nonaka 已提交
28
#include "FontLanguageListCache.h"
29
#include "MinikinInternal.h"
R
Raph Levien 已提交
30 31 32 33
#include <minikin/FontCollection.h>

using std::vector;

S
Seigo Nonaka 已提交
34
namespace minikin {
R
Raph Levien 已提交
35 36 37 38 39 40

template <typename T>
static inline T max(T a, T b) {
    return a>b ? a : b;
}

41 42 43
const uint32_t EMOJI_STYLE_VS = 0xFE0F;
const uint32_t TEXT_STYLE_VS = 0xFE0E;

44 45 46
// See http://www.unicode.org/Public/9.0.0/ucd/StandardizedVariants.txt
// U+2640, U+2642, U+2695 are now in emoji category but not listed in above file, so added them by
// manual.
47 48 49 50 51 52 53
// Must be sorted.
const uint32_t EMOJI_STYLE_VS_BASES[] = {
    0x0023, 0x002A, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039,
    0x00A9, 0x00AE, 0x203C, 0x2049, 0x2122, 0x2139, 0x2194, 0x2195, 0x2196, 0x2197, 0x2198, 0x2199,
    0x21A9, 0x21AA, 0x231A, 0x231B, 0x2328, 0x23CF, 0x23ED, 0x23EE, 0x23EF, 0x23F1, 0x23F2, 0x23F8,
    0x23F9, 0x23FA, 0x24C2, 0x25AA, 0x25AB, 0x25B6, 0x25C0, 0x25FB, 0x25FC, 0x25FD, 0x25FE, 0x2600,
    0x2601, 0x2602, 0x2603, 0x2604, 0x260E, 0x2611, 0x2614, 0x2615, 0x2618, 0x261D, 0x2620, 0x2622,
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    0x2623, 0x2626, 0x262A, 0x262E, 0x262F, 0x2638, 0x2639, 0x263A, 0x2640, 0x2642, 0x2648, 0x2649,
    0x264A, 0x264B, 0x264C, 0x264D, 0x264E, 0x264F, 0x2650, 0x2651, 0x2652, 0x2653, 0x2660, 0x2663,
    0x2665, 0x2666, 0x2668, 0x267B, 0x267F, 0x2692, 0x2693, 0x2694, 0x2695, 0x2696, 0x2697, 0x2699,
    0x269B, 0x269C, 0x26A0, 0x26A1, 0x26AA, 0x26AB, 0x26B0, 0x26B1, 0x26BD, 0x26BE, 0x26C4, 0x26C5,
    0x26C8, 0x26CF, 0x26D1, 0x26D3, 0x26D4, 0x26E9, 0x26EA, 0x26F0, 0x26F1, 0x26F2, 0x26F3, 0x26F4,
    0x26F5, 0x26F7, 0x26F8, 0x26F9, 0x26FA, 0x26FD, 0x2702, 0x2708, 0x2709, 0x270C, 0x270D, 0x270F,
    0x2712, 0x2714, 0x2716, 0x271D, 0x2721, 0x2733, 0x2734, 0x2744, 0x2747, 0x2757, 0x2763, 0x2764,
    0x27A1, 0x2934, 0x2935, 0x2B05, 0x2B06, 0x2B07, 0x2B1B, 0x2B1C, 0x2B50, 0x2B55, 0x3030, 0x303D,
    0x3297, 0x3299, 0x1F004, 0x1F170, 0x1F171, 0x1F17E, 0x1F17F, 0x1F202, 0x1F21A, 0x1F22F, 0x1F237,
    0x1F321, 0x1F324, 0x1F325, 0x1F326, 0x1F327, 0x1F328, 0x1F329, 0x1F32A, 0x1F32B, 0x1F32C,
    0x1F336, 0x1F37D, 0x1F396, 0x1F397, 0x1F399, 0x1F39A, 0x1F39B, 0x1F39E, 0x1F39F, 0x1F3CB,
    0x1F3CC, 0x1F3CD, 0x1F3CE, 0x1F3D4, 0x1F3D5, 0x1F3D6, 0x1F3D7, 0x1F3D8, 0x1F3D9, 0x1F3DA,
    0x1F3DB, 0x1F3DC, 0x1F3DD, 0x1F3DE, 0x1F3DF, 0x1F3F3, 0x1F3F5, 0x1F3F7, 0x1F43F, 0x1F441,
    0x1F4FD, 0x1F549, 0x1F54A, 0x1F56F, 0x1F570, 0x1F573, 0x1F574, 0x1F575, 0x1F576, 0x1F577,
    0x1F578, 0x1F579, 0x1F587, 0x1F58A, 0x1F58B, 0x1F58C, 0x1F58D, 0x1F590, 0x1F5A5, 0x1F5A8,
    0x1F5B1, 0x1F5B2, 0x1F5BC, 0x1F5C2, 0x1F5C3, 0x1F5C4, 0x1F5D1, 0x1F5D2, 0x1F5D3, 0x1F5DC,
    0x1F5DD, 0x1F5DE, 0x1F5E1, 0x1F5E3, 0x1F5E8, 0x1F5EF, 0x1F5F3, 0x1F5FA, 0x1F6CB, 0x1F6CD,
    0x1F6CE, 0x1F6CF, 0x1F6E0, 0x1F6E1, 0x1F6E2, 0x1F6E3, 0x1F6E4, 0x1F6E5, 0x1F6E9, 0x1F6F0,
    0x1F6F3,
73 74 75 76 77 78 79
};

static bool isEmojiStyleVSBase(uint32_t cp) {
    const size_t length = sizeof(EMOJI_STYLE_VS_BASES) / sizeof(EMOJI_STYLE_VS_BASES[0]);
    return std::binary_search(EMOJI_STYLE_VS_BASES, EMOJI_STYLE_VS_BASES + length, cp);
}

80 81
uint32_t FontCollection::sNextId = 0;

R
Raph Levien 已提交
82 83
FontCollection::FontCollection(const vector<FontFamily*>& typefaces) :
    mMaxChar(0) {
S
Seigo Nonaka 已提交
84
    android::AutoMutex _l(gMinikinLock);
85
    mId = sNextId++;
R
Raph Levien 已提交
86 87 88
    vector<uint32_t> lastChar;
    size_t nTypefaces = typefaces.size();
#ifdef VERBOSE_DEBUG
89
    ALOGD("nTypefaces = %zd\n", nTypefaces);
R
Raph Levien 已提交
90 91 92 93
#endif
    const FontStyle defaultStyle;
    for (size_t i = 0; i < nTypefaces; i++) {
        FontFamily* family = typefaces[i];
R
Raph Levien 已提交
94
        MinikinFont* typeface = family->getClosestMatch(defaultStyle).font;
95 96 97
        if (typeface == NULL) {
            continue;
        }
98
        family->RefLocked();
99
        const SparseBitSet& coverage = family->getCoverage();
100
        mFamilies.push_back(family);  // emplace_back would be better
101 102 103
        if (family->hasVSTable()) {
            mVSFamilyVec.push_back(family);
        }
104 105
        mMaxChar = max(mMaxChar, coverage.length());
        lastChar.push_back(coverage.nextSetBit(0));
106 107 108

        const std::unordered_set<AxisTag>& supportedAxes = family->supportedAxes();
        mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end());
R
Raph Levien 已提交
109
    }
110
    nTypefaces = mFamilies.size();
111 112
    LOG_ALWAYS_FATAL_IF(nTypefaces == 0,
        "Font collection must have at least one valid typeface");
113
    size_t nPages = (mMaxChar + kPageMask) >> kLogCharsPerPage;
R
Raph Levien 已提交
114
    size_t offset = 0;
115 116 117 118
    // TODO: Use variation selector map for mRanges construction.
    // A font can have a glyph for a base code point and variation selector pair but no glyph for
    // the base code point without variation selector. The family won't be listed in the range in
    // this case.
R
Raph Levien 已提交
119 120 121 122 123
    for (size_t i = 0; i < nPages; i++) {
        Range dummy;
        mRanges.push_back(dummy);
        Range* range = &mRanges.back();
#ifdef VERBOSE_DEBUG
124
        ALOGD("i=%zd: range start = %zd\n", i, offset);
R
Raph Levien 已提交
125
#endif
126
        range->start = offset;
R
Raph Levien 已提交
127 128
        for (size_t j = 0; j < nTypefaces; j++) {
            if (lastChar[j] < (i + 1) << kLogCharsPerPage) {
129
                FontFamily* family = mFamilies[j];
130
                mFamilyVec.push_back(family);
R
Raph Levien 已提交
131
                offset++;
132
                uint32_t nextChar = family->getCoverage().nextSetBit((i + 1) << kLogCharsPerPage);
R
Raph Levien 已提交
133
#ifdef VERBOSE_DEBUG
134
                ALOGD("nextChar = %d (j = %zd)\n", nextChar, j);
R
Raph Levien 已提交
135 136 137 138
#endif
                lastChar[j] = nextChar;
            }
        }
139
        range->end = offset;
R
Raph Levien 已提交
140 141 142 143
    }
}

FontCollection::~FontCollection() {
144 145
    for (size_t i = 0; i < mFamilies.size(); i++) {
        mFamilies[i]->UnrefLocked();
R
Raph Levien 已提交
146 147 148
    }
}

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
// Special scores for the font fallback.
const uint32_t kUnsupportedFontScore = 0;
const uint32_t kFirstFontScore = UINT32_MAX;

// Calculates a font score.
// The score of the font family is based on three subscores.
//  - Coverage Score: How well the font family covers the given character or variation sequence.
//  - Language Score: How well the font family is appropriate for the language.
//  - Variant Score: Whether the font family matches the variant. Note that this variant is not the
//    one in BCP47. This is our own font variant (e.g., elegant, compact).
//
// Then, there is a priority for these three subscores as follow:
//   Coverage Score > Language Score > Variant Score
// The returned score reflects this priority order.
//
// Note that there are two special scores.
//  - kUnsupportedFontScore: When the font family doesn't support the variation sequence or even its
//    base character.
//  - kFirstFontScore: When the font is the first font family in the collection and it supports the
//    given character or variation sequence.
uint32_t FontCollection::calcFamilyScore(uint32_t ch, uint32_t vs, int variant, uint32_t langListId,
                                        FontFamily* fontFamily) const {

    const uint32_t coverageScore = calcCoverageScore(ch, vs, fontFamily);
    if (coverageScore == kFirstFontScore || coverageScore == kUnsupportedFontScore) {
        // No need to calculate other scores.
        return coverageScore;
    }

    const uint32_t languageScore = calcLanguageMatchingScore(langListId, *fontFamily);
    const uint32_t variantScore = calcVariantMatchingScore(variant, *fontFamily);

    // Subscores are encoded into 31 bits representation to meet the subscore priority.
    // The highest 2 bits are for coverage score, then following 28 bits are for language score,
    // then the last 1 bit is for variant score.
    return coverageScore << 29 | languageScore << 1 | variantScore;
}

// Calculates a font score based on variation sequence coverage.
// - Returns kUnsupportedFontScore if the font doesn't support the variation sequence or its base
//   character.
// - Returns kFirstFontScore if the font family is the first font family in the collection and it
//   supports the given character or variation sequence.
// - Returns 3 if the font family supports the variation sequence.
// - Returns 2 if the vs is a color variation selector (U+FE0F) and if the font is an emoji font.
// - Returns 2 if the vs is a text variation selector (U+FE0E) and if the font is not an emoji font.
// - Returns 1 if the variation selector is not specified or if the font family only supports the
//   variation sequence's base character.
uint32_t FontCollection::calcCoverageScore(uint32_t ch, uint32_t vs, FontFamily* fontFamily) const {
198
    const bool hasVSGlyph = (vs != 0) && fontFamily->hasGlyph(ch, vs);
199
    if (!hasVSGlyph && !fontFamily->getCoverage().get(ch)) {
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
        // The font doesn't support either variation sequence or even the base character.
        return kUnsupportedFontScore;
    }

    if ((vs == 0 || hasVSGlyph) && mFamilies[0] == fontFamily) {
        // If the first font family supports the given character or variation sequence, always use
        // it.
        return kFirstFontScore;
    }

    if (vs == 0) {
        return 1;
    }

    if (hasVSGlyph) {
        return 3;
    }

218
    if (vs == EMOJI_STYLE_VS || vs == TEXT_STYLE_VS) {
219 220 221
        const FontLanguages& langs = FontLanguageListCache::getById(fontFamily->langId());
        bool hasEmojiFlag = false;
        for (size_t i = 0; i < langs.size(); ++i) {
222
            if (langs[i].getEmojiStyle() == FontLanguage::EMSTYLE_EMOJI) {
223 224 225 226 227
                hasEmojiFlag = true;
                break;
            }
        }

228
        if (vs == EMOJI_STYLE_VS) {
229
            return hasEmojiFlag ? 2 : 1;
230
        } else {  // vs == TEXT_STYLE_VS
231 232 233 234 235 236
            return hasEmojiFlag ? 1 : 2;
        }
    }
    return 1;
}

Y
Yirui Huang 已提交
237
// Calculate font scores based on the script matching, subtag matching and primary langauge matching.
238
//
Y
Yirui Huang 已提交
239 240 241 242 243 244
// 1. If only the font's language matches or there is no matches between requested font and
//    supported font, then the font obtains a score of 0.
// 2. Without a match in language, considering subtag may change font's EmojiStyle over script,
//    a match in subtag gets a score of 2 and a match in scripts gains a score of 1.
// 3. Regarding to two elements matchings, language-and-subtag matching has a score of 4, while
//    language-and-script obtains a socre of 3 with the same reason above.
245 246 247 248 249 250
//
// If two languages in the requested list have the same language score, the font matching with
// higher priority language gets a higher score. For example, in the case the user requested
// language list is "ja-Jpan,en-Latn". The score of for the font of "ja-Jpan" gets a higher score
// than the font of "en-Latn".
//
Y
Yirui Huang 已提交
251 252
// To achieve score calculation with priorities, the language score is determined as follows:
//   LanguageScore = s(0) * 5^(m - 1) + s(1) * 5^(m - 2) + ... + s(m - 2) * 5 + s(m - 1)
253
// Here, m is the maximum number of languages to be compared, and s(i) is the i-th language's
Y
Yirui Huang 已提交
254
// matching score. The possible values of s(i) are 0, 1, 2, 3 and 4.
255 256 257
uint32_t FontCollection::calcLanguageMatchingScore(
        uint32_t userLangListId, const FontFamily& fontFamily) {
    const FontLanguages& langList = FontLanguageListCache::getById(userLangListId);
258
    const FontLanguages& fontLanguages = FontLanguageListCache::getById(fontFamily.langId());
259 260

    const size_t maxCompareNum = std::min(langList.size(), FONT_LANGUAGES_LIMIT);
261 262
    uint32_t score = 0;
    for (size_t i = 0; i < maxCompareNum; ++i) {
Y
Yirui Huang 已提交
263
        score = score * 5u + langList[i].calcScoreFor(fontLanguages);
264 265 266 267 268 269 270 271 272 273 274
    }
    return score;
}

// Calculates a font score based on variant ("compact" or "elegant") matching.
//  - Returns 1 if the font doesn't have variant or the variant matches with the text style.
//  - No score if the font has a variant but it doesn't match with the text style.
uint32_t FontCollection::calcVariantMatchingScore(int variant, const FontFamily& fontFamily) {
    return (fontFamily.variant() == 0 || fontFamily.variant() == variant) ? 1 : 0;
}

R
Raph Levien 已提交
275 276
// Implement heuristic for choosing best-match font. Here are the rules:
// 1. If first font in the collection has the character, it wins.
277 278
// 2. Calculate a score for the font family. See comments in calcFamilyScore for the detail.
// 3. Highest score wins, with ties resolved to the first font.
279
// This method never returns nullptr.
280
FontFamily* FontCollection::getFamilyForChar(uint32_t ch, uint32_t vs,
S
Seigo Nonaka 已提交
281
            uint32_t langListId, int variant) const {
R
Raph Levien 已提交
282
    if (ch >= mMaxChar) {
283
        return mFamilies[0];
R
Raph Levien 已提交
284
    }
285

286
    const std::vector<FontFamily*>& familyVec = (vs == 0) ? mFamilyVec : mFamilies;
287 288 289
    Range range = mRanges[ch >> kLogCharsPerPage];

    if (vs != 0) {
290
        range = { 0, mFamilies.size() };
291 292
    }

R
Raph Levien 已提交
293
#ifdef VERBOSE_DEBUG
294
    ALOGD("querying range %zd:%zd\n", range.start, range.end);
R
Raph Levien 已提交
295
#endif
296
    FontFamily* bestFamily = nullptr;
297
    uint32_t bestScore = kUnsupportedFontScore;
R
Raph Levien 已提交
298
    for (size_t i = range.start; i < range.end; i++) {
299
        FontFamily* family = familyVec[i];
300 301 302 303 304 305 306 307 308
        const uint32_t score = calcFamilyScore(ch, vs, variant, langListId, family);
        if (score == kFirstFontScore) {
            // If the first font family supports the given character or variation sequence, always
            // use it.
            return family;
        }
        if (score > bestScore) {
            bestScore = score;
            bestFamily = family;
R
Raph Levien 已提交
309
        }
S
Seigo Nonaka 已提交
310
    }
311
    if (bestFamily == nullptr) {
312 313 314 315 316 317 318 319
        UErrorCode errorCode = U_ZERO_ERROR;
        const UNormalizer2* normalizer = unorm2_getNFDInstance(&errorCode);
        if (U_SUCCESS(errorCode)) {
            UChar decomposed[4];
            int len = unorm2_getRawDecomposition(normalizer, ch, decomposed, 4, &errorCode);
            if (U_SUCCESS(errorCode) && len > 0) {
                int off = 0;
                U16_NEXT_UNSAFE(decomposed, off, ch);
S
Seigo Nonaka 已提交
320
                return getFamilyForChar(ch, vs, langListId, variant);
321 322
            }
        }
323
        bestFamily = mFamilies[0];
324
    }
325
    return bestFamily;
R
Raph Levien 已提交
326 327
}

R
Raph Levien 已提交
328
const uint32_t NBSP = 0xa0;
329 330
const uint32_t ZWJ = 0x200c;
const uint32_t ZWNJ = 0x200d;
331 332
const uint32_t HYPHEN = 0x2010;
const uint32_t NB_HYPHEN = 0x2011;
333 334 335
const uint32_t FEMALE_SIGN = 0x2640;
const uint32_t MALE_SIGN = 0x2642;
const uint32_t STAFF_OF_AESCULAPIUS = 0x2695;
336

R
Raph Levien 已提交
337 338
// Characters where we want to continue using existing font run instead of
// recomputing the best match in the fallback list.
339
static const uint32_t stickyWhitelist[] = { '!', ',', '-', '.', ':', ';', '?', NBSP, ZWJ, ZWNJ,
340
        HYPHEN, NB_HYPHEN, FEMALE_SIGN, MALE_SIGN, STAFF_OF_AESCULAPIUS };
R
Raph Levien 已提交
341 342 343 344 345 346 347 348

static bool isStickyWhitelisted(uint32_t c) {
    for (size_t i = 0; i < sizeof(stickyWhitelist) / sizeof(stickyWhitelist[0]); i++) {
        if (stickyWhitelist[i] == c) return true;
    }
    return false;
}

349 350 351 352
static bool isVariationSelector(uint32_t c) {
    return (0xFE00 <= c && c <= 0xFE0F) || (0xE0100 <= c && c <= 0xE01EF);
}

353 354 355 356 357 358 359 360
bool FontCollection::hasVariationSelector(uint32_t baseCodepoint,
        uint32_t variationSelector) const {
    if (!isVariationSelector(variationSelector)) {
        return false;
    }
    if (baseCodepoint >= mMaxChar) {
        return false;
    }
361

S
Seigo Nonaka 已提交
362
    android::AutoMutex _l(gMinikinLock);
363

364
    // Currently mRanges can not be used here since it isn't aware of the variation sequence.
365
    for (size_t i = 0; i < mVSFamilyVec.size(); i++) {
366
        if (mVSFamilyVec[i]->hasGlyph(baseCodepoint, variationSelector)) {
367
            return true;
368 369
        }
    }
370 371 372 373 374 375 376 377 378 379 380 381

    // Even if there is no cmap format 14 subtable entry for the given sequence, should return true
    // for emoji + U+FE0E case since we have special fallback rule for the sequence.
    if (isEmojiStyleVSBase(baseCodepoint) && variationSelector == TEXT_STYLE_VS) {
        for (size_t i = 0; i < mFamilies.size(); ++i) {
            if (!mFamilies[i]->isColorEmojiFamily() && variationSelector == TEXT_STYLE_VS &&
                mFamilies[i]->hasGlyph(baseCodepoint, 0)) {
                return true;
            }
        }
    }

382 383 384
    return false;
}

R
Raph Levien 已提交
385 386
void FontCollection::itemize(const uint16_t *string, size_t string_size, FontStyle style,
        vector<Run>* result) const {
S
Seigo Nonaka 已提交
387
    const uint32_t langListId = style.getLanguageListId();
R
Raph Levien 已提交
388
    int variant = style.getVariant();
389
    FontFamily* lastFamily = NULL;
R
Raph Levien 已提交
390
    Run* run = NULL;
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417

    if (string_size == 0) {
        return;
    }

    const uint32_t kEndOfString = 0xFFFFFFFF;

    uint32_t nextCh = 0;
    uint32_t prevCh = 0;
    size_t nextUtf16Pos = 0;
    size_t readLength = 0;
    U16_NEXT(string, readLength, string_size, nextCh);

    do {
        const uint32_t ch = nextCh;
        const size_t utf16Pos = nextUtf16Pos;
        nextUtf16Pos = readLength;
        if (readLength < string_size) {
            U16_NEXT(string, readLength, string_size, nextCh);
        } else {
            nextCh = kEndOfString;
        }

        bool shouldContinueRun = false;
        if (lastFamily != nullptr) {
            if (isStickyWhitelisted(ch)) {
                // Continue using existing font as long as it has coverage and is whitelisted
418
                shouldContinueRun = lastFamily->getCoverage().get(ch);
419 420 421
            } else if (isVariationSelector(ch)) {
                // Always continue if the character is a variation selector.
                shouldContinueRun = true;
R
Raph Levien 已提交
422 423
            }
        }
424 425

        if (!shouldContinueRun) {
426
            FontFamily* family = getFamilyForChar(ch, isVariationSelector(nextCh) ? nextCh : 0,
S
Seigo Nonaka 已提交
427
                    langListId, variant);
428 429
            if (utf16Pos == 0 || family != lastFamily) {
                size_t start = utf16Pos;
430 431 432 433 434
                // Workaround for combining marks and emoji modifiers until we implement
                // per-cluster font selection: if a combining mark or an emoji modifier is found in
                // a different font that also supports the previous character, attach previous
                // character to the new run. U+20E3 COMBINING ENCLOSING KEYCAP, used in emoji, is
                // handled properly by this since it's a combining mark too.
435
                if (utf16Pos != 0 &&
436 437
                        ((U_GET_GC_MASK(ch) & U_GC_M_MASK) != 0 ||
                         (isEmojiModifier(ch) && isEmojiBase(prevCh))) &&
438
                        family && family->getCoverage().get(prevCh)) {
439 440
                    const size_t prevChLength = U16_LENGTH(prevCh);
                    run->end -= prevChLength;
441 442 443
                    if (run->start == run->end) {
                        result->pop_back();
                    }
444
                    start -= prevChLength;
445
                }
446 447 448
                Run dummy;
                result->push_back(dummy);
                run = &result->back();
449
                run->fakedFont = family->getClosestMatch(style);
450
                lastFamily = family;
451
                run->start = start;
R
Raph Levien 已提交
452 453
            }
        }
454 455 456
        prevCh = ch;
        run->end = nextUtf16Pos;  // exclusive
    } while (nextCh != kEndOfString);
R
Raph Levien 已提交
457 458
}

459
MinikinFont* FontCollection::baseFont(FontStyle style) {
R
Raph Levien 已提交
460 461 462 463
    return baseFontFaked(style).font;
}

FakedFont FontCollection::baseFontFaked(FontStyle style) {
464
    return mFamilies[0]->getClosestMatch(style);
465 466
}

467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
FontCollection* FontCollection::createCollectionWithVariation(
        const std::vector<FontVariation>& variations) {
    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 supported by this font collection.
        return nullptr;
    }

    std::vector<FontFamily*> families;
    for (FontFamily* family : mFamilies) {
        FontFamily* newFamily = family->createFamilyWithVariation(variations);
        if (newFamily) {
            families.push_back(newFamily);
        } else {
            family->Ref();
            families.push_back(family);
        }
    }

    FontCollection* result = new FontCollection(families);
    for (FontFamily* family : families) {
        family->Unref();
    }
    return result;
}

503 504 505 506
uint32_t FontCollection::getId() const {
    return mId;
}

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