FontFamily.cpp revision aaa4e3470270496e6eb80704eadecb2cb7c56bf0
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 <cutils/log.h> 209cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <stdlib.h> 219cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <stdint.h> 224b723bf22b1bbc5fcdaa9bd96178c921199905d5Roozbeh Pournader#include <string.h> 23c31e3883456e018d742e9f29815ba5ff8b315ea1Raph Levien 240f2a025d135f9ca52cc3cf917fffc29d6c126094Seigo Nonaka#include <hb.h> 250f2a025d135f9ca52cc3cf917fffc29d6c126094Seigo Nonaka#include <hb-ot.h> 260f2a025d135f9ca52cc3cf917fffc29d6c126094Seigo Nonaka 276d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka#include <utils/JenkinsHash.h> 286d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka 29198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka#include "FontLanguage.h" 306d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka#include "FontLanguageListCache.h" 3189e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka#include "HbFontCache.h" 32c31e3883456e018d742e9f29815ba5ff8b315ea1Raph Levien#include "MinikinInternal.h" 33bcc3dc5a2591a95a57e379e27cbad69c18e91e67Raph Levien#include <minikin/MinikinFont.h> 349cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <minikin/AnalyzeStyle.h> 3513f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien#include <minikin/CmapCoverage.h> 369cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien#include <minikin/FontFamily.h> 371279a3bf5ec6131efefbc51d52d24850fd81f676Kenny Root#include <UniquePtr.h> 389cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 399cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levienusing std::vector; 409cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 419cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Leviennamespace android { 429cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 436d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo NonakaFontStyle::FontStyle(int variant, int weight, bool italic) 446d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo 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 516d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonakahash_t FontStyle::hash() const { 526d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka uint32_t hash = JenkinsHashMix(0, bits); 536d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka hash = JenkinsHashMix(hash, mLanguageListId); 546d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka return JenkinsHashWhiten(hash); 556d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka} 566d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka 576d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka// static 586d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonakauint32_t FontStyle::registerLanguageList(const std::string& languages) { 596d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo Nonaka AutoMutex _l(gMinikinLock); 606d9dcd2cf3d3ed26a886e02d94c907311e7b1f83Seigo 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 68198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo NonakaFontFamily::FontFamily(int variant) : FontFamily(FontLanguageListCache::kEmptyListId, variant) { 69198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka} 70198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 71b80c1f19c58b927820a8a24bf2218e5645724608Raph LevienFontFamily::~FontFamily() { 72b80c1f19c58b927820a8a24bf2218e5645724608Raph Levien for (size_t i = 0; i < mFonts.size(); i++) { 73b80c1f19c58b927820a8a24bf2218e5645724608Raph Levien mFonts[i].typeface->UnrefLocked(); 74b80c1f19c58b927820a8a24bf2218e5645724608Raph Levien } 75b80c1f19c58b927820a8a24bf2218e5645724608Raph Levien} 76b80c1f19c58b927820a8a24bf2218e5645724608Raph Levien 77bcc3dc5a2591a95a57e379e27cbad69c18e91e67Raph Levienbool FontFamily::addFont(MinikinFont* typeface) { 78c31e3883456e018d742e9f29815ba5ff8b315ea1Raph Levien AutoMutex _l(gMinikinLock); 79bcc3dc5a2591a95a57e379e27cbad69c18e91e67Raph Levien const uint32_t os2Tag = MinikinFont::MakeTag('O', 'S', '/', '2'); 80aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien HbBlob os2Table(getFontTable(typeface, os2Tag)); 81aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien if (os2Table.get() == nullptr) return false; 829cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien int weight; 839cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien bool italic; 84aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien if (analyzeStyle(os2Table.get(), os2Table.size(), &weight, &italic)) { 859cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien //ALOGD("analyzed weight = %d, italic = %s", weight, italic ? "true" : "false"); 869cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien FontStyle style(weight, italic); 87c31e3883456e018d742e9f29815ba5ff8b315ea1Raph Levien addFontLocked(typeface, style); 889cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return true; 899cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } else { 909cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien ALOGD("failed to analyze style"); 919cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 929cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return false; 939cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 949cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 95bcc3dc5a2591a95a57e379e27cbad69c18e91e67Raph Levienvoid FontFamily::addFont(MinikinFont* typeface, FontStyle style) { 96c31e3883456e018d742e9f29815ba5ff8b315ea1Raph Levien AutoMutex _l(gMinikinLock); 97c31e3883456e018d742e9f29815ba5ff8b315ea1Raph Levien addFontLocked(typeface, style); 98c31e3883456e018d742e9f29815ba5ff8b315ea1Raph Levien} 99c31e3883456e018d742e9f29815ba5ff8b315ea1Raph Levien 100198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonakavoid FontFamily::addFontLocked(MinikinFont* typeface, FontStyle style) { 101198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka typeface->RefLocked(); 1029cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien mFonts.push_back(Font(typeface, style)); 10313f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien mCoverageValid = false; 1049cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 1059cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 1069cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien// Compute a matching metric between two styles - 0 is an exact match 1079a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levienstatic int computeMatch(FontStyle style1, FontStyle style2) { 1089cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (style1 == style2) return 0; 1099cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien int score = abs(style1.getWeight() - style2.getWeight()); 1109cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (style1.getItalic() != style2.getItalic()) { 1119cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien score += 2; 1129cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1139cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return score; 1149cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 1159cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 1169a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levienstatic FontFakery computeFakery(FontStyle wanted, FontStyle actual) { 117d5804e3937a961736e5cef0e8a70eacf91ee00bbRaph Levien // If desired weight is semibold or darker, and 2 or more grades 118d5804e3937a961736e5cef0e8a70eacf91ee00bbRaph Levien // higher than actual (for example, medium 500 -> bold 700), then 119d5804e3937a961736e5cef0e8a70eacf91ee00bbRaph Levien // select fake bold. 1209f9f3b1ef40f7358dca6acd9dfef686cedefb6aaRaph Levien int wantedWeight = wanted.getWeight(); 121d5804e3937a961736e5cef0e8a70eacf91ee00bbRaph Levien bool isFakeBold = wantedWeight >= 6 && (wantedWeight - actual.getWeight()) >= 2; 1229a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien bool isFakeItalic = wanted.getItalic() && !actual.getItalic(); 1239a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien return FontFakery(isFakeBold, isFakeItalic); 1249a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien} 1259a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien 1269a5f713add8cfb91ac2c9ed5c917309053201ab6Raph LevienFakedFont FontFamily::getClosestMatch(FontStyle style) const { 1279cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const Font* bestFont = NULL; 1289cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien int bestMatch = 0; 1299cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien for (size_t i = 0; i < mFonts.size(); i++) { 1309cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien const Font& font = mFonts[i]; 1319cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien int match = computeMatch(font.style, style); 1329cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien if (i == 0 || match < bestMatch) { 1339cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien bestFont = &font; 1349cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien bestMatch = match; 1359cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1369cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien } 1379a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien FakedFont result; 1389a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien if (bestFont == NULL) { 1399a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien result.font = NULL; 1409a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien } else { 1419a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien result.font = bestFont->typeface; 1429a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien result.fakery = computeFakery(style, bestFont->style); 1439a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien } 1449a5f713add8cfb91ac2c9ed5c917309053201ab6Raph Levien return result; 1459cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 1469cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 1479cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Leviensize_t FontFamily::getNumFonts() const { 1489cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return mFonts.size(); 1499cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 1509cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 151bcc3dc5a2591a95a57e379e27cbad69c18e91e67Raph LevienMinikinFont* FontFamily::getFont(size_t index) const { 1529cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return mFonts[index].typeface; 1539cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 1549cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 1559cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph LevienFontStyle FontFamily::getStyle(size_t index) const { 1569cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien return mFonts[index].style; 1579cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} 1589cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien 15913f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levienconst SparseBitSet* FontFamily::getCoverage() { 16013f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien if (!mCoverageValid) { 16113f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien const FontStyle defaultStyle; 16213f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien MinikinFont* typeface = getClosestMatch(defaultStyle).font; 16313f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien const uint32_t cmapTag = MinikinFont::MakeTag('c', 'm', 'a', 'p'); 164aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien HbBlob cmapTable(getFontTable(typeface, cmapTag)); 165aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien if (cmapTable.get() == nullptr) { 166cb20a2f0b366bfc16db3a489a60156dec7a9fe21Andreas Gampe ALOGE("Could not get cmap table size!\n"); 167cb20a2f0b366bfc16db3a489a60156dec7a9fe21Andreas Gampe // Note: This means we will retry on the next call to getCoverage, as we can't store 168cb20a2f0b366bfc16db3a489a60156dec7a9fe21Andreas Gampe // the failure. This is fine, as we assume this doesn't really happen in practice. 169cb20a2f0b366bfc16db3a489a60156dec7a9fe21Andreas Gampe return nullptr; 170cb20a2f0b366bfc16db3a489a60156dec7a9fe21Andreas Gampe } 1716b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka // TODO: Error check? 172aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien CmapCoverage::getCoverage(mCoverage, cmapTable.get(), cmapTable.size(), &mHasVSTable); 17313f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien#ifdef VERBOSE_DEBUG 174bae347682989d2627081310129a5b60541ed6ad0Seigo Nonaka ALOGD("font coverage length=%d, first ch=%x\n", mCoverage.length(), 175bae347682989d2627081310129a5b60541ed6ad0Seigo Nonaka mCoverage.nextSetBit(0)); 17613f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien#endif 17713f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien mCoverageValid = true; 17813f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien } 17913f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien return &mCoverage; 18013f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien} 18113f1aae02bacd475722bc8ea3fc2cf6abc1a82e3Raph Levien 1820f2a025d135f9ca52cc3cf917fffc29d6c126094Seigo Nonakabool FontFamily::hasVariationSelector(uint32_t codepoint, uint32_t variationSelector) { 1830f2a025d135f9ca52cc3cf917fffc29d6c126094Seigo Nonaka assertMinikinLocked(); 1846b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka if (!mHasVSTable) { 1856b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka return false; 1866b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka } 1876b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka 18889e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka const FontStyle defaultStyle; 18989e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka MinikinFont* minikinFont = getClosestMatch(defaultStyle).font; 19089e80237bc27af084c9ff316d4f47abf426eced8Seigo Nonaka hb_font_t* font = getHbFontLocked(minikinFont); 1910f2a025d135f9ca52cc3cf917fffc29d6c126094Seigo Nonaka uint32_t unusedGlyph; 192aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien bool result = hb_font_get_glyph(font, codepoint, variationSelector, &unusedGlyph); 193aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien hb_font_destroy(font); 194aaa4e3470270496e6eb80704eadecb2cb7c56bf0Raph Levien return result; 1950f2a025d135f9ca52cc3cf917fffc29d6c126094Seigo Nonaka} 1960f2a025d135f9ca52cc3cf917fffc29d6c126094Seigo Nonaka 1976b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonakabool FontFamily::hasVSTable() const { 1986b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka LOG_ALWAYS_FATAL_IF(!mCoverageValid, "Do not call this method before getCoverage() call"); 1996b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka return mHasVSTable; 2006b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka} 2016b1c227da6492a435f0341d7fe95d9992669920eSeigo Nonaka 2029cc9bbe1461f359f0b27c5e7645c17dda001ab1dRaph Levien} // namespace android 203