| // Copyright 2016 PDFium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| |
| #include "core/fxge/cfx_fontmapper.h" |
| |
| #include <algorithm> |
| #include <memory> |
| #include <sstream> |
| #include <utility> |
| #include <vector> |
| |
| #include "core/fxcrt/fx_codepage.h" |
| #include "core/fxge/cfx_substfont.h" |
| #include "core/fxge/fx_font.h" |
| #include "core/fxge/ifx_systemfontinfo.h" |
| |
| #include "third_party/base/stl_util.h" |
| |
| #define FX_FONT_STYLE_None 0x00 |
| #define FX_FONT_STYLE_Bold 0x01 |
| #define FX_FONT_STYLE_Italic 0x02 |
| #define FX_FONT_STYLE_BoldBold 0x04 |
| |
| namespace { |
| |
| const int kNumStandardFonts = 14; |
| |
| const char* const g_Base14FontNames[kNumStandardFonts] = { |
| "Courier", |
| "Courier-Bold", |
| "Courier-BoldOblique", |
| "Courier-Oblique", |
| "Helvetica", |
| "Helvetica-Bold", |
| "Helvetica-BoldOblique", |
| "Helvetica-Oblique", |
| "Times-Roman", |
| "Times-Bold", |
| "Times-BoldItalic", |
| "Times-Italic", |
| "Symbol", |
| "ZapfDingbats", |
| }; |
| |
| const struct AltFontName { |
| const char* m_pName; |
| int m_Index; |
| } g_AltFontNames[] = { |
| {"Arial", 4}, |
| {"Arial,Bold", 5}, |
| {"Arial,BoldItalic", 6}, |
| {"Arial,Italic", 7}, |
| {"Arial-Bold", 5}, |
| {"Arial-BoldItalic", 6}, |
| {"Arial-BoldItalicMT", 6}, |
| {"Arial-BoldMT", 5}, |
| {"Arial-Italic", 7}, |
| {"Arial-ItalicMT", 7}, |
| {"ArialBold", 5}, |
| {"ArialBoldItalic", 6}, |
| {"ArialItalic", 7}, |
| {"ArialMT", 4}, |
| {"ArialMT,Bold", 5}, |
| {"ArialMT,BoldItalic", 6}, |
| {"ArialMT,Italic", 7}, |
| {"ArialRoundedMTBold", 5}, |
| {"Courier", 0}, |
| {"Courier,Bold", 1}, |
| {"Courier,BoldItalic", 2}, |
| {"Courier,Italic", 3}, |
| {"Courier-Bold", 1}, |
| {"Courier-BoldOblique", 2}, |
| {"Courier-Oblique", 3}, |
| {"CourierBold", 1}, |
| {"CourierBoldItalic", 2}, |
| {"CourierItalic", 3}, |
| {"CourierNew", 0}, |
| {"CourierNew,Bold", 1}, |
| {"CourierNew,BoldItalic", 2}, |
| {"CourierNew,Italic", 3}, |
| {"CourierNew-Bold", 1}, |
| {"CourierNew-BoldItalic", 2}, |
| {"CourierNew-Italic", 3}, |
| {"CourierNewBold", 1}, |
| {"CourierNewBoldItalic", 2}, |
| {"CourierNewItalic", 3}, |
| {"CourierNewPS-BoldItalicMT", 2}, |
| {"CourierNewPS-BoldMT", 1}, |
| {"CourierNewPS-ItalicMT", 3}, |
| {"CourierNewPSMT", 0}, |
| {"CourierStd", 0}, |
| {"CourierStd-Bold", 1}, |
| {"CourierStd-BoldOblique", 2}, |
| {"CourierStd-Oblique", 3}, |
| {"Helvetica", 4}, |
| {"Helvetica,Bold", 5}, |
| {"Helvetica,BoldItalic", 6}, |
| {"Helvetica,Italic", 7}, |
| {"Helvetica-Bold", 5}, |
| {"Helvetica-BoldItalic", 6}, |
| {"Helvetica-BoldOblique", 6}, |
| {"Helvetica-Italic", 7}, |
| {"Helvetica-Oblique", 7}, |
| {"HelveticaBold", 5}, |
| {"HelveticaBoldItalic", 6}, |
| {"HelveticaItalic", 7}, |
| {"Symbol", 12}, |
| {"SymbolMT", 12}, |
| {"Times-Bold", 9}, |
| {"Times-BoldItalic", 10}, |
| {"Times-Italic", 11}, |
| {"Times-Roman", 8}, |
| {"TimesBold", 9}, |
| {"TimesBoldItalic", 10}, |
| {"TimesItalic", 11}, |
| {"TimesNewRoman", 8}, |
| {"TimesNewRoman,Bold", 9}, |
| {"TimesNewRoman,BoldItalic", 10}, |
| {"TimesNewRoman,Italic", 11}, |
| {"TimesNewRoman-Bold", 9}, |
| {"TimesNewRoman-BoldItalic", 10}, |
| {"TimesNewRoman-Italic", 11}, |
| {"TimesNewRomanBold", 9}, |
| {"TimesNewRomanBoldItalic", 10}, |
| {"TimesNewRomanItalic", 11}, |
| {"TimesNewRomanPS", 8}, |
| {"TimesNewRomanPS-Bold", 9}, |
| {"TimesNewRomanPS-BoldItalic", 10}, |
| {"TimesNewRomanPS-BoldItalicMT", 10}, |
| {"TimesNewRomanPS-BoldMT", 9}, |
| {"TimesNewRomanPS-Italic", 11}, |
| {"TimesNewRomanPS-ItalicMT", 11}, |
| {"TimesNewRomanPSMT", 8}, |
| {"TimesNewRomanPSMT,Bold", 9}, |
| {"TimesNewRomanPSMT,BoldItalic", 10}, |
| {"TimesNewRomanPSMT,Italic", 11}, |
| {"ZapfDingbats", 13}, |
| }; |
| |
| const struct AltFontFamily { |
| const char* m_pFontName; |
| const char* m_pFontFamily; |
| } g_AltFontFamilies[] = { |
| {"AGaramondPro", "Adobe Garamond Pro"}, |
| {"BankGothicBT-Medium", "BankGothic Md BT"}, |
| {"ForteMT", "Forte"}, |
| }; |
| |
| const struct FX_FontStyle { |
| const char* style; |
| int32_t len; |
| } g_FontStyles[] = { |
| {"Bold", 4}, {"Italic", 6}, {"BoldItalic", 10}, {"Reg", 3}, {"Regular", 7}, |
| }; |
| |
| const struct CODEPAGE_MAP { |
| uint16_t codepage; |
| uint8_t charset; |
| } g_Codepage2CharsetTable[] = { |
| {0, 1}, {42, 2}, {437, 254}, {850, 255}, {874, 222}, |
| {932, 128}, {936, 134}, {949, 129}, {950, 136}, {1250, 238}, |
| {1251, 204}, {1252, 0}, {1253, 161}, {1254, 162}, {1255, 177}, |
| {1256, 178}, {1257, 186}, {1258, 163}, {1361, 130}, {10000, 77}, |
| {10001, 78}, {10002, 81}, {10003, 79}, {10004, 84}, {10005, 83}, |
| {10006, 85}, {10007, 89}, {10008, 80}, {10021, 87}, {10029, 88}, |
| {10081, 86}, |
| }; |
| |
| int CompareFontFamilyString(const void* key, const void* element) { |
| CFX_ByteString str_key((const char*)key); |
| const AltFontFamily* family = reinterpret_cast<const AltFontFamily*>(element); |
| if (str_key.Find(family->m_pFontName) != FX_STRNPOS) |
| return 0; |
| return FXSYS_stricmp(reinterpret_cast<const char*>(key), family->m_pFontName); |
| } |
| |
| int CompareString(const void* key, const void* element) { |
| return FXSYS_stricmp(reinterpret_cast<const char*>(key), |
| reinterpret_cast<const AltFontName*>(element)->m_pName); |
| } |
| |
| CFX_ByteString TT_NormalizeName(const char* family) { |
| CFX_ByteString norm(family); |
| norm.Remove(' '); |
| norm.Remove('-'); |
| norm.Remove(','); |
| FX_STRSIZE pos = norm.Find('+'); |
| if (pos != 0 && pos != FX_STRNPOS) |
| norm = norm.Left(pos); |
| norm.MakeLower(); |
| return norm; |
| } |
| |
| uint8_t GetCharsetFromCodePage(uint16_t codepage) { |
| const CODEPAGE_MAP* pEnd = |
| g_Codepage2CharsetTable + FX_ArraySize(g_Codepage2CharsetTable); |
| const CODEPAGE_MAP* pCharmap = |
| std::lower_bound(g_Codepage2CharsetTable, pEnd, codepage, |
| [](const CODEPAGE_MAP& charset, uint16_t page) { |
| return charset.codepage < page; |
| }); |
| if (pCharmap < pEnd && codepage == pCharmap->codepage) |
| return pCharmap->charset; |
| return FX_CHARSET_Default; |
| } |
| |
| CFX_ByteString GetFontFamily(CFX_ByteString fontName, int nStyle) { |
| if (fontName.Find("Script") >= 0) { |
| if ((nStyle & FX_FONT_STYLE_Bold) == FX_FONT_STYLE_Bold) |
| fontName = "ScriptMTBold"; |
| else if (fontName.Find("Palace") >= 0) |
| fontName = "PalaceScriptMT"; |
| else if (fontName.Find("French") >= 0) |
| fontName = "FrenchScriptMT"; |
| else if (fontName.Find("FreeStyle") >= 0) |
| fontName = "FreeStyleScript"; |
| return fontName; |
| } |
| AltFontFamily* found = reinterpret_cast<AltFontFamily*>(bsearch( |
| fontName.c_str(), g_AltFontFamilies, FX_ArraySize(g_AltFontFamilies), |
| sizeof(AltFontFamily), CompareFontFamilyString)); |
| return found ? CFX_ByteString(found->m_pFontFamily) : fontName; |
| } |
| |
| CFX_ByteString ParseStyle(const char* pStyle, int iLen, int iIndex) { |
| std::ostringstream buf; |
| if (!iLen || iLen <= iIndex) |
| return CFX_ByteString(buf); |
| while (iIndex < iLen) { |
| if (pStyle[iIndex] == ',') |
| break; |
| buf << pStyle[iIndex]; |
| ++iIndex; |
| } |
| return CFX_ByteString(buf); |
| } |
| |
| int32_t GetStyleType(const CFX_ByteString& bsStyle, bool bReverse) { |
| int32_t iLen = bsStyle.GetLength(); |
| if (!iLen) |
| return -1; |
| int iSize = FX_ArraySize(g_FontStyles); |
| const FX_FontStyle* pStyle = nullptr; |
| for (int i = iSize - 1; i >= 0; --i) { |
| pStyle = g_FontStyles + i; |
| if (!pStyle || pStyle->len > iLen) |
| continue; |
| |
| if (bReverse) { |
| if (bsStyle.Right(pStyle->len).Compare(pStyle->style) == 0) |
| return i; |
| } else { |
| if (bsStyle.Left(pStyle->len).Compare(pStyle->style) == 0) |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| bool CheckSupportThirdPartFont(CFX_ByteString name, int& PitchFamily) { |
| if (name == "MyriadPro") { |
| PitchFamily &= ~FXFONT_FF_ROMAN; |
| return true; |
| } |
| return false; |
| } |
| |
| void UpdatePitchFamily(uint32_t flags, int& PitchFamily) { |
| if (flags & FXFONT_SERIF) |
| PitchFamily |= FXFONT_FF_ROMAN; |
| if (flags & FXFONT_SCRIPT) |
| PitchFamily |= FXFONT_FF_SCRIPT; |
| if (flags & FXFONT_FIXED_PITCH) |
| PitchFamily |= FXFONT_FF_FIXEDPITCH; |
| } |
| |
| } // namespace |
| |
| CFX_FontMapper::CFX_FontMapper(CFX_FontMgr* mgr) |
| : m_bListLoaded(false), m_pFontMgr(mgr) { |
| m_MMFaces[0] = nullptr; |
| m_MMFaces[1] = nullptr; |
| memset(m_FoxitFaces, 0, sizeof(m_FoxitFaces)); |
| } |
| |
| CFX_FontMapper::~CFX_FontMapper() { |
| for (size_t i = 0; i < FX_ArraySize(m_FoxitFaces); ++i) { |
| if (m_FoxitFaces[i]) |
| FXFT_Done_Face(m_FoxitFaces[i]); |
| } |
| if (m_MMFaces[0]) |
| FXFT_Done_Face(m_MMFaces[0]); |
| if (m_MMFaces[1]) |
| FXFT_Done_Face(m_MMFaces[1]); |
| } |
| |
| void CFX_FontMapper::SetSystemFontInfo( |
| std::unique_ptr<IFX_SystemFontInfo> pFontInfo) { |
| if (!pFontInfo) |
| return; |
| |
| m_pFontInfo = std::move(pFontInfo); |
| } |
| |
| CFX_ByteString CFX_FontMapper::GetPSNameFromTT(void* hFont) { |
| if (!m_pFontInfo) |
| return CFX_ByteString(); |
| |
| uint32_t size = m_pFontInfo->GetFontData(hFont, kTableNAME, nullptr, 0); |
| if (!size) |
| return CFX_ByteString(); |
| |
| std::vector<uint8_t> buffer(size); |
| uint8_t* buffer_ptr = buffer.data(); |
| uint32_t bytes_read = |
| m_pFontInfo->GetFontData(hFont, kTableNAME, buffer_ptr, size); |
| return bytes_read == size ? GetNameFromTT(buffer_ptr, bytes_read, 6) |
| : CFX_ByteString(); |
| } |
| |
| void CFX_FontMapper::AddInstalledFont(const CFX_ByteString& name, int charset) { |
| if (!m_pFontInfo) |
| return; |
| |
| m_FaceArray.push_back({name, static_cast<uint32_t>(charset)}); |
| if (name == m_LastFamily) |
| return; |
| |
| bool bLocalized = std::any_of(name.begin(), name.end(), [](const char& c) { |
| return static_cast<uint8_t>(c) > 0x80; |
| }); |
| |
| if (bLocalized) { |
| void* hFont = m_pFontInfo->GetFont(name.c_str()); |
| if (!hFont) { |
| int iExact; |
| hFont = m_pFontInfo->MapFont(0, 0, FX_CHARSET_Default, 0, name.c_str(), |
| iExact); |
| if (!hFont) |
| return; |
| } |
| |
| CFX_ByteString new_name = GetPSNameFromTT(hFont); |
| if (!new_name.IsEmpty()) |
| m_LocalizedTTFonts.push_back(std::make_pair(new_name, name)); |
| m_pFontInfo->DeleteFont(hFont); |
| } |
| m_InstalledTTFonts.push_back(name); |
| m_LastFamily = name; |
| } |
| |
| void CFX_FontMapper::LoadInstalledFonts() { |
| if (!m_pFontInfo || m_bListLoaded) |
| return; |
| |
| m_pFontInfo->EnumFontList(this); |
| m_bListLoaded = true; |
| } |
| |
| CFX_ByteString CFX_FontMapper::MatchInstalledFonts( |
| const CFX_ByteString& norm_name) { |
| LoadInstalledFonts(); |
| int i; |
| for (i = pdfium::CollectionSize<int>(m_InstalledTTFonts) - 1; i >= 0; i--) { |
| CFX_ByteString norm1 = TT_NormalizeName(m_InstalledTTFonts[i].c_str()); |
| if (norm1 == norm_name) |
| return m_InstalledTTFonts[i]; |
| } |
| for (i = pdfium::CollectionSize<int>(m_LocalizedTTFonts) - 1; i >= 0; i--) { |
| CFX_ByteString norm1 = |
| TT_NormalizeName(m_LocalizedTTFonts[i].first.c_str()); |
| if (norm1 == norm_name) |
| return m_LocalizedTTFonts[i].second; |
| } |
| return CFX_ByteString(); |
| } |
| |
| FXFT_Face CFX_FontMapper::UseInternalSubst(CFX_SubstFont* pSubstFont, |
| int iBaseFont, |
| int italic_angle, |
| int weight, |
| int picthfamily) { |
| if (iBaseFont < kNumStandardFonts) { |
| if (m_FoxitFaces[iBaseFont]) |
| return m_FoxitFaces[iBaseFont]; |
| const uint8_t* pFontData = nullptr; |
| uint32_t size = 0; |
| if (m_pFontMgr->GetBuiltinFont(iBaseFont, &pFontData, &size)) { |
| m_FoxitFaces[iBaseFont] = m_pFontMgr->GetFixedFace(pFontData, size, 0); |
| return m_FoxitFaces[iBaseFont]; |
| } |
| } |
| pSubstFont->m_SubstFlags |= FXFONT_SUBST_MM; |
| pSubstFont->m_ItalicAngle = italic_angle; |
| if (weight) |
| pSubstFont->m_Weight = weight; |
| if (picthfamily & FXFONT_FF_ROMAN) { |
| pSubstFont->m_Weight = pSubstFont->m_Weight * 4 / 5; |
| pSubstFont->m_Family = "Chrome Serif"; |
| if (m_MMFaces[1]) |
| return m_MMFaces[1]; |
| const uint8_t* pFontData = nullptr; |
| uint32_t size = 0; |
| m_pFontMgr->GetBuiltinFont(14, &pFontData, &size); |
| m_MMFaces[1] = m_pFontMgr->GetFixedFace(pFontData, size, 0); |
| return m_MMFaces[1]; |
| } |
| pSubstFont->m_Family = "Chrome Sans"; |
| if (m_MMFaces[0]) |
| return m_MMFaces[0]; |
| const uint8_t* pFontData = nullptr; |
| uint32_t size = 0; |
| m_pFontMgr->GetBuiltinFont(15, &pFontData, &size); |
| m_MMFaces[0] = m_pFontMgr->GetFixedFace(pFontData, size, 0); |
| return m_MMFaces[0]; |
| } |
| |
| FXFT_Face CFX_FontMapper::FindSubstFont(const CFX_ByteString& name, |
| bool bTrueType, |
| uint32_t flags, |
| int weight, |
| int italic_angle, |
| int WindowCP, |
| CFX_SubstFont* pSubstFont) { |
| if (!(flags & FXFONT_USEEXTERNATTR)) { |
| weight = FXFONT_FW_NORMAL; |
| italic_angle = 0; |
| } |
| CFX_ByteString SubstName = name; |
| SubstName.Remove(' '); |
| if (bTrueType && name[0] == '@') |
| SubstName = name.Right(name.GetLength() - 1); |
| PDF_GetStandardFontName(&SubstName); |
| if (SubstName == "Symbol" && !bTrueType) { |
| pSubstFont->m_Family = "Chrome Symbol"; |
| pSubstFont->m_Charset = FX_CHARSET_Symbol; |
| return UseInternalSubst(pSubstFont, 12, italic_angle, weight, 0); |
| } |
| if (SubstName == "ZapfDingbats") { |
| pSubstFont->m_Family = "Chrome Dingbats"; |
| pSubstFont->m_Charset = FX_CHARSET_Symbol; |
| return UseInternalSubst(pSubstFont, 13, italic_angle, weight, 0); |
| } |
| int iBaseFont = 0; |
| CFX_ByteString family; |
| CFX_ByteString style; |
| bool bHasComma = false; |
| bool bHasHyphen = false; |
| int find = SubstName.Find(",", 0); |
| if (find >= 0) { |
| family = SubstName.Left(find); |
| PDF_GetStandardFontName(&family); |
| style = SubstName.Right(SubstName.GetLength() - (find + 1)); |
| bHasComma = true; |
| } else { |
| family = SubstName; |
| } |
| for (; iBaseFont < 12; iBaseFont++) { |
| if (family == CFX_ByteStringC(g_Base14FontNames[iBaseFont])) |
| break; |
| } |
| int PitchFamily = 0; |
| bool bItalic = false; |
| uint32_t nStyle = 0; |
| bool bStyleAvail = false; |
| if (iBaseFont < 12) { |
| if ((iBaseFont % 4) == 1 || (iBaseFont % 4) == 2) |
| nStyle |= FX_FONT_STYLE_Bold; |
| if ((iBaseFont % 4) / 2) |
| nStyle |= FX_FONT_STYLE_Italic; |
| if (iBaseFont < 4) |
| PitchFamily |= FXFONT_FF_FIXEDPITCH; |
| if (iBaseFont >= 8) |
| PitchFamily |= FXFONT_FF_ROMAN; |
| } else { |
| iBaseFont = kNumStandardFonts; |
| if (!bHasComma) { |
| find = family.ReverseFind('-'); |
| if (find >= 0) { |
| style = family.Right(family.GetLength() - (find + 1)); |
| family = family.Left(find); |
| bHasHyphen = true; |
| } |
| } |
| if (!bHasHyphen) { |
| int nLen = family.GetLength(); |
| int32_t nRet = GetStyleType(family, true); |
| if (nRet > -1) { |
| family = family.Left(nLen - g_FontStyles[nRet].len); |
| if (nRet == 0) |
| nStyle |= FX_FONT_STYLE_Bold; |
| else if (nRet == 1) |
| nStyle |= FX_FONT_STYLE_Italic; |
| else if (nRet == 2) |
| nStyle |= (FX_FONT_STYLE_Bold | FX_FONT_STYLE_Italic); |
| } |
| } |
| UpdatePitchFamily(flags, PitchFamily); |
| } |
| if (!style.IsEmpty()) { |
| int nLen = style.GetLength(); |
| const char* pStyle = style.c_str(); |
| int i = 0; |
| bool bFirstItem = true; |
| CFX_ByteString buf; |
| while (i < nLen) { |
| buf = ParseStyle(pStyle, nLen, i); |
| int32_t nRet = GetStyleType(buf, false); |
| if ((i && !bStyleAvail) || (!i && nRet < 0)) { |
| family = SubstName; |
| iBaseFont = kNumStandardFonts; |
| break; |
| } |
| if (nRet >= 0) { |
| bStyleAvail = true; |
| } |
| if (nRet == 1) { |
| if (bFirstItem) { |
| nStyle |= FX_FONT_STYLE_Italic; |
| } else { |
| family = SubstName; |
| iBaseFont = kNumStandardFonts; |
| } |
| break; |
| } |
| if (nRet == 0) { |
| if (nStyle & FX_FONT_STYLE_Bold) |
| nStyle |= FX_FONT_STYLE_BoldBold; |
| else |
| nStyle |= FX_FONT_STYLE_Bold; |
| bFirstItem = false; |
| } else if (nRet == 2) { |
| nStyle |= FX_FONT_STYLE_Italic; |
| if (nStyle & FX_FONT_STYLE_Bold) |
| nStyle |= FX_FONT_STYLE_BoldBold; |
| else |
| nStyle |= FX_FONT_STYLE_Bold; |
| bFirstItem = false; |
| } |
| i += buf.GetLength() + 1; |
| } |
| } |
| weight = weight ? weight : FXFONT_FW_NORMAL; |
| int old_weight = weight; |
| if (nStyle) { |
| weight = |
| nStyle & FX_FONT_STYLE_BoldBold |
| ? 900 |
| : (nStyle & FX_FONT_STYLE_Bold ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL); |
| } |
| if (nStyle & FX_FONT_STYLE_Italic) |
| bItalic = true; |
| int iExact = 0; |
| int Charset = FX_CHARSET_ANSI; |
| if (WindowCP) |
| Charset = GetCharsetFromCodePage(WindowCP); |
| else if (iBaseFont == kNumStandardFonts && (flags & FXFONT_SYMBOLIC)) |
| Charset = FX_CHARSET_Symbol; |
| bool bCJK = (Charset == FX_CHARSET_ShiftJIS || |
| Charset == FX_CHARSET_ChineseSimplified || |
| Charset == FX_CHARSET_Hangul || |
| Charset == FX_CHARSET_ChineseTraditional); |
| if (!m_pFontInfo) { |
| return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight, |
| PitchFamily); |
| } |
| family = GetFontFamily(family, nStyle); |
| CFX_ByteString match = MatchInstalledFonts(TT_NormalizeName(family.c_str())); |
| if (match.IsEmpty() && family != SubstName && |
| (!bHasComma && (!bHasHyphen || (bHasHyphen && !bStyleAvail)))) { |
| match = MatchInstalledFonts(TT_NormalizeName(SubstName.c_str())); |
| } |
| if (match.IsEmpty() && iBaseFont >= kNumStandardFonts) { |
| if (!bCJK) { |
| if (!CheckSupportThirdPartFont(family, PitchFamily)) { |
| bItalic = italic_angle != 0; |
| weight = old_weight; |
| } |
| #if _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_ |
| if (SubstName.Find("Narrow") > 0 || SubstName.Find("Condensed") > 0) |
| family = "LiberationSansNarrow"; |
| #elif _FXM_PLATFORM_ == _FXM_PLATFORM_ANDROID_ |
| if (family.Find("Narrow") > 0 || family.Find("Condensed") > 0) |
| family = "RobotoCondensed"; |
| #else |
| if (family.Find("Narrow") > 0 || family.Find("Condensed") > 0) |
| family = "ArialNarrow"; |
| #endif // _FXM_PLATFORM_ == _FXM_PLATFORM_LINUX_ |
| } else { |
| pSubstFont->m_bSubstCJK = true; |
| if (nStyle) |
| pSubstFont->m_WeightCJK = nStyle ? weight : FXFONT_FW_NORMAL; |
| if (nStyle & FX_FONT_STYLE_Italic) |
| pSubstFont->m_bItalicCJK = true; |
| } |
| } else { |
| italic_angle = 0; |
| weight = |
| nStyle & FX_FONT_STYLE_BoldBold |
| ? 900 |
| : (nStyle & FX_FONT_STYLE_Bold ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL); |
| } |
| if (!match.IsEmpty() || iBaseFont < kNumStandardFonts) { |
| if (!match.IsEmpty()) |
| family = match; |
| if (iBaseFont < kNumStandardFonts) { |
| if (nStyle && !(iBaseFont % 4)) { |
| if ((nStyle & 0x3) == 1) |
| iBaseFont += 1; |
| if ((nStyle & 0x3) == 2) |
| iBaseFont += 3; |
| if ((nStyle & 0x3) == 3) |
| iBaseFont += 2; |
| } |
| family = g_Base14FontNames[iBaseFont]; |
| } |
| } else { |
| if (flags & FXFONT_ITALIC) |
| bItalic = true; |
| } |
| iExact = !match.IsEmpty(); |
| void* hFont = m_pFontInfo->MapFont(weight, bItalic, Charset, PitchFamily, |
| family.c_str(), iExact); |
| if (iExact) |
| pSubstFont->m_SubstFlags |= FXFONT_SUBST_EXACT; |
| if (!hFont) { |
| #ifdef PDF_ENABLE_XFA |
| if (flags & FXFONT_EXACTMATCH) |
| return nullptr; |
| #endif // PDF_ENABLE_XFA |
| if (bCJK) { |
| bItalic = italic_angle != 0; |
| weight = old_weight; |
| } |
| if (!match.IsEmpty()) { |
| hFont = m_pFontInfo->GetFont(match.c_str()); |
| if (!hFont) { |
| return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight, |
| PitchFamily); |
| } |
| } else { |
| if (Charset == FX_CHARSET_Symbol) { |
| #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_ || \ |
| _FXM_PLATFORM_ == _FXM_PLATFORM_ANDROID_ |
| if (SubstName == "Symbol") { |
| pSubstFont->m_Family = "Chrome Symbol"; |
| pSubstFont->m_Charset = FX_CHARSET_Symbol; |
| return UseInternalSubst(pSubstFont, 12, italic_angle, old_weight, |
| PitchFamily); |
| } |
| #endif |
| return FindSubstFont(family, bTrueType, flags & ~FXFONT_SYMBOLIC, |
| weight, italic_angle, 0, pSubstFont); |
| } |
| if (Charset == FX_CHARSET_ANSI) { |
| return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight, |
| PitchFamily); |
| } |
| |
| auto it = |
| std::find_if(m_FaceArray.begin(), m_FaceArray.end(), |
| [Charset](const FaceData& face) { |
| return face.charset == static_cast<uint32_t>(Charset); |
| }); |
| if (it == m_FaceArray.end()) { |
| return UseInternalSubst(pSubstFont, iBaseFont, italic_angle, old_weight, |
| PitchFamily); |
| } |
| hFont = m_pFontInfo->GetFont(it->name.c_str()); |
| } |
| } |
| if (!hFont) |
| return nullptr; |
| |
| m_pFontInfo->GetFaceName(hFont, &SubstName); |
| if (Charset == FX_CHARSET_Default) |
| m_pFontInfo->GetFontCharset(hFont, &Charset); |
| uint32_t ttc_size = m_pFontInfo->GetFontData(hFont, kTableTTCF, nullptr, 0); |
| uint32_t font_size = m_pFontInfo->GetFontData(hFont, 0, nullptr, 0); |
| if (font_size == 0 && ttc_size == 0) { |
| m_pFontInfo->DeleteFont(hFont); |
| return nullptr; |
| } |
| FXFT_Face face = nullptr; |
| if (ttc_size) |
| face = GetCachedTTCFace(hFont, kTableTTCF, ttc_size, font_size); |
| else |
| face = GetCachedFace(hFont, SubstName, weight, bItalic, font_size); |
| if (!face) { |
| m_pFontInfo->DeleteFont(hFont); |
| return nullptr; |
| } |
| pSubstFont->m_Family = SubstName; |
| pSubstFont->m_Charset = Charset; |
| bool bNeedUpdateWeight = false; |
| if (FXFT_Is_Face_Bold(face)) |
| bNeedUpdateWeight = weight != FXFONT_FW_BOLD; |
| else |
| bNeedUpdateWeight = weight != FXFONT_FW_NORMAL; |
| if (bNeedUpdateWeight) |
| pSubstFont->m_Weight = weight; |
| if (bItalic && !FXFT_Is_Face_Italic(face)) { |
| if (italic_angle == 0) |
| italic_angle = -12; |
| else if (abs(italic_angle) < 5) |
| italic_angle = 0; |
| pSubstFont->m_ItalicAngle = italic_angle; |
| } |
| m_pFontInfo->DeleteFont(hFont); |
| return face; |
| } |
| |
| #ifdef PDF_ENABLE_XFA |
| FXFT_Face CFX_FontMapper::FindSubstFontByUnicode(uint32_t dwUnicode, |
| uint32_t flags, |
| int weight, |
| int italic_angle) { |
| if (!m_pFontInfo) |
| return nullptr; |
| |
| bool bItalic = (flags & FXFONT_ITALIC) != 0; |
| int PitchFamily = 0; |
| UpdatePitchFamily(flags, PitchFamily); |
| void* hFont = |
| m_pFontInfo->MapFontByUnicode(dwUnicode, weight, bItalic, PitchFamily); |
| if (!hFont) |
| return nullptr; |
| |
| uint32_t ttc_size = m_pFontInfo->GetFontData(hFont, 0x74746366, nullptr, 0); |
| uint32_t font_size = m_pFontInfo->GetFontData(hFont, 0, nullptr, 0); |
| if (font_size == 0 && ttc_size == 0) { |
| m_pFontInfo->DeleteFont(hFont); |
| return nullptr; |
| } |
| FXFT_Face face = nullptr; |
| if (ttc_size) { |
| face = GetCachedTTCFace(hFont, 0x74746366, ttc_size, font_size); |
| } else { |
| CFX_ByteString SubstName; |
| m_pFontInfo->GetFaceName(hFont, &SubstName); |
| face = GetCachedFace(hFont, SubstName, weight, bItalic, font_size); |
| } |
| m_pFontInfo->DeleteFont(hFont); |
| return face; |
| } |
| #endif // PDF_ENABLE_XFA |
| |
| int CFX_FontMapper::GetFaceSize() const { |
| return pdfium::CollectionSize<int>(m_FaceArray); |
| } |
| |
| bool CFX_FontMapper::IsBuiltinFace(const FXFT_Face face) const { |
| for (size_t i = 0; i < MM_FACE_COUNT; ++i) { |
| if (m_MMFaces[i] == face) |
| return true; |
| } |
| for (size_t i = 0; i < FOXIT_FACE_COUNT; ++i) { |
| if (m_FoxitFaces[i] == face) |
| return true; |
| } |
| return false; |
| } |
| |
| FXFT_Face CFX_FontMapper::GetCachedTTCFace(void* hFont, |
| const uint32_t tableTTCF, |
| uint32_t ttc_size, |
| uint32_t font_size) { |
| FXFT_Face face; |
| uint8_t buffer[1024]; |
| m_pFontInfo->GetFontData(hFont, tableTTCF, buffer, FX_ArraySize(buffer)); |
| uint32_t* pBuffer = reinterpret_cast<uint32_t*>(buffer); |
| uint32_t checksum = 0; |
| for (int i = 0; i < 256; i++) |
| checksum += pBuffer[i]; |
| uint8_t* pFontData; |
| face = m_pFontMgr->GetCachedTTCFace(ttc_size, checksum, ttc_size - font_size, |
| pFontData); |
| if (!face) { |
| pFontData = FX_Alloc(uint8_t, ttc_size); |
| m_pFontInfo->GetFontData(hFont, tableTTCF, pFontData, ttc_size); |
| face = m_pFontMgr->AddCachedTTCFace(ttc_size, checksum, pFontData, ttc_size, |
| ttc_size - font_size); |
| } |
| return face; |
| } |
| |
| FXFT_Face CFX_FontMapper::GetCachedFace(void* hFont, |
| CFX_ByteString SubstName, |
| int weight, |
| bool bItalic, |
| uint32_t font_size) { |
| FXFT_Face face; |
| uint8_t* pFontData; |
| face = m_pFontMgr->GetCachedFace(SubstName, weight, bItalic, pFontData); |
| if (!face) { |
| pFontData = FX_Alloc(uint8_t, font_size); |
| m_pFontInfo->GetFontData(hFont, 0, pFontData, font_size); |
| face = |
| m_pFontMgr->AddCachedFace(SubstName, weight, bItalic, pFontData, |
| font_size, m_pFontInfo->GetFaceIndex(hFont)); |
| } |
| return face; |
| } |
| |
| int PDF_GetStandardFontName(CFX_ByteString* name) { |
| AltFontName* found = static_cast<AltFontName*>( |
| bsearch(name->c_str(), g_AltFontNames, FX_ArraySize(g_AltFontNames), |
| sizeof(AltFontName), CompareString)); |
| if (!found) |
| return -1; |
| |
| *name = g_Base14FontNames[found->m_Index]; |
| return found->m_Index; |
| } |