FontCollection.cpp revision 0036da164e3b25f1ac29c840c1fe15b03dc6677f
19cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien/* 29cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * Copyright (C) 2013 The Android Open Source Project 39cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * 49cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * Licensed under the Apache License, Version 2.0 (the "License"); 59cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * you may not use this file except in compliance with the License. 69cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * You may obtain a copy of the License at 79cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * 89cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * http://www.apache.org/licenses/LICENSE-2.0 99cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * 109cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * Unless required by applicable law or agreed to in writing, software 119cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * distributed under the License is distributed on an "AS IS" BASIS, 129cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * See the License for the specific language governing permissions and 149cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien * limitations under the License. 159cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien */ 169cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 17ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien// #define VERBOSE_DEBUG 18ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien 19ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#define LOG_TAG "Minikin" 20ecc2d34ac23a497988f21e5f415b53c007b9d8c5Raph Levien#include <cutils/log.h> 216f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka#include <algorithm> 229cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 23997c799e3ec6bf8adf687e29670d23d91e0f5feeRaph Levien#include "unicode/unistr.h" 24997c799e3ec6bf8adf687e29670d23d91e0f5feeRaph Levien#include "unicode/unorm2.h" 25997c799e3ec6bf8adf687e29670d23d91e0f5feeRaph Levien 26198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka#include "FontLanguage.h" 276d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka#include "FontLanguageListCache.h" 28c31e3883456e018d742e9f29815ba5ff8b315ea1Raph Levien#include "MinikinInternal.h" 299cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <minikin/FontCollection.h> 309cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 319cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienusing std::vector; 329cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 339cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Leviennamespace android { 349cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 359cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levientemplate <typename T> 369cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienstatic inline T max(T a, T b) { 379cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return a>b ? a : b; 389cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 399cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 404d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levienuint32_t FontCollection::sNextId = 0; 414d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 429cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph LevienFontCollection::FontCollection(const vector<FontFamily*>& typefaces) : 439cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien mMaxChar(0) { 44c31e3883456e018d742e9f29815ba5ff8b315ea1Raph Levien AutoMutex _l(gMinikinLock); 454d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien mId = sNextId++; 469cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien vector<uint32_t> lastChar; 479cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien size_t nTypefaces = typefaces.size(); 489cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#ifdef VERBOSE_DEBUG 49bae347682989d2627081310129a5b60541ed6ad0Seigo Nonaka ALOGD("nTypefaces = %zd\n", nTypefaces); 509cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#endif 519cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const FontStyle defaultStyle; 529cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien for (size_t i = 0; i < nTypefaces; i++) { 539cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien FontFamily* family = typefaces[i]; 549a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien MinikinFont* typeface = family->getClosestMatch(defaultStyle).font; 554d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien if (typeface == NULL) { 564d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien continue; 574d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien } 58bd36ec766a451c62ffdd407d5ce1a355e8f7dfd8Raph Levien family->RefLocked(); 5913f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien const SparseBitSet* coverage = family->getCoverage(); 60cb20a2f0b366bfc16db3a489a60156dec7a9fe21Andreas Gampe if (coverage == nullptr) { 61cb20a2f0b366bfc16db3a489a60156dec7a9fe21Andreas Gampe family->UnrefLocked(); 62cb20a2f0b366bfc16db3a489a60156dec7a9fe21Andreas Gampe continue; 63cb20a2f0b366bfc16db3a489a60156dec7a9fe21Andreas Gampe } 64cb20a2f0b366bfc16db3a489a60156dec7a9fe21Andreas Gampe mFamilies.push_back(family); // emplace_back would be better 656b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka if (family->hasVSTable()) { 666b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka mVSFamilyVec.push_back(family); 676b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka } 6813f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien mMaxChar = max(mMaxChar, coverage->length()); 6913f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien lastChar.push_back(coverage->nextSetBit(0)); 709cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 7113f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien nTypefaces = mFamilies.size(); 72156acb18f53b32655abb34166ea737e4320ca366Raph Levien LOG_ALWAYS_FATAL_IF(nTypefaces == 0, 73156acb18f53b32655abb34166ea737e4320ca366Raph Levien "Font collection must have at least one valid typeface"); 7472fe9422c869b7878240a23e4650d9d90edb1c2aRaph Levien size_t nPages = (mMaxChar + kPageMask) >> kLogCharsPerPage; 759cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien size_t offset = 0; 7680d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka // TODO: Use variation selector map for mRanges construction. 7780d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka // A font can have a glyph for a base code point and variation selector pair but no glyph for 7880d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka // the base code point without variation selector. The family won't be listed in the range in 7980d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka // this case. 809cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien for (size_t i = 0; i < nPages; i++) { 819cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien Range dummy; 829cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien mRanges.push_back(dummy); 839cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien Range* range = &mRanges.back(); 849cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#ifdef VERBOSE_DEBUG 85bae347682989d2627081310129a5b60541ed6ad0Seigo Nonaka ALOGD("i=%zd: range start = %zd\n", i, offset); 869cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#endif 879cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien range->start = offset; 889cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien for (size_t j = 0; j < nTypefaces; j++) { 899cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (lastChar[j] < (i + 1) << kLogCharsPerPage) { 9013f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien FontFamily* family = mFamilies[j]; 9113f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien mFamilyVec.push_back(family); 929cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien offset++; 9313f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien uint32_t nextChar = family->getCoverage()->nextSetBit((i + 1) << kLogCharsPerPage); 949cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#ifdef VERBOSE_DEBUG 95bae347682989d2627081310129a5b60541ed6ad0Seigo Nonaka ALOGD("nextChar = %d (j = %zd)\n", nextChar, j); 969cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#endif 979cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien lastChar[j] = nextChar; 989cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 999cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1009cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien range->end = offset; 1019cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1029cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 1039cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 1049cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph LevienFontCollection::~FontCollection() { 10513f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien for (size_t i = 0; i < mFamilies.size(); i++) { 10613f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien mFamilies[i]->UnrefLocked(); 1079cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1089cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 1099cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 1106f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// Special scores for the font fallback. 1116f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonakaconst uint32_t kUnsupportedFontScore = 0; 1126f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonakaconst uint32_t kFirstFontScore = UINT32_MAX; 1136f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 1146f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// Calculates a font score. 1156f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// The score of the font family is based on three subscores. 1166f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// - Coverage Score: How well the font family covers the given character or variation sequence. 1176f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// - Language Score: How well the font family is appropriate for the language. 1186f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// - Variant Score: Whether the font family matches the variant. Note that this variant is not the 1196f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// one in BCP47. This is our own font variant (e.g., elegant, compact). 1206f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// 1216f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// Then, there is a priority for these three subscores as follow: 1226f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// Coverage Score > Language Score > Variant Score 1236f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// The returned score reflects this priority order. 1246f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// 1256f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// Note that there are two special scores. 1266f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// - kUnsupportedFontScore: When the font family doesn't support the variation sequence or even its 1276f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// base character. 1286f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// - kFirstFontScore: When the font is the first font family in the collection and it supports the 1296f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// given character or variation sequence. 1306f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonakauint32_t FontCollection::calcFamilyScore(uint32_t ch, uint32_t vs, int variant, uint32_t langListId, 1316f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka FontFamily* fontFamily) const { 1326f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 1336f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka const uint32_t coverageScore = calcCoverageScore(ch, vs, fontFamily); 1346f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka if (coverageScore == kFirstFontScore || coverageScore == kUnsupportedFontScore) { 1356f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka // No need to calculate other scores. 1366f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return coverageScore; 1376f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka } 1386f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 1396f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka const uint32_t languageScore = calcLanguageMatchingScore(langListId, *fontFamily); 1406f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka const uint32_t variantScore = calcVariantMatchingScore(variant, *fontFamily); 1416f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 1426f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka // Subscores are encoded into 31 bits representation to meet the subscore priority. 1436f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka // The highest 2 bits are for coverage score, then following 28 bits are for language score, 1446f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka // then the last 1 bit is for variant score. 1456f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return coverageScore << 29 | languageScore << 1 | variantScore; 1466f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka} 1476f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 1486f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// Calculates a font score based on variation sequence coverage. 1496f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// - Returns kUnsupportedFontScore if the font doesn't support the variation sequence or its base 1506f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// character. 1516f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// - Returns kFirstFontScore if the font family is the first font family in the collection and it 1526f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// supports the given character or variation sequence. 1536f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// - Returns 3 if the font family supports the variation sequence. 1546f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// - Returns 2 if the vs is a color variation selector (U+FE0F) and if the font is an emoji font. 1556f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// - Returns 2 if the vs is a text variation selector (U+FE0E) and if the font is not an emoji font. 1566f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// - Returns 1 if the variation selector is not specified or if the font family only supports the 1576f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// variation sequence's base character. 1586f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonakauint32_t FontCollection::calcCoverageScore(uint32_t ch, uint32_t vs, FontFamily* fontFamily) const { 1596f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka const bool hasVSGlyph = (vs != 0) && fontFamily->hasVariationSelector(ch, vs); 1606f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka if (!hasVSGlyph && !fontFamily->getCoverage()->get(ch)) { 1616f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka // The font doesn't support either variation sequence or even the base character. 1626f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return kUnsupportedFontScore; 1636f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka } 1646f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 1656f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka if ((vs == 0 || hasVSGlyph) && mFamilies[0] == fontFamily) { 1666f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka // If the first font family supports the given character or variation sequence, always use 1676f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka // it. 1686f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return kFirstFontScore; 1696f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka } 1706f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 1716f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka if (vs == 0) { 1726f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return 1; 1736f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka } 1746f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 1756f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka if (hasVSGlyph) { 1766f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return 3; 1776f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka } 1786f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 1796f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka if (vs == 0xFE0F || vs == 0xFE0E) { 1806f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka // TODO use all language in the list. 1816f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka const FontLanguage lang = FontLanguageListCache::getById(fontFamily->langId())[0]; 1826f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka const bool hasEmojiFlag = lang.hasEmojiFlag(); 1836f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka if (vs == 0xFE0F) { 1846f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return hasEmojiFlag ? 2 : 1; 1856f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka } else { // vs == 0xFE0E 1866f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return hasEmojiFlag ? 1 : 2; 1876f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka } 1886f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka } 1896f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return 1; 1906f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka} 1916f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 1926f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// Calculates font scores based on the script matching and primary langauge matching. 1936f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// 1946f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// If the font's script doesn't support the requested script, the font gets a score of 0. If the 1956f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// font's script supports the requested script and the font has the same primary language as the 1966f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// requested one, the font gets a score of 2. If the font's script supports the requested script 1976f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// but the primary language is different from the requested one, the font gets a score of 1. 1986f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// 1996f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// If two languages in the requested list have the same language score, the font matching with 2006f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// higher priority language gets a higher score. For example, in the case the user requested 2016f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// language list is "ja-Jpan,en-Latn". The score of for the font of "ja-Jpan" gets a higher score 2026f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// than the font of "en-Latn". 2036f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// 2046f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// To achieve the above two conditions, the language score is determined as follows: 2056f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// LanguageScore = s(0) * 3^(m - 1) + s(1) * 3^(m - 2) + ... + s(m - 2) * 3 + s(m - 1) 2066f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// Here, m is the maximum number of languages to be compared, and s(i) is the i-th language's 2076f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// matching score. The possible values of s(i) are 0, 1 and 2. 2086f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonakauint32_t FontCollection::calcLanguageMatchingScore( 2096f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka uint32_t userLangListId, const FontFamily& fontFamily) { 2106f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka const FontLanguages& langList = FontLanguageListCache::getById(userLangListId); 2116f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka // TODO use all language in the list. 2126f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka FontLanguage fontLanguage = FontLanguageListCache::getById(fontFamily.langId())[0]; 2136f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 2146f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka const size_t maxCompareNum = std::min(langList.size(), FONT_LANGUAGES_LIMIT); 2156f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka uint32_t score = fontLanguage.getScoreFor(langList[0]); // maxCompareNum can't be zero. 2166f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka for (size_t i = 1; i < maxCompareNum; ++i) { 2176f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka score = score * 3u + fontLanguage.getScoreFor(langList[i]); 2186f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka } 2196f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return score; 2206f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka} 2216f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 2226f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// Calculates a font score based on variant ("compact" or "elegant") matching. 2236f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// - Returns 1 if the font doesn't have variant or the variant matches with the text style. 2246f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// - No score if the font has a variant but it doesn't match with the text style. 2256f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonakauint32_t FontCollection::calcVariantMatchingScore(int variant, const FontFamily& fontFamily) { 2266f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return (fontFamily.variant() == 0 || fontFamily.variant() == variant) ? 1 : 0; 2276f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka} 2286f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 2297b221d97b7b64dc5ce457e19666d55d042e22e62Raph Levien// Implement heuristic for choosing best-match font. Here are the rules: 2307b221d97b7b64dc5ce457e19666d55d042e22e62Raph Levien// 1. If first font in the collection has the character, it wins. 2316f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// 2. Calculate a score for the font family. See comments in calcFamilyScore for the detail. 2326f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka// 3. Highest score wins, with ties resolved to the first font. 233bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo NonakaFontFamily* FontCollection::getFamilyForChar(uint32_t ch, uint32_t vs, 2346d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka uint32_t langListId, int variant) const { 2359cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (ch >= mMaxChar) { 2369cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return NULL; 2379cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 238fc119c68f5def1e44e65ae4cdd147c01d62c9ad2Seigo Nonaka 2396b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka const std::vector<FontFamily*>* familyVec = &mFamilyVec; 2406b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka Range range = mRanges[ch >> kLogCharsPerPage]; 2416b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka 2426b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka std::vector<FontFamily*> familyVecForVS; 2436b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka if (vs != 0) { 2446b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka // If variation selector is specified, need to search for both the variation sequence and 2456b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka // its base codepoint. Compute the union vector of them. 2466b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka familyVecForVS = mVSFamilyVec; 2476b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka familyVecForVS.insert(familyVecForVS.end(), 2486b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka mFamilyVec.begin() + range.start, mFamilyVec.begin() + range.end); 2496b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka std::sort(familyVecForVS.begin(), familyVecForVS.end()); 2506b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka auto last = std::unique(familyVecForVS.begin(), familyVecForVS.end()); 2516b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka familyVecForVS.erase(last, familyVecForVS.end()); 2526b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka 2536b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka familyVec = &familyVecForVS; 2546b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka range = { 0, familyVecForVS.size() }; 255fc119c68f5def1e44e65ae4cdd147c01d62c9ad2Seigo Nonaka } 256fc119c68f5def1e44e65ae4cdd147c01d62c9ad2Seigo Nonaka 2579cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#ifdef VERBOSE_DEBUG 258bae347682989d2627081310129a5b60541ed6ad0Seigo Nonaka ALOGD("querying range %zd:%zd\n", range.start, range.end); 2599cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#endif 260bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka FontFamily* bestFamily = nullptr; 2616f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka uint32_t bestScore = kUnsupportedFontScore; 2629cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien for (size_t i = range.start; i < range.end; i++) { 2636b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka FontFamily* family = (*familyVec)[i]; 2646f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka const uint32_t score = calcFamilyScore(ch, vs, variant, langListId, family); 2656f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka if (score == kFirstFontScore) { 2666f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka // If the first font family supports the given character or variation sequence, always 2676f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka // use it. 2686f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return family; 2696f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka } 2706f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka if (score > bestScore) { 2716f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka bestScore = score; 2726f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka bestFamily = family; 2739cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 2746d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka } 275bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka if (bestFamily == nullptr && !mFamilyVec.empty()) { 276997c799e3ec6bf8adf687e29670d23d91e0f5feeRaph Levien UErrorCode errorCode = U_ZERO_ERROR; 277997c799e3ec6bf8adf687e29670d23d91e0f5feeRaph Levien const UNormalizer2* normalizer = unorm2_getNFDInstance(&errorCode); 278997c799e3ec6bf8adf687e29670d23d91e0f5feeRaph Levien if (U_SUCCESS(errorCode)) { 279997c799e3ec6bf8adf687e29670d23d91e0f5feeRaph Levien UChar decomposed[4]; 280997c799e3ec6bf8adf687e29670d23d91e0f5feeRaph Levien int len = unorm2_getRawDecomposition(normalizer, ch, decomposed, 4, &errorCode); 281997c799e3ec6bf8adf687e29670d23d91e0f5feeRaph Levien if (U_SUCCESS(errorCode) && len > 0) { 282997c799e3ec6bf8adf687e29670d23d91e0f5feeRaph Levien int off = 0; 283997c799e3ec6bf8adf687e29670d23d91e0f5feeRaph Levien U16_NEXT_UNSAFE(decomposed, off, ch); 2846d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka return getFamilyForChar(ch, vs, langListId, variant); 285997c799e3ec6bf8adf687e29670d23d91e0f5feeRaph Levien } 286997c799e3ec6bf8adf687e29670d23d91e0f5feeRaph Levien } 28713f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien bestFamily = mFamilies[0]; 288156acb18f53b32655abb34166ea737e4320ca366Raph Levien } 28913f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien return bestFamily; 2909cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 2919cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 292bb601b67dd05947f92cc23092bfb8a059c2e3377Raph Levienconst uint32_t NBSP = 0xa0; 293bb601b67dd05947f92cc23092bfb8a059c2e3377Raph Levienconst uint32_t ZWJ = 0x200c; 294bb601b67dd05947f92cc23092bfb8a059c2e3377Raph Levienconst uint32_t ZWNJ = 0x200d; 295f952161b874fd2e9af474b9fd2ebcca1f3bb4555Behdad Esfahbodconst uint32_t KEYCAP = 0x20e3; 29690a09c3f36d98530822392446884b8af68035908Raph Levienconst uint32_t HYPHEN = 0x2010; 29790a09c3f36d98530822392446884b8af68035908Raph Levienconst uint32_t NB_HYPHEN = 0x2011; 298f952161b874fd2e9af474b9fd2ebcca1f3bb4555Behdad Esfahbod 299bb601b67dd05947f92cc23092bfb8a059c2e3377Raph Levien// Characters where we want to continue using existing font run instead of 300bb601b67dd05947f92cc23092bfb8a059c2e3377Raph Levien// recomputing the best match in the fallback list. 30190a09c3f36d98530822392446884b8af68035908Raph Levienstatic const uint32_t stickyWhitelist[] = { '!', ',', '-', '.', ':', ';', '?', NBSP, ZWJ, ZWNJ, 30290a09c3f36d98530822392446884b8af68035908Raph Levien KEYCAP, HYPHEN, NB_HYPHEN }; 303bb601b67dd05947f92cc23092bfb8a059c2e3377Raph Levien 304bb601b67dd05947f92cc23092bfb8a059c2e3377Raph Levienstatic bool isStickyWhitelisted(uint32_t c) { 305bb601b67dd05947f92cc23092bfb8a059c2e3377Raph Levien for (size_t i = 0; i < sizeof(stickyWhitelist) / sizeof(stickyWhitelist[0]); i++) { 306bb601b67dd05947f92cc23092bfb8a059c2e3377Raph Levien if (stickyWhitelist[i] == c) return true; 307bb601b67dd05947f92cc23092bfb8a059c2e3377Raph Levien } 308bb601b67dd05947f92cc23092bfb8a059c2e3377Raph Levien return false; 309bb601b67dd05947f92cc23092bfb8a059c2e3377Raph Levien} 310bb601b67dd05947f92cc23092bfb8a059c2e3377Raph Levien 311bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonakastatic bool isVariationSelector(uint32_t c) { 312bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka return (0xFE00 <= c && c <= 0xFE0F) || (0xE0100 <= c && c <= 0xE01EF); 313bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka} 314bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka 31580d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonakabool FontCollection::hasVariationSelector(uint32_t baseCodepoint, 31680d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka uint32_t variationSelector) const { 31780d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka if (!isVariationSelector(variationSelector)) { 31880d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka return false; 31980d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka } 32080d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka if (baseCodepoint >= mMaxChar) { 32180d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka return false; 32280d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka } 3236b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka if (variationSelector == 0) { 3246b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka return false; 3256b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka } 3266b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka 32780d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka // Currently mRanges can not be used here since it isn't aware of the variation sequence. 3286b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka for (size_t i = 0; i < mVSFamilyVec.size(); i++) { 329a6f5c46836090d1197e453c15c7f04c3c796a7abSeigo Nonaka AutoMutex _l(gMinikinLock); 3306b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka if (mVSFamilyVec[i]->hasVariationSelector(baseCodepoint, variationSelector)) { 3316b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka return true; 33280d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka } 33380d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka } 33480d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka return false; 33580d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka} 33680d113bcd4bbc395218503354af1a5a6dba59b4bSeigo Nonaka 3379cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienvoid FontCollection::itemize(const uint16_t *string, size_t string_size, FontStyle style, 3389cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien vector<Run>* result) const { 3396d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka const uint32_t langListId = style.getLanguageListId(); 3407b221d97b7b64dc5ce457e19666d55d042e22e62Raph Levien int variant = style.getVariant(); 34113f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien FontFamily* lastFamily = NULL; 3429cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien Run* run = NULL; 343bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka 344bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka if (string_size == 0) { 345bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka return; 346bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka } 347bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka 348bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka const uint32_t kEndOfString = 0xFFFFFFFF; 349bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka 350bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka uint32_t nextCh = 0; 351bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka uint32_t prevCh = 0; 352bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka size_t nextUtf16Pos = 0; 353bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka size_t readLength = 0; 354bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka U16_NEXT(string, readLength, string_size, nextCh); 355bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka 356bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka do { 357bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka const uint32_t ch = nextCh; 358bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka const size_t utf16Pos = nextUtf16Pos; 359bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka nextUtf16Pos = readLength; 360bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka if (readLength < string_size) { 361bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka U16_NEXT(string, readLength, string_size, nextCh); 362bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka } else { 363bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka nextCh = kEndOfString; 364bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka } 365bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka 366bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka bool shouldContinueRun = false; 367bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka if (lastFamily != nullptr) { 368bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka if (isStickyWhitelisted(ch)) { 369bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka // Continue using existing font as long as it has coverage and is whitelisted 370bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka shouldContinueRun = lastFamily->getCoverage()->get(ch); 371bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka } else if (isVariationSelector(ch)) { 372bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka // Always continue if the character is a variation selector. 373bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka shouldContinueRun = true; 3749cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 3759cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 376bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka 377bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka if (!shouldContinueRun) { 3786d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka FontFamily* family = getFamilyForChar(ch, isVariationSelector(nextCh) ? nextCh : 0, 3796d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka langListId, variant); 380bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka if (utf16Pos == 0 || family != lastFamily) { 381bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka size_t start = utf16Pos; 3820036da164e3b25f1ac29c840c1fe15b03dc6677fSeigo Nonaka // Workaround for Emoji keycap and emoji modifier until we implement per-cluster 3830036da164e3b25f1ac29c840c1fe15b03dc6677fSeigo Nonaka // font selection: if a keycap or an emoji modifier is found in a different font 3840036da164e3b25f1ac29c840c1fe15b03dc6677fSeigo Nonaka // that also supports previous char, attach previous char to the new run. 385f952161b874fd2e9af474b9fd2ebcca1f3bb4555Behdad Esfahbod // Bug 7557244. 3860036da164e3b25f1ac29c840c1fe15b03dc6677fSeigo Nonaka if (utf16Pos != 0 && 3870036da164e3b25f1ac29c840c1fe15b03dc6677fSeigo Nonaka (ch == KEYCAP || (isEmojiModifier(ch) && isEmojiBase(prevCh))) && 3880036da164e3b25f1ac29c840c1fe15b03dc6677fSeigo Nonaka family && family->getCoverage()->get(prevCh)) { 3893dd8757fcf48976295bac566277b6da1046e8362Seigo Nonaka const size_t prevChLength = U16_LENGTH(prevCh); 3903dd8757fcf48976295bac566277b6da1046e8362Seigo Nonaka run->end -= prevChLength; 391f952161b874fd2e9af474b9fd2ebcca1f3bb4555Behdad Esfahbod if (run->start == run->end) { 392f952161b874fd2e9af474b9fd2ebcca1f3bb4555Behdad Esfahbod result->pop_back(); 393f952161b874fd2e9af474b9fd2ebcca1f3bb4555Behdad Esfahbod } 3943dd8757fcf48976295bac566277b6da1046e8362Seigo Nonaka start -= prevChLength; 395f952161b874fd2e9af474b9fd2ebcca1f3bb4555Behdad Esfahbod } 396066e8575af64fb452617ac6005de6ccf6509553bRaph Levien Run dummy; 397066e8575af64fb452617ac6005de6ccf6509553bRaph Levien result->push_back(dummy); 398066e8575af64fb452617ac6005de6ccf6509553bRaph Levien run = &result->back(); 39913f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien if (family == NULL) { 4009a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien run->fakedFont.font = NULL; 401066e8575af64fb452617ac6005de6ccf6509553bRaph Levien } else { 40213f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien run->fakedFont = family->getClosestMatch(style); 403066e8575af64fb452617ac6005de6ccf6509553bRaph Levien } 40413f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien lastFamily = family; 405f952161b874fd2e9af474b9fd2ebcca1f3bb4555Behdad Esfahbod run->start = start; 4069cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 4079cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 408bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka prevCh = ch; 409bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka run->end = nextUtf16Pos; // exclusive 410bbdd73ec077a1bb6801b25a639834be16dfd78cbSeigo Nonaka } while (nextCh != kEndOfString); 4119cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 4129cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 41389566f0ada1cafe673efa064cde38467990235d4Raph LevienMinikinFont* FontCollection::baseFont(FontStyle style) { 4149a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien return baseFontFaked(style).font; 4159a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien} 4169a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien 4179a5f713add8cfb91ac2c9ed5c917309053201ab6Raph LevienFakedFont FontCollection::baseFontFaked(FontStyle style) { 41813f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien if (mFamilies.empty()) { 4199a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien return FakedFont(); 42089566f0ada1cafe673efa064cde38467990235d4Raph Levien } 42113f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien return mFamilies[0]->getClosestMatch(style); 42289566f0ada1cafe673efa064cde38467990235d4Raph Levien} 42389566f0ada1cafe673efa064cde38467990235d4Raph Levien 4244d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levienuint32_t FontCollection::getId() const { 4254d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien return mId; 4264d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien} 4274d4e6bc8118d15542f1f2a9218f0f7a91a29474fRaph Levien 4289cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} // namespace android 429