| // 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/fpdfapi/font/cpdf_truetypefont.h" |
| |
| #include "core/fpdfapi/parser/cpdf_dictionary.h" |
| #include "core/fxge/fx_font.h" |
| #include "third_party/base/cxx17_backports.h" |
| |
| namespace { |
| |
| const uint8_t kPrefix[4] = {0x00, 0xf0, 0xf1, 0xf2}; |
| |
| bool IsWinAnsiOrMacRomanEncoding(int encoding) { |
| return encoding == PDFFONT_ENCODING_WINANSI || |
| encoding == PDFFONT_ENCODING_MACROMAN; |
| } |
| |
| } // namespace |
| |
| CPDF_TrueTypeFont::CPDF_TrueTypeFont(CPDF_Document* pDocument, |
| CPDF_Dictionary* pFontDict) |
| : CPDF_SimpleFont(pDocument, pFontDict) {} |
| |
| CPDF_TrueTypeFont::~CPDF_TrueTypeFont() = default; |
| |
| bool CPDF_TrueTypeFont::IsTrueTypeFont() const { |
| return true; |
| } |
| |
| const CPDF_TrueTypeFont* CPDF_TrueTypeFont::AsTrueTypeFont() const { |
| return this; |
| } |
| |
| CPDF_TrueTypeFont* CPDF_TrueTypeFont::AsTrueTypeFont() { |
| return this; |
| } |
| |
| bool CPDF_TrueTypeFont::Load() { |
| return LoadCommon(); |
| } |
| |
| void CPDF_TrueTypeFont::LoadGlyphMap() { |
| FXFT_FaceRec* face = m_Font.GetFaceRec(); |
| if (!face) |
| return; |
| |
| const int base_encoding = DetermineEncoding(); |
| if ((IsWinAnsiOrMacRomanEncoding(base_encoding) && m_CharNames.empty()) || |
| FontStyleIsNonSymbolic(m_Flags)) { |
| if (!FXFT_Has_Glyph_Names(face) && |
| (!face->num_charmaps || !face->charmaps)) { |
| int nStartChar = m_pFontDict->GetIntegerFor("FirstChar"); |
| if (nStartChar < 0 || nStartChar > 255) |
| return; |
| |
| int charcode = 0; |
| for (; charcode < nStartChar; charcode++) |
| m_GlyphIndex[charcode] = 0; |
| uint16_t nGlyph = charcode - nStartChar + 3; |
| for (; charcode < 256; charcode++, nGlyph++) |
| m_GlyphIndex[charcode] = nGlyph; |
| return; |
| } |
| bool bMSUnicode = FT_UseTTCharmap(face, 3, 1); |
| bool bMacRoman = false; |
| bool bMSSymbol = false; |
| if (!bMSUnicode) { |
| if (FontStyleIsNonSymbolic(m_Flags)) { |
| bMacRoman = FT_UseTTCharmap(face, 1, 0); |
| bMSSymbol = !bMacRoman && FT_UseTTCharmap(face, 3, 0); |
| } else { |
| bMSSymbol = FT_UseTTCharmap(face, 3, 0); |
| bMacRoman = !bMSSymbol && FT_UseTTCharmap(face, 1, 0); |
| } |
| } |
| bool bToUnicode = m_pFontDict->KeyExist("ToUnicode"); |
| for (uint32_t charcode = 0; charcode < 256; charcode++) { |
| const char* name = GetAdobeCharName(base_encoding, m_CharNames, charcode); |
| if (!name) { |
| m_GlyphIndex[charcode] = |
| m_pFontFile ? FT_Get_Char_Index(face, charcode) : -1; |
| continue; |
| } |
| m_Encoding.SetUnicode(charcode, PDF_UnicodeFromAdobeName(name)); |
| if (bMSSymbol) { |
| for (size_t j = 0; j < pdfium::size(kPrefix); j++) { |
| uint16_t unicode = kPrefix[j] * 256 + charcode; |
| m_GlyphIndex[charcode] = FT_Get_Char_Index(face, unicode); |
| if (m_GlyphIndex[charcode]) |
| break; |
| } |
| } else if (m_Encoding.UnicodeFromCharCode(charcode)) { |
| if (bMSUnicode) { |
| m_GlyphIndex[charcode] = |
| FT_Get_Char_Index(face, m_Encoding.UnicodeFromCharCode(charcode)); |
| } else if (bMacRoman) { |
| uint32_t maccode = |
| FT_CharCodeFromUnicode(FT_ENCODING_APPLE_ROMAN, |
| m_Encoding.UnicodeFromCharCode(charcode)); |
| if (!maccode) { |
| m_GlyphIndex[charcode] = FT_Get_Name_Index(face, name); |
| } else { |
| m_GlyphIndex[charcode] = FT_Get_Char_Index(face, maccode); |
| } |
| } |
| } |
| if ((m_GlyphIndex[charcode] != 0 && m_GlyphIndex[charcode] != 0xffff) || |
| !name) { |
| continue; |
| } |
| if (strcmp(name, ".notdef") == 0) { |
| m_GlyphIndex[charcode] = FT_Get_Char_Index(face, 32); |
| continue; |
| } |
| m_GlyphIndex[charcode] = FT_Get_Name_Index(face, name); |
| if (m_GlyphIndex[charcode] != 0 || !bToUnicode) |
| continue; |
| |
| WideString wsUnicode = UnicodeFromCharCode(charcode); |
| if (!wsUnicode.IsEmpty()) { |
| m_GlyphIndex[charcode] = FT_Get_Char_Index(face, wsUnicode[0]); |
| m_Encoding.SetUnicode(charcode, wsUnicode[0]); |
| } |
| } |
| return; |
| } |
| if (FT_UseTTCharmap(face, 3, 0)) { |
| bool bFound = false; |
| for (int charcode = 0; charcode < 256; charcode++) { |
| for (size_t j = 0; j < pdfium::size(kPrefix); j++) { |
| uint16_t unicode = kPrefix[j] * 256 + charcode; |
| m_GlyphIndex[charcode] = FT_Get_Char_Index(face, unicode); |
| if (m_GlyphIndex[charcode]) { |
| bFound = true; |
| break; |
| } |
| } |
| } |
| if (bFound) { |
| if (base_encoding != PDFFONT_ENCODING_BUILTIN) { |
| for (uint32_t charcode = 0; charcode < 256; charcode++) { |
| const char* name = |
| GetAdobeCharName(base_encoding, m_CharNames, charcode); |
| if (name) |
| m_Encoding.SetUnicode(charcode, PDF_UnicodeFromAdobeName(name)); |
| } |
| } else if (FT_UseTTCharmap(face, 1, 0)) { |
| for (int charcode = 0; charcode < 256; charcode++) { |
| m_Encoding.SetUnicode( |
| charcode, |
| FT_UnicodeFromCharCode(FT_ENCODING_APPLE_ROMAN, charcode)); |
| } |
| } |
| return; |
| } |
| } |
| if (FT_UseTTCharmap(face, 1, 0)) { |
| bool bFound = false; |
| for (int charcode = 0; charcode < 256; charcode++) { |
| m_GlyphIndex[charcode] = FT_Get_Char_Index(face, charcode); |
| m_Encoding.SetUnicode( |
| charcode, FT_UnicodeFromCharCode(FT_ENCODING_APPLE_ROMAN, charcode)); |
| if (m_GlyphIndex[charcode]) { |
| bFound = true; |
| } |
| } |
| if (m_pFontFile || bFound) |
| return; |
| } |
| if (FXFT_Select_Charmap(face, FT_ENCODING_UNICODE) == 0) { |
| bool bFound = false; |
| const uint16_t* pUnicodes = PDF_UnicodesForPredefinedCharSet(base_encoding); |
| for (uint32_t charcode = 0; charcode < 256; charcode++) { |
| if (m_pFontFile) { |
| m_Encoding.SetUnicode(charcode, charcode); |
| } else { |
| const char* name = GetAdobeCharName(0, m_CharNames, charcode); |
| if (name) |
| m_Encoding.SetUnicode(charcode, PDF_UnicodeFromAdobeName(name)); |
| else if (pUnicodes) |
| m_Encoding.SetUnicode(charcode, pUnicodes[charcode]); |
| } |
| m_GlyphIndex[charcode] = |
| FT_Get_Char_Index(face, m_Encoding.UnicodeFromCharCode(charcode)); |
| if (m_GlyphIndex[charcode]) |
| bFound = true; |
| } |
| if (bFound) |
| return; |
| } |
| for (int charcode = 0; charcode < 256; charcode++) |
| m_GlyphIndex[charcode] = charcode; |
| } |
| |
| int CPDF_TrueTypeFont::DetermineEncoding() const { |
| if (!m_pFontFile || !FontStyleIsSymbolic(m_Flags) || |
| !IsWinAnsiOrMacRomanEncoding(m_BaseEncoding)) { |
| return m_BaseEncoding; |
| } |
| |
| // Not null - caller checked. |
| FXFT_FaceRec* face = m_Font.GetFaceRec(); |
| if (face->num_charmaps <= 0) |
| return m_BaseEncoding; |
| |
| bool support_win = false; |
| bool support_mac = false; |
| for (int i = 0; i < face->num_charmaps; i++) { |
| int platform_id = FXFT_Get_Charmap_PlatformID(face->charmaps[i]); |
| if (platform_id == kNamePlatformAppleUnicode || |
| platform_id == kNamePlatformWindows) { |
| support_win = true; |
| } else if (platform_id == kNamePlatformMac) { |
| support_mac = true; |
| } |
| if (support_win && support_mac) |
| break; |
| } |
| |
| if (m_BaseEncoding == PDFFONT_ENCODING_WINANSI && !support_win) |
| return support_mac ? PDFFONT_ENCODING_MACROMAN : PDFFONT_ENCODING_BUILTIN; |
| if (m_BaseEncoding == PDFFONT_ENCODING_MACROMAN && !support_mac) |
| return support_win ? PDFFONT_ENCODING_WINANSI : PDFFONT_ENCODING_BUILTIN; |
| return m_BaseEncoding; |
| } |