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
179cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#define LOG_TAG "Minikin"
189cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
199cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <stdint.h>
20555d84c6f98eafcbe677cdcb8e9605760acd8ce5Mark Salyzyn#include <stdlib.h>
214b723bf22b1bbc5fcdaa9bd96178c921199905d5Roozbeh Pournader#include <string.h>
22c31e3883456e018d742e9f29815ba5ff8b315ea1Raph Levien
2339ab40115fae6d0c948e435233b3dd997ee7d8e5Mark Salyzyn#include <log/log.h>
24555d84c6f98eafcbe677cdcb8e9605760acd8ce5Mark Salyzyn#include <utils/JenkinsHash.h>
25555d84c6f98eafcbe677cdcb8e9605760acd8ce5Mark Salyzyn
260f2a025d135f9ca52cc3cf917fffc29d6c126094Seigo Nonaka#include <hb.h>
270f2a025d135f9ca52cc3cf917fffc29d6c126094Seigo Nonaka#include <hb-ot.h>
280f2a025d135f9ca52cc3cf917fffc29d6c126094Seigo Nonaka
29198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka#include "FontLanguage.h"
306d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka#include "FontLanguageListCache.h"
31065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka#include "FontUtils.h"
3289e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka#include "HbFontCache.h"
33c31e3883456e018d742e9f29815ba5ff8b315ea1Raph Levien#include "MinikinInternal.h"
3413f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien#include <minikin/CmapCoverage.h>
35065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka#include <minikin/MinikinFont.h>
369cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <minikin/FontFamily.h>
37555d84c6f98eafcbe677cdcb8e9605760acd8ce5Mark Salyzyn#include <minikin/MinikinFont.h>
389cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
399cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienusing std::vector;
409cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
4114e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonakanamespace minikin {
429cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
436d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo NonakaFontStyle::FontStyle(int variant, int weight, bool italic)
44fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka        : FontStyle(FontLanguageListCache::kEmptyListId, variant, weight, italic) {
456d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka}
466d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka
476d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo NonakaFontStyle::FontStyle(uint32_t languageListId, int variant, int weight, bool italic)
486d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka        : bits(pack(variant, weight, italic)), mLanguageListId(languageListId) {
496d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka}
506d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka
5114e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonakaandroid::hash_t FontStyle::hash() const {
5214e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonaka    uint32_t hash = android::JenkinsHashMix(0, bits);
5314e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonaka    hash = android::JenkinsHashMix(hash, mLanguageListId);
5414e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonaka    return android::JenkinsHashWhiten(hash);
556d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka}
566d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka
576d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka// static
586d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonakauint32_t FontStyle::registerLanguageList(const std::string& languages) {
59fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    android::AutoMutex _l(gMinikinLock);
60fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    return FontLanguageListCache::getId(languages);
616d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka}
626d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka
636d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka// static
646d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonakauint32_t FontStyle::pack(int variant, int weight, bool italic) {
656d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka    return (weight & kWeightMask) | (italic ? kItalicMask : 0) | (variant << kVariantShift);
666d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka}
676d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka
68dfbc6e374259f9d81940b5195ac013b02429af27Seigo NonakaFont::Font(const std::shared_ptr<MinikinFont>& typeface, FontStyle style)
6941718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka    : typeface(typeface), style(style) {
70dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka}
71dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka
72dfbc6e374259f9d81940b5195ac013b02429af27Seigo NonakaFont::Font(std::shared_ptr<MinikinFont>&& typeface, FontStyle style)
73dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka    : typeface(typeface), style(style) {
74dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka}
75065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka
761adbccfd0f40ef416e4f76ea16cbc0bae549d669Seigo Nonakastd::unordered_set<AxisTag> Font::getSupportedAxesLocked() const {
77065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    const uint32_t fvarTag = MinikinFont::MakeTag('f', 'v', 'a', 'r');
78dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka    HbBlob fvarTable(getFontTable(typeface.get(), fvarTag));
79065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    if (fvarTable.size() == 0) {
801adbccfd0f40ef416e4f76ea16cbc0bae549d669Seigo Nonaka        return std::unordered_set<AxisTag>();
81065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    }
82065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka
831adbccfd0f40ef416e4f76ea16cbc0bae549d669Seigo Nonaka    std::unordered_set<AxisTag> supportedAxes;
84065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    analyzeAxes(fvarTable.get(), fvarTable.size(), &supportedAxes);
851adbccfd0f40ef416e4f76ea16cbc0bae549d669Seigo Nonaka    return supportedAxes;
86994aa84f7b18466806fe552ea57da1852b909f24Seigo Nonaka}
87994aa84f7b18466806fe552ea57da1852b909f24Seigo Nonaka
8841718c770d0ae12133270a4ee4a8dbd27851480dSeigo NonakaFont::Font(Font&& o) {
89dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka    typeface = std::move(o.typeface);
9041718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka    style = o.style;
9141718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka    o.typeface = nullptr;
9241e02e96131c1ec66d013e4615348be013518dc4Seigo Nonaka}
9341e02e96131c1ec66d013e4615348be013518dc4Seigo Nonaka
9441718c770d0ae12133270a4ee4a8dbd27851480dSeigo NonakaFont::Font(const Font& o) {
9541718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka    typeface = o.typeface;
9641718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka    style = o.style;
97c31e3883456e018d742e9f29815ba5ff8b315ea1Raph Levien}
98c31e3883456e018d742e9f29815ba5ff8b315ea1Raph Levien
99dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka// static
10041718c770d0ae12133270a4ee4a8dbd27851480dSeigo NonakaFontFamily::FontFamily(std::vector<Font>&& fonts) : FontFamily(0 /* variant */, std::move(fonts)) {
10141718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka}
10241718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka
10341718c770d0ae12133270a4ee4a8dbd27851480dSeigo NonakaFontFamily::FontFamily(int variant, std::vector<Font>&& fonts)
104fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    : FontFamily(FontLanguageListCache::kEmptyListId, variant, std::move(fonts)) {
10541718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka}
10641718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka
10741718c770d0ae12133270a4ee4a8dbd27851480dSeigo NonakaFontFamily::FontFamily(uint32_t langId, int variant, std::vector<Font>&& fonts)
1089196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka    : mLangId(langId), mVariant(variant), mFonts(std::move(fonts)) {
10941718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka    computeCoverage();
11041718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka}
11141718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka
112dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonakabool FontFamily::analyzeStyle(const std::shared_ptr<MinikinFont>& typeface, int* weight,
113dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka        bool* italic) {
114fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    android::AutoMutex _l(gMinikinLock);
11541718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka    const uint32_t os2Tag = MinikinFont::MakeTag('O', 'S', '/', '2');
116dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka    HbBlob os2Table(getFontTable(typeface.get(), os2Tag));
11741718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka    if (os2Table.get() == nullptr) return false;
11841718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka    return ::minikin::analyzeStyle(os2Table.get(), os2Table.size(), weight, italic);
1199cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
1209cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
1219cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien// Compute a matching metric between two styles - 0 is an exact match
1229a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levienstatic int computeMatch(FontStyle style1, FontStyle style2) {
1239cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (style1 == style2) return 0;
1249cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    int score = abs(style1.getWeight() - style2.getWeight());
1259cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    if (style1.getItalic() != style2.getItalic()) {
1269cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        score += 2;
1279cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
1289cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    return score;
1299cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
1309cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
1319a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levienstatic FontFakery computeFakery(FontStyle wanted, FontStyle actual) {
132d5804e3937a961736e5cef0e8a70eacf91ee00bbRaph Levien    // If desired weight is semibold or darker, and 2 or more grades
133d5804e3937a961736e5cef0e8a70eacf91ee00bbRaph Levien    // higher than actual (for example, medium 500 -> bold 700), then
134d5804e3937a961736e5cef0e8a70eacf91ee00bbRaph Levien    // select fake bold.
1359f9f3b1ef40f7358dca6acd9dfef686cedefb6aaRaph Levien    int wantedWeight = wanted.getWeight();
136d5804e3937a961736e5cef0e8a70eacf91ee00bbRaph Levien    bool isFakeBold = wantedWeight >= 6 && (wantedWeight - actual.getWeight()) >= 2;
1379a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien    bool isFakeItalic = wanted.getItalic() && !actual.getItalic();
1389a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien    return FontFakery(isFakeBold, isFakeItalic);
1399a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien}
1409a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien
1419a5f713add8cfb91ac2c9ed5c917309053201ab6Raph LevienFakedFont FontFamily::getClosestMatch(FontStyle style) const {
142dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka    const Font* bestFont = nullptr;
1439cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    int bestMatch = 0;
1449cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    for (size_t i = 0; i < mFonts.size(); i++) {
1459cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        const Font& font = mFonts[i];
1469cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        int match = computeMatch(font.style, style);
1479cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        if (i == 0 || match < bestMatch) {
1489cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            bestFont = &font;
1499cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien            bestMatch = match;
1509cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien        }
1519cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien    }
152dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka    if (bestFont != nullptr) {
153dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka        return FakedFont{ bestFont->typeface.get(), computeFakery(style, bestFont->style) };
1549a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien    }
155dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka    return FakedFont{ nullptr, FontFakery() };
1569cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien}
1579cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien
158994aa84f7b18466806fe552ea57da1852b909f24Seigo Nonakabool FontFamily::isColorEmojiFamily() const {
159fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    const FontLanguages& languageList = FontLanguageListCache::getById(mLangId);
160994aa84f7b18466806fe552ea57da1852b909f24Seigo Nonaka    for (size_t i = 0; i < languageList.size(); ++i) {
161e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui        if (languageList[i].getEmojiStyle() == FontLanguage::EMSTYLE_EMOJI) {
162994aa84f7b18466806fe552ea57da1852b909f24Seigo Nonaka            return true;
163994aa84f7b18466806fe552ea57da1852b909f24Seigo Nonaka        }
164994aa84f7b18466806fe552ea57da1852b909f24Seigo Nonaka    }
165994aa84f7b18466806fe552ea57da1852b909f24Seigo Nonaka    return false;
166994aa84f7b18466806fe552ea57da1852b909f24Seigo Nonaka}
167994aa84f7b18466806fe552ea57da1852b909f24Seigo Nonaka
16841718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonakavoid FontFamily::computeCoverage() {
169fd4124c53399581dd94eac5a9749bc07b474a294Seigo Nonaka    android::AutoMutex _l(gMinikinLock);
17041718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka    const FontStyle defaultStyle;
171dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka    const MinikinFont* typeface = getClosestMatch(defaultStyle).font;
17241718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka    const uint32_t cmapTag = MinikinFont::MakeTag('c', 'm', 'a', 'p');
17341718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka    HbBlob cmapTable(getFontTable(typeface, cmapTag));
17441718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka    if (cmapTable.get() == nullptr) {
17541718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka        ALOGE("Could not get cmap table size!\n");
17641718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka        return;
17741718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonaka    }
1789196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka    mCoverage = CmapCoverage::getCoverage(cmapTable.get(), cmapTable.size(), &mCmapFmt14Coverage);
179065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka
180065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    for (size_t i = 0; i < mFonts.size(); ++i) {
1811adbccfd0f40ef416e4f76ea16cbc0bae549d669Seigo Nonaka        std::unordered_set<AxisTag> supportedAxes = mFonts[i].getSupportedAxesLocked();
1821adbccfd0f40ef416e4f76ea16cbc0bae549d669Seigo Nonaka        mSupportedAxes.insert(supportedAxes.begin(), supportedAxes.end());
183065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    }
18413f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien}
18513f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien
18641718c770d0ae12133270a4ee4a8dbd27851480dSeigo Nonakabool FontFamily::hasGlyph(uint32_t codepoint, uint32_t variationSelector) const {
1879196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka    if (variationSelector == 0) {
1889196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka        return mCoverage.get(codepoint);
1899196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka    }
1909196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka
1919196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka    if (mCmapFmt14Coverage.empty()) {
1926b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka        return false;
1936b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka    }
1946b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka
1959196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka    const uint16_t vsIndex = getVsIndex(variationSelector);
1969196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka
1979196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka    if (vsIndex >= mCmapFmt14Coverage.size()) {
1989196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka        // Even if vsIndex is INVALID_VS_INDEX, we reach here since INVALID_VS_INDEX is defined to
1999196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka        // be at the maximum end of the range.
2009196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka        return false;
2019196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka    }
2029196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka
2039196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka    const std::unique_ptr<SparseBitSet>& bitset = mCmapFmt14Coverage[vsIndex];
2049196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka    if (bitset.get() == nullptr) {
2059196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka        return false;
2069196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka    }
2079196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka
2089196194d76e4325c5bb0c23f22a5787a717067edSeigo Nonaka    return bitset->get(codepoint);
2090f2a025d135f9ca52cc3cf917fffc29d6c126094Seigo Nonaka}
2100f2a025d135f9ca52cc3cf917fffc29d6c126094Seigo Nonaka
211dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonakastd::shared_ptr<FontFamily> FontFamily::createFamilyWithVariation(
212065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka        const std::vector<FontVariation>& variations) const {
213065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    if (variations.empty() || mSupportedAxes.empty()) {
214065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka        return nullptr;
215065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    }
216065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka
217065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    bool hasSupportedAxis = false;
218065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    for (const FontVariation& variation : variations) {
219065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka        if (mSupportedAxes.find(variation.axisTag) != mSupportedAxes.end()) {
220065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka            hasSupportedAxis = true;
221065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka            break;
222065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka        }
223065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    }
224065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    if (!hasSupportedAxis) {
225065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka        // None of variation axes are suppored by this family.
226065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka        return nullptr;
227065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    }
228065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka
229065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    std::vector<Font> fonts;
230065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    for (const Font& font : mFonts) {
231065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka        bool supportedVariations = false;
2321adbccfd0f40ef416e4f76ea16cbc0bae549d669Seigo Nonaka        android::AutoMutex _l(gMinikinLock);
2331adbccfd0f40ef416e4f76ea16cbc0bae549d669Seigo Nonaka        std::unordered_set<AxisTag> supportedAxes = font.getSupportedAxesLocked();
2341adbccfd0f40ef416e4f76ea16cbc0bae549d669Seigo Nonaka        if (!supportedAxes.empty()) {
235065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka            for (const FontVariation& variation : variations) {
2361adbccfd0f40ef416e4f76ea16cbc0bae549d669Seigo Nonaka                if (supportedAxes.find(variation.axisTag) != supportedAxes.end()) {
237065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka                    supportedVariations = true;
238065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka                    break;
239065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka                }
240065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka            }
241065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka        }
242dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka        std::shared_ptr<MinikinFont> minikinFont;
243065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka        if (supportedVariations) {
244065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka            minikinFont = font.typeface->createFontWithVariation(variations);
245065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka        }
246065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka        if (minikinFont == nullptr) {
247065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka            minikinFont = font.typeface;
248065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka        }
249dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka        fonts.push_back(Font(std::move(minikinFont), font.style));
250065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka    }
251065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka
252dfbc6e374259f9d81940b5195ac013b02429af27Seigo Nonaka    return std::shared_ptr<FontFamily>(new FontFamily(mLangId, mVariant, std::move(fonts)));
253065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka}
254065c46a665d562c93ffa82fda10dee52a16ac23bSeigo Nonaka
25514e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonaka}  // namespace minikin
256