// Copyright 2014 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/fpdfdoc/cba_fontmap.h" #include #include #include "constants/annotation_common.h" #include "core/fpdfapi/font/cpdf_font.h" #include "core/fpdfapi/font/cpdf_fontencoding.h" #include "core/fpdfapi/page/cpdf_docpagedata.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_parser.h" #include "core/fpdfapi/parser/cpdf_reference.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/parser/fpdf_parser_utility.h" #include "core/fpdfdoc/cpdf_defaultappearance.h" #include "core/fpdfdoc/cpdf_formfield.h" #include "core/fpdfdoc/ipvt_fontmap.h" #include "core/fxcrt/fx_codepage.h" #include "core/fxge/cfx_fontmapper.h" #include "core/fxge/cfx_fontmgr.h" #include "core/fxge/cfx_gemodule.h" #include "core/fxge/cfx_substfont.h" #include "third_party/base/ptr_util.h" #include "third_party/base/stl_util.h" namespace { bool FindNativeTrueTypeFont(ByteString sFontFaceName) { CFX_FontMgr* pFontMgr = CFX_GEModule::Get()->GetFontMgr(); if (!pFontMgr) return false; CFX_FontMapper* pFontMapper = pFontMgr->GetBuiltinMapper(); pFontMapper->LoadInstalledFonts(); for (const auto& font : pFontMapper->m_InstalledTTFonts) { if (font.Compare(sFontFaceName.AsStringView())) return true; } for (const auto& fontPair : pFontMapper->m_LocalizedTTFonts) { if (fontPair.first.Compare(sFontFaceName.AsStringView())) return true; } return false; } RetainPtr AddNativeTrueTypeFontToPDF(CPDF_Document* pDoc, ByteString sFontFaceName, uint8_t nCharset) { if (!pDoc) return nullptr; auto pFXFont = pdfium::MakeUnique(); pFXFont->LoadSubst(sFontFaceName, true, 0, 0, 0, FX_GetCodePageFromCharset(nCharset), false); auto* pDocPageData = CPDF_DocPageData::FromDocument(pDoc); return pDocPageData->AddFont(std::move(pFXFont), nCharset); } } // namespace CBA_FontMap::Data::Data() = default; CBA_FontMap::Data::~Data() = default; CBA_FontMap::CBA_FontMap(CPDF_Document* pDocument, CPDF_Dictionary* pAnnotDict) : m_pDocument(pDocument), m_pAnnotDict(pAnnotDict) { Initialize(); } CBA_FontMap::~CBA_FontMap() { Clear(); } RetainPtr CBA_FontMap::GetPDFFont(int32_t nFontIndex) { if (pdfium::IndexInBounds(m_Data, nFontIndex)) return m_Data[nFontIndex]->pFont; return nullptr; } ByteString CBA_FontMap::GetPDFFontAlias(int32_t nFontIndex) { if (pdfium::IndexInBounds(m_Data, nFontIndex)) return m_Data[nFontIndex]->sFontName; return ByteString(); } int32_t CBA_FontMap::GetWordFontIndex(uint16_t word, int32_t nCharset, int32_t nFontIndex) { if (nFontIndex > 0) { if (KnowWord(nFontIndex, word)) return nFontIndex; } else { if (!m_Data.empty()) { const Data* pData = m_Data.front().get(); if (nCharset == FX_CHARSET_Default || pData->nCharset == FX_CHARSET_Symbol || nCharset == pData->nCharset) { if (KnowWord(0, word)) return 0; } } } int32_t nNewFontIndex = GetFontIndex(GetCachedNativeFontName(nCharset), nCharset, true); if (nNewFontIndex >= 0) { if (KnowWord(nNewFontIndex, word)) return nNewFontIndex; } nNewFontIndex = GetFontIndex(CFX_Font::kUniversalDefaultFontName, FX_CHARSET_Default, false); if (nNewFontIndex >= 0) { if (KnowWord(nNewFontIndex, word)) return nNewFontIndex; } return -1; } int32_t CBA_FontMap::CharCodeFromUnicode(int32_t nFontIndex, uint16_t word) { if (!pdfium::IndexInBounds(m_Data, nFontIndex)) return -1; Data* pData = m_Data[nFontIndex].get(); if (!pData->pFont) return -1; if (pData->pFont->IsUnicodeCompatible()) return pData->pFont->CharCodeFromUnicode(word); return word < 0xFF ? word : -1; } int32_t CBA_FontMap::CharSetFromUnicode(uint16_t word, int32_t nOldCharset) { // to avoid CJK Font to show ASCII if (word < 0x7F) return FX_CHARSET_ANSI; // follow the old charset if (nOldCharset != FX_CHARSET_Default) return nOldCharset; return CFX_Font::GetCharSetFromUnicode(word); } int32_t CBA_FontMap::GetNativeCharset() { return FX_GetCharsetFromCodePage(FXSYS_GetACP()); } void CBA_FontMap::Reset() { Clear(); m_pDefaultFont = nullptr; m_sDefaultFontName.clear(); } void CBA_FontMap::SetAPType(const ByteString& sAPType) { m_sAPType = sAPType; Reset(); Initialize(); } void CBA_FontMap::Initialize() { int32_t nCharset = FX_CHARSET_Default; if (!m_pDefaultFont) { m_pDefaultFont = GetAnnotDefaultFont(&m_sDefaultFontName); if (m_pDefaultFont) { if (const CFX_SubstFont* pSubstFont = m_pDefaultFont->GetSubstFont()) { nCharset = pSubstFont->m_Charset; } else { if (m_sDefaultFontName == "Wingdings" || m_sDefaultFontName == "Wingdings2" || m_sDefaultFontName == "Wingdings3" || m_sDefaultFontName == "Webdings") nCharset = FX_CHARSET_Symbol; else nCharset = FX_CHARSET_ANSI; } AddFontData(m_pDefaultFont, m_sDefaultFontName, nCharset); AddFontToAnnotDict(m_pDefaultFont, m_sDefaultFontName); } } if (nCharset != FX_CHARSET_ANSI) GetFontIndex(CFX_Font::kDefaultAnsiFontName, FX_CHARSET_ANSI, false); } RetainPtr CBA_FontMap::FindFontSameCharset(ByteString* sFontAlias, int32_t nCharset) { if (m_pAnnotDict->GetStringFor(pdfium::annotation::kSubtype) != "Widget") return nullptr; const CPDF_Dictionary* pRootDict = m_pDocument->GetRoot(); if (!pRootDict) return nullptr; const CPDF_Dictionary* pAcroFormDict = pRootDict->GetDictFor("AcroForm"); if (!pAcroFormDict) return nullptr; const CPDF_Dictionary* pDRDict = pAcroFormDict->GetDictFor("DR"); if (!pDRDict) return nullptr; return FindResFontSameCharset(pDRDict, sFontAlias, nCharset); } RetainPtr CBA_FontMap::FindResFontSameCharset( const CPDF_Dictionary* pResDict, ByteString* sFontAlias, int32_t nCharset) { if (!pResDict) return nullptr; const CPDF_Dictionary* pFonts = pResDict->GetDictFor("Font"); if (!pFonts) return nullptr; RetainPtr pFind; CPDF_DictionaryLocker locker(pFonts); for (const auto& it : locker) { const ByteString& csKey = it.first; if (!it.second) continue; CPDF_Dictionary* pElement = ToDictionary(it.second->GetDirect()); if (!pElement || pElement->GetStringFor("Type") != "Font") continue; auto* pData = CPDF_DocPageData::FromDocument(m_pDocument.Get()); RetainPtr pFont = pData->GetFont(pElement); if (!pFont) continue; const CFX_SubstFont* pSubst = pFont->GetSubstFont(); if (!pSubst) continue; if (pSubst->m_Charset == nCharset) { *sFontAlias = csKey; pFind = std::move(pFont); } } return pFind; } RetainPtr CBA_FontMap::GetAnnotDefaultFont(ByteString* sAlias) { CPDF_Dictionary* pAcroFormDict = nullptr; const bool bWidget = (m_pAnnotDict->GetStringFor(pdfium::annotation::kSubtype) == "Widget"); if (bWidget) { CPDF_Dictionary* pRootDict = m_pDocument->GetRoot(); if (pRootDict) pAcroFormDict = pRootDict->GetDictFor("AcroForm"); } ByteString sDA; const CPDF_Object* pObj = CPDF_FormField::GetFieldAttr(m_pAnnotDict.Get(), "DA"); if (pObj) sDA = pObj->GetString(); if (bWidget) { if (sDA.IsEmpty()) { pObj = CPDF_FormField::GetFieldAttr(pAcroFormDict, "DA"); sDA = pObj ? pObj->GetString() : ByteString(); } } if (sDA.IsEmpty()) return nullptr; CPDF_DefaultAppearance appearance(sDA); float font_size; Optional font = appearance.GetFont(&font_size); *sAlias = font.value_or(ByteString()); CPDF_Dictionary* pFontDict = nullptr; if (CPDF_Dictionary* pAPDict = m_pAnnotDict->GetDictFor(pdfium::annotation::kAP)) { if (CPDF_Dictionary* pNormalDict = pAPDict->GetDictFor("N")) { if (CPDF_Dictionary* pNormalResDict = pNormalDict->GetDictFor("Resources")) { if (CPDF_Dictionary* pResFontDict = pNormalResDict->GetDictFor("Font")) pFontDict = pResFontDict->GetDictFor(*sAlias); } } } if (bWidget && !pFontDict && pAcroFormDict) { if (CPDF_Dictionary* pDRDict = pAcroFormDict->GetDictFor("DR")) { if (CPDF_Dictionary* pDRFontDict = pDRDict->GetDictFor("Font")) pFontDict = pDRFontDict->GetDictFor(*sAlias); } } if (!pFontDict) return nullptr; return CPDF_DocPageData::FromDocument(m_pDocument.Get())->GetFont(pFontDict); } void CBA_FontMap::AddFontToAnnotDict(const RetainPtr& pFont, const ByteString& sAlias) { if (!pFont) return; CPDF_Dictionary* pAPDict = m_pAnnotDict->GetDictFor(pdfium::annotation::kAP); if (!pAPDict) pAPDict = m_pAnnotDict->SetNewFor(pdfium::annotation::kAP); // to avoid checkbox and radiobutton if (ToDictionary(pAPDict->GetObjectFor(m_sAPType))) return; CPDF_Stream* pStream = pAPDict->GetStreamFor(m_sAPType); if (!pStream) { pStream = m_pDocument->NewIndirect(); pAPDict->SetNewFor(m_sAPType, m_pDocument.Get(), pStream->GetObjNum()); } CPDF_Dictionary* pStreamDict = pStream->GetDict(); if (!pStreamDict) { auto pOwnedDict = m_pDocument->New(); pStreamDict = pOwnedDict.Get(); pStream->InitStream({}, std::move(pOwnedDict)); } CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources"); if (!pStreamResList) pStreamResList = pStreamDict->SetNewFor("Resources"); CPDF_Dictionary* pStreamResFontList = pStreamResList->GetDictFor("Font"); if (!pStreamResFontList) { pStreamResFontList = m_pDocument->NewIndirect(); pStreamResList->SetNewFor("Font", m_pDocument.Get(), pStreamResFontList->GetObjNum()); } if (!pStreamResFontList->KeyExist(sAlias)) { CPDF_Dictionary* pFontDict = pFont->GetFontDict(); RetainPtr pObject = pFontDict->IsInline() ? pFontDict->Clone() : pFontDict->MakeReference(m_pDocument.Get()); pStreamResFontList->SetFor(sAlias, std::move(pObject)); } } bool CBA_FontMap::KnowWord(int32_t nFontIndex, uint16_t word) { return pdfium::IndexInBounds(m_Data, nFontIndex) && CharCodeFromUnicode(nFontIndex, word) >= 0; } void CBA_FontMap::Clear() { m_Data.clear(); m_NativeFont.clear(); } int32_t CBA_FontMap::GetFontIndex(const ByteString& sFontName, int32_t nCharset, bool bFind) { int32_t nFontIndex = FindFont(EncodeFontAlias(sFontName, nCharset), nCharset); if (nFontIndex >= 0) return nFontIndex; ByteString sAlias; RetainPtr pFont = bFind ? FindFontSameCharset(&sAlias, nCharset) : nullptr; if (!pFont) { ByteString sTemp = sFontName; pFont = AddFontToDocument(sTemp, nCharset); sAlias = EncodeFontAlias(sTemp, nCharset); } AddFontToAnnotDict(pFont, sAlias); return AddFontData(pFont, sAlias, nCharset); } int32_t CBA_FontMap::AddFontData(const RetainPtr& pFont, const ByteString& sFontAlias, int32_t nCharset) { auto pNewData = pdfium::MakeUnique(); pNewData->pFont = pFont; pNewData->sFontName = sFontAlias; pNewData->nCharset = nCharset; m_Data.push_back(std::move(pNewData)); return pdfium::CollectionSize(m_Data) - 1; } ByteString CBA_FontMap::EncodeFontAlias(const ByteString& sFontName, int32_t nCharset) { return EncodeFontAlias(sFontName) + ByteString::Format("_%02X", nCharset); } ByteString CBA_FontMap::EncodeFontAlias(const ByteString& sFontName) { ByteString sRet = sFontName; sRet.Remove(' '); return sRet; } int32_t CBA_FontMap::FindFont(const ByteString& sFontName, int32_t nCharset) { int32_t i = 0; for (const auto& pData : m_Data) { if ((nCharset == FX_CHARSET_Default || nCharset == pData->nCharset) && (sFontName.IsEmpty() || pData->sFontName == sFontName)) { return i; } ++i; } return -1; } ByteString CBA_FontMap::GetNativeFontName(int32_t nCharset) { if (nCharset == FX_CHARSET_Default) nCharset = GetNativeCharset(); ByteString sFontName = CFX_Font::GetDefaultFontNameByCharset(nCharset); if (!FindNativeTrueTypeFont(sFontName)) return ByteString(); return sFontName; } ByteString CBA_FontMap::GetCachedNativeFontName(int32_t nCharset) { for (const auto& pData : m_NativeFont) { if (pData && pData->nCharset == nCharset) return pData->sFontName; } ByteString sNew = GetNativeFontName(nCharset); if (sNew.IsEmpty()) return ByteString(); auto pNewData = pdfium::MakeUnique(); pNewData->nCharset = nCharset; pNewData->sFontName = sNew; m_NativeFont.push_back(std::move(pNewData)); return sNew; } RetainPtr CBA_FontMap::AddFontToDocument(ByteString sFontName, uint8_t nCharset) { if (IsStandardFont(sFontName)) return AddStandardFont(sFontName); return AddSystemFont(sFontName, nCharset); } bool CBA_FontMap::IsStandardFont(const ByteString& sFontName) { static const char* const kStandardFontNames[] = {"Courier", "Courier-Bold", "Courier-BoldOblique", "Courier-Oblique", "Helvetica", "Helvetica-Bold", "Helvetica-BoldOblique", "Helvetica-Oblique", "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic", "Symbol", "ZapfDingbats"}; for (const char* name : kStandardFontNames) { if (sFontName == name) return true; } return false; } RetainPtr CBA_FontMap::AddStandardFont(ByteString sFontName) { auto* pPageData = CPDF_DocPageData::FromDocument(m_pDocument.Get()); if (sFontName == "ZapfDingbats") return pPageData->AddStandardFont(sFontName, nullptr); static const CPDF_FontEncoding fe(PDFFONT_ENCODING_WINANSI); return pPageData->AddStandardFont(sFontName, &fe); } RetainPtr CBA_FontMap::AddSystemFont(ByteString sFontName, uint8_t nCharset) { if (sFontName.IsEmpty()) sFontName = GetNativeFontName(nCharset); if (nCharset == FX_CHARSET_Default) nCharset = GetNativeCharset(); return AddNativeTrueTypeFontToPDF(m_pDocument.Get(), sFontName, nCharset); }