// 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 <algorithm> #include <vector> #include "core/fpdfapi/fpdf_font/include/cpdf_font.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_document.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_simple_parser.h" #include "core/fpdfdoc/doc_utils.h" #include "core/fpdfdoc/include/fpdf_doc.h" #include "core/fxge/include/fx_font.h" namespace { const int FPDFDOC_UTILS_MAXRECURSION = 32; CPDF_Object* SearchNumberNode(const CPDF_Dictionary* pNode, int num) { CPDF_Array* pLimits = pNode->GetArrayBy("Limits"); if (pLimits && (num < pLimits->GetIntegerAt(0) || num > pLimits->GetIntegerAt(1))) { return NULL; } CPDF_Array* pNumbers = pNode->GetArrayBy("Nums"); if (pNumbers) { uint32_t dwCount = pNumbers->GetCount() / 2; for (uint32_t i = 0; i < dwCount; i++) { int index = pNumbers->GetIntegerAt(i * 2); if (num == index) { return pNumbers->GetDirectObjectAt(i * 2 + 1); } if (index > num) { break; } } return NULL; } CPDF_Array* pKids = pNode->GetArrayBy("Kids"); if (!pKids) { return NULL; } for (uint32_t i = 0; i < pKids->GetCount(); i++) { CPDF_Dictionary* pKid = pKids->GetDictAt(i); if (!pKid) { continue; } CPDF_Object* pFound = SearchNumberNode(pKid, num); if (pFound) { return pFound; } } return NULL; } } // namespace CPDF_Object* CPDF_NumberTree::LookupValue(int num) const { return SearchNumberNode(m_pRoot, num); } CFX_WideString GetFullName(CPDF_Dictionary* pFieldDict) { CFX_WideString full_name; CPDF_Dictionary* pLevel = pFieldDict; while (pLevel) { CFX_WideString short_name = pLevel->GetUnicodeTextBy("T"); if (short_name != L"") { if (full_name == L"") { full_name = short_name; } else { full_name = short_name + L"." + full_name; } } pLevel = pLevel->GetDictBy("Parent"); } return full_name; } FX_BOOL CPDF_DefaultAppearance::HasFont() { if (m_csDA.IsEmpty()) { return FALSE; } CPDF_SimpleParser syntax(m_csDA.AsByteStringC()); return syntax.FindTagParamFromStart("Tf", 2); } CFX_ByteString CPDF_DefaultAppearance::GetFontString() { CFX_ByteString csFont; if (m_csDA.IsEmpty()) { return csFont; } CPDF_SimpleParser syntax(m_csDA.AsByteStringC()); if (syntax.FindTagParamFromStart("Tf", 2)) { csFont += (CFX_ByteString)syntax.GetWord(); csFont += " "; csFont += (CFX_ByteString)syntax.GetWord(); csFont += " "; csFont += (CFX_ByteString)syntax.GetWord(); } return csFont; } void CPDF_DefaultAppearance::GetFont(CFX_ByteString& csFontNameTag, FX_FLOAT& fFontSize) { csFontNameTag = ""; fFontSize = 0; if (m_csDA.IsEmpty()) { return; } CPDF_SimpleParser syntax(m_csDA.AsByteStringC()); if (syntax.FindTagParamFromStart("Tf", 2)) { csFontNameTag = CFX_ByteString(syntax.GetWord()); csFontNameTag.Delete(0, 1); fFontSize = FX_atof(syntax.GetWord()); } csFontNameTag = PDF_NameDecode(csFontNameTag); } FX_BOOL CPDF_DefaultAppearance::HasColor(FX_BOOL bStrokingOperation) { if (m_csDA.IsEmpty()) { return FALSE; } CPDF_SimpleParser syntax(m_csDA.AsByteStringC()); if (syntax.FindTagParamFromStart(bStrokingOperation ? "G" : "g", 1)) { return TRUE; } if (syntax.FindTagParamFromStart(bStrokingOperation ? "RG" : "rg", 3)) { return TRUE; } return syntax.FindTagParamFromStart(bStrokingOperation ? "K" : "k", 4); } CFX_ByteString CPDF_DefaultAppearance::GetColorString( FX_BOOL bStrokingOperation) { CFX_ByteString csColor; if (m_csDA.IsEmpty()) { return csColor; } CPDF_SimpleParser syntax(m_csDA.AsByteStringC()); if (syntax.FindTagParamFromStart(bStrokingOperation ? "G" : "g", 1)) { csColor += (CFX_ByteString)syntax.GetWord(); csColor += " "; csColor += (CFX_ByteString)syntax.GetWord(); return csColor; } if (syntax.FindTagParamFromStart(bStrokingOperation ? "RG" : "rg", 3)) { csColor += (CFX_ByteString)syntax.GetWord(); csColor += " "; csColor += (CFX_ByteString)syntax.GetWord(); csColor += " "; csColor += (CFX_ByteString)syntax.GetWord(); csColor += " "; csColor += (CFX_ByteString)syntax.GetWord(); return csColor; } if (syntax.FindTagParamFromStart(bStrokingOperation ? "K" : "k", 4)) { csColor += (CFX_ByteString)syntax.GetWord(); csColor += " "; csColor += (CFX_ByteString)syntax.GetWord(); csColor += " "; csColor += (CFX_ByteString)syntax.GetWord(); csColor += " "; csColor += (CFX_ByteString)syntax.GetWord(); csColor += " "; csColor += (CFX_ByteString)syntax.GetWord(); } return csColor; } void CPDF_DefaultAppearance::GetColor(int& iColorType, FX_FLOAT fc[4], FX_BOOL bStrokingOperation) { iColorType = COLORTYPE_TRANSPARENT; for (int c = 0; c < 4; c++) { fc[c] = 0; } if (m_csDA.IsEmpty()) { return; } CPDF_SimpleParser syntax(m_csDA.AsByteStringC()); if (syntax.FindTagParamFromStart(bStrokingOperation ? "G" : "g", 1)) { iColorType = COLORTYPE_GRAY; fc[0] = FX_atof(syntax.GetWord()); return; } if (syntax.FindTagParamFromStart(bStrokingOperation ? "RG" : "rg", 3)) { iColorType = COLORTYPE_RGB; fc[0] = FX_atof(syntax.GetWord()); fc[1] = FX_atof(syntax.GetWord()); fc[2] = FX_atof(syntax.GetWord()); return; } if (syntax.FindTagParamFromStart(bStrokingOperation ? "K" : "k", 4)) { iColorType = COLORTYPE_CMYK; fc[0] = FX_atof(syntax.GetWord()); fc[1] = FX_atof(syntax.GetWord()); fc[2] = FX_atof(syntax.GetWord()); fc[3] = FX_atof(syntax.GetWord()); } } void CPDF_DefaultAppearance::GetColor(FX_ARGB& color, int& iColorType, FX_BOOL bStrokingOperation) { color = 0; iColorType = COLORTYPE_TRANSPARENT; if (m_csDA.IsEmpty()) { return; } CPDF_SimpleParser syntax(m_csDA.AsByteStringC()); if (syntax.FindTagParamFromStart(bStrokingOperation ? "G" : "g", 1)) { iColorType = COLORTYPE_GRAY; FX_FLOAT g = FX_atof(syntax.GetWord()) * 255 + 0.5f; color = ArgbEncode(255, (int)g, (int)g, (int)g); return; } if (syntax.FindTagParamFromStart(bStrokingOperation ? "RG" : "rg", 3)) { iColorType = COLORTYPE_RGB; FX_FLOAT r = FX_atof(syntax.GetWord()) * 255 + 0.5f; FX_FLOAT g = FX_atof(syntax.GetWord()) * 255 + 0.5f; FX_FLOAT b = FX_atof(syntax.GetWord()) * 255 + 0.5f; color = ArgbEncode(255, (int)r, (int)g, (int)b); return; } if (syntax.FindTagParamFromStart(bStrokingOperation ? "K" : "k", 4)) { iColorType = COLORTYPE_CMYK; FX_FLOAT c = FX_atof(syntax.GetWord()); FX_FLOAT m = FX_atof(syntax.GetWord()); FX_FLOAT y = FX_atof(syntax.GetWord()); FX_FLOAT k = FX_atof(syntax.GetWord()); FX_FLOAT r = 1.0f - std::min(1.0f, c + k); FX_FLOAT g = 1.0f - std::min(1.0f, m + k); FX_FLOAT b = 1.0f - std::min(1.0f, y + k); color = ArgbEncode(255, (int)(r * 255 + 0.5f), (int)(g * 255 + 0.5f), (int)(b * 255 + 0.5f)); } } FX_BOOL CPDF_DefaultAppearance::HasTextMatrix() { if (m_csDA.IsEmpty()) { return FALSE; } CPDF_SimpleParser syntax(m_csDA.AsByteStringC()); return syntax.FindTagParamFromStart("Tm", 6); } CFX_ByteString CPDF_DefaultAppearance::GetTextMatrixString() { CFX_ByteString csTM; if (m_csDA.IsEmpty()) { return csTM; } CPDF_SimpleParser syntax(m_csDA.AsByteStringC()); if (syntax.FindTagParamFromStart("Tm", 6)) { for (int i = 0; i < 6; i++) { csTM += (CFX_ByteString)syntax.GetWord(); csTM += " "; } csTM += (CFX_ByteString)syntax.GetWord(); } return csTM; } CFX_Matrix CPDF_DefaultAppearance::GetTextMatrix() { CFX_Matrix tm; if (m_csDA.IsEmpty()) { return tm; } CPDF_SimpleParser syntax(m_csDA.AsByteStringC()); if (syntax.FindTagParamFromStart("Tm", 6)) { FX_FLOAT f[6]; for (int i = 0; i < 6; i++) { f[i] = FX_atof(syntax.GetWord()); } tm.Set(f[0], f[1], f[2], f[3], f[4], f[5]); } return tm; } void InitInterFormDict(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument) { if (!pDocument) { return; } if (!pFormDict) { pFormDict = new CPDF_Dictionary; uint32_t dwObjNum = pDocument->AddIndirectObject(pFormDict); CPDF_Dictionary* pRoot = pDocument->GetRoot(); pRoot->SetAtReference("AcroForm", pDocument, dwObjNum); } CFX_ByteString csDA; if (!pFormDict->KeyExist("DR")) { CPDF_Font* pFont = NULL; CFX_ByteString csBaseName, csDefault; uint8_t charSet = CPDF_InterForm::GetNativeCharSet(); pFont = CPDF_InterForm::AddStandardFont(pDocument, "Helvetica"); if (pFont) { AddInterFormFont(pFormDict, pDocument, pFont, csBaseName); csDefault = csBaseName; } if (charSet != 0) { CFX_ByteString csFontName = CPDF_InterForm::GetNativeFont(charSet, NULL); if (!pFont || csFontName != "Helvetica") { pFont = CPDF_InterForm::AddNativeFont(pDocument); if (pFont) { csBaseName = ""; AddInterFormFont(pFormDict, pDocument, pFont, csBaseName); csDefault = csBaseName; } } } if (pFont) { csDA = "/" + PDF_NameEncode(csDefault) + " 0 Tf"; } } if (!csDA.IsEmpty()) { csDA += " "; } csDA += "0 g"; if (!pFormDict->KeyExist("DA")) { pFormDict->SetAtString("DA", csDA); } } uint32_t CountInterFormFonts(CPDF_Dictionary* pFormDict) { if (!pFormDict) { return 0; } CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); if (!pDR) { return 0; } CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); if (!pFonts) { return 0; } uint32_t dwCount = 0; for (const auto& it : *pFonts) { CPDF_Object* pObj = it.second; if (!pObj) { continue; } if (CPDF_Dictionary* pDirect = ToDictionary(pObj->GetDirect())) { if (pDirect->GetStringBy("Type") == "Font") { dwCount++; } } } return dwCount; } CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, uint32_t index, CFX_ByteString& csNameTag) { if (!pFormDict) { return NULL; } CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); if (!pDR) { return NULL; } CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); if (!pFonts) { return NULL; } uint32_t dwCount = 0; for (const auto& it : *pFonts) { const CFX_ByteString& csKey = it.first; CPDF_Object* pObj = it.second; if (!pObj) { continue; } CPDF_Dictionary* pElement = ToDictionary(pObj->GetDirect()); if (!pElement) continue; if (pElement->GetStringBy("Type") != "Font") continue; if (dwCount == index) { csNameTag = csKey; return pDocument->LoadFont(pElement); } dwCount++; } return NULL; } CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, CFX_ByteString csNameTag) { CFX_ByteString csAlias = PDF_NameDecode(csNameTag); if (!pFormDict || csAlias.IsEmpty()) { return NULL; } CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); if (!pDR) { return NULL; } CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); if (!pFonts) { return NULL; } CPDF_Dictionary* pElement = pFonts->GetDictBy(csAlias.AsByteStringC()); if (!pElement) { return NULL; } if (pElement->GetStringBy("Type") == "Font") { return pDocument->LoadFont(pElement); } return NULL; } CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, CFX_ByteString csFontName, CFX_ByteString& csNameTag) { if (!pFormDict || csFontName.IsEmpty()) { return NULL; } CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); if (!pDR) { return NULL; } CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); if (!pFonts) { return NULL; } for (const auto& it : *pFonts) { const CFX_ByteString& csKey = it.first; CPDF_Object* pObj = it.second; if (!pObj) { continue; } CPDF_Dictionary* pElement = ToDictionary(pObj->GetDirect()); if (!pElement) continue; if (pElement->GetStringBy("Type") != "Font") continue; CPDF_Font* pFind = pDocument->LoadFont(pElement); if (!pFind) continue; CFX_ByteString csBaseFont; csBaseFont = pFind->GetBaseFont(); csBaseFont.Remove(' '); if (csBaseFont == csFontName) { csNameTag = csKey; return pFind; } } return NULL; } CPDF_Font* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, uint8_t charSet, CFX_ByteString& csNameTag) { if (!pFormDict) { return NULL; } CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); if (!pDR) { return NULL; } CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); if (!pFonts) { return NULL; } for (const auto& it : *pFonts) { const CFX_ByteString& csKey = it.first; CPDF_Object* pObj = it.second; if (!pObj) { continue; } CPDF_Dictionary* pElement = ToDictionary(pObj->GetDirect()); if (!pElement) continue; if (pElement->GetStringBy("Type") != "Font") continue; CPDF_Font* pFind = pDocument->LoadFont(pElement); if (!pFind) { continue; } CFX_SubstFont* pSubst = (CFX_SubstFont*)pFind->GetSubstFont(); if (!pSubst) { continue; } if (pSubst->m_Charset == (int)charSet) { csNameTag = csKey; return pFind; } } return NULL; } CPDF_Font* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, CFX_ByteString& csNameTag) { csNameTag = ""; uint8_t charSet = CPDF_InterForm::GetNativeCharSet(); CFX_SubstFont* pSubst; CPDF_Font* pFont = GetDefaultInterFormFont(pFormDict, pDocument); if (pFont) { pSubst = (CFX_SubstFont*)pFont->GetSubstFont(); if (pSubst && pSubst->m_Charset == (int)charSet) { FindInterFormFont(pFormDict, pFont, csNameTag); return pFont; } } return GetNativeInterFormFont(pFormDict, pDocument, charSet, csNameTag); } FX_BOOL FindInterFormFont(CPDF_Dictionary* pFormDict, const CPDF_Font* pFont, CFX_ByteString& csNameTag) { if (!pFormDict || !pFont) { return FALSE; } CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); if (!pDR) { return FALSE; } CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); if (!pFonts) { return FALSE; } for (const auto& it : *pFonts) { const CFX_ByteString& csKey = it.first; CPDF_Object* pObj = it.second; if (!pObj) { continue; } CPDF_Dictionary* pElement = ToDictionary(pObj->GetDirect()); if (!pElement) continue; if (pElement->GetStringBy("Type") != "Font") { continue; } if (pFont->GetFontDict() == pElement) { csNameTag = csKey; return TRUE; } } return FALSE; } FX_BOOL FindInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument, CFX_ByteString csFontName, CPDF_Font*& pFont, CFX_ByteString& csNameTag) { if (!pFormDict) { return FALSE; } CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); if (!pDR) { return FALSE; } CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); if (!pFonts) { return FALSE; } if (csFontName.GetLength() > 0) { csFontName.Remove(' '); } for (const auto& it : *pFonts) { const CFX_ByteString& csKey = it.first; CPDF_Object* pObj = it.second; if (!pObj) { continue; } CPDF_Dictionary* pElement = ToDictionary(pObj->GetDirect()); if (!pElement) continue; if (pElement->GetStringBy("Type") != "Font") { continue; } pFont = pDocument->LoadFont(pElement); if (!pFont) { continue; } CFX_ByteString csBaseFont; csBaseFont = pFont->GetBaseFont(); csBaseFont.Remove(' '); if (csBaseFont == csFontName) { csNameTag = csKey; return TRUE; } } return FALSE; } void AddInterFormFont(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument, const CPDF_Font* pFont, CFX_ByteString& csNameTag) { if (!pFont) { return; } if (!pFormDict) { InitInterFormDict(pFormDict, pDocument); } CFX_ByteString csTag; if (FindInterFormFont(pFormDict, pFont, csTag)) { csNameTag = csTag; return; } if (!pFormDict) { InitInterFormDict(pFormDict, pDocument); } CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); if (!pDR) { pDR = new CPDF_Dictionary; pFormDict->SetAt("DR", pDR); } CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); if (!pFonts) { pFonts = new CPDF_Dictionary; pDR->SetAt("Font", pFonts); } if (csNameTag.IsEmpty()) { csNameTag = pFont->GetBaseFont(); } csNameTag.Remove(' '); csNameTag = CPDF_InterForm::GenerateNewResourceName(pDR, "Font", 4, csNameTag); pFonts->SetAtReference(csNameTag.AsByteStringC(), pDocument, pFont->GetFontDict()); } CPDF_Font* AddNativeInterFormFont(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument, uint8_t charSet, CFX_ByteString& csNameTag) { if (!pFormDict) { InitInterFormDict(pFormDict, pDocument); } CFX_ByteString csTemp; CPDF_Font* pFont = GetNativeInterFormFont(pFormDict, pDocument, charSet, csTemp); if (pFont) { csNameTag = csTemp; return pFont; } CFX_ByteString csFontName = CPDF_InterForm::GetNativeFont(charSet); if (!csFontName.IsEmpty()) { if (FindInterFormFont(pFormDict, pDocument, csFontName, pFont, csNameTag)) { return pFont; } } pFont = CPDF_InterForm::AddNativeFont(charSet, pDocument); if (pFont) { AddInterFormFont(pFormDict, pDocument, pFont, csNameTag); } return pFont; } CPDF_Font* AddNativeInterFormFont(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument, CFX_ByteString& csNameTag) { uint8_t charSet = CPDF_InterForm::GetNativeCharSet(); return AddNativeInterFormFont(pFormDict, pDocument, charSet, csNameTag); } void RemoveInterFormFont(CPDF_Dictionary* pFormDict, const CPDF_Font* pFont) { if (!pFormDict || !pFont) { return; } CFX_ByteString csTag; if (!FindInterFormFont(pFormDict, pFont, csTag)) { return; } CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); pFonts->RemoveAt(csTag.AsByteStringC()); } void RemoveInterFormFont(CPDF_Dictionary* pFormDict, CFX_ByteString csNameTag) { if (!pFormDict || csNameTag.IsEmpty()) { return; } CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); if (!pDR) { return; } CPDF_Dictionary* pFonts = pDR->GetDictBy("Font"); if (!pFonts) { return; } pFonts->RemoveAt(csNameTag.AsByteStringC()); } CPDF_Font* GetDefaultInterFormFont(CPDF_Dictionary* pFormDict, CPDF_Document* pDocument) { if (!pFormDict) { return NULL; } CPDF_DefaultAppearance cDA(pFormDict->GetStringBy("DA")); CFX_ByteString csFontNameTag; FX_FLOAT fFontSize; cDA.GetFont(csFontNameTag, fFontSize); return GetInterFormFont(pFormDict, pDocument, csFontNameTag); } CPDF_IconFit::ScaleMethod CPDF_IconFit::GetScaleMethod() { if (!m_pDict) { return Always; } CFX_ByteString csSW = m_pDict->GetStringBy("SW", "A"); if (csSW == "B") { return Bigger; } if (csSW == "S") { return Smaller; } if (csSW == "N") { return Never; } return Always; } FX_BOOL CPDF_IconFit::IsProportionalScale() { if (!m_pDict) { return TRUE; } return m_pDict->GetStringBy("S", "P") != "A"; } void CPDF_IconFit::GetIconPosition(FX_FLOAT& fLeft, FX_FLOAT& fBottom) { fLeft = fBottom = 0.5; if (!m_pDict) { return; } CPDF_Array* pA = m_pDict->GetArrayBy("A"); if (pA) { uint32_t dwCount = pA->GetCount(); if (dwCount > 0) { fLeft = pA->GetNumberAt(0); } if (dwCount > 1) { fBottom = pA->GetNumberAt(1); } } } FX_BOOL CPDF_IconFit::GetFittingBounds() { if (!m_pDict) { return FALSE; } return m_pDict->GetBooleanBy("FB"); } std::vector<bool> SaveCheckedFieldStatus(CPDF_FormField* pField) { std::vector<bool> result; int iCount = pField->CountControls(); for (int i = 0; i < iCount; ++i) { if (CPDF_FormControl* pControl = pField->GetControl(i)) result.push_back(pControl->IsChecked()); } return result; } CPDF_Object* FPDF_GetFieldAttr(CPDF_Dictionary* pFieldDict, const FX_CHAR* name, int nLevel) { if (nLevel > FPDFDOC_UTILS_MAXRECURSION) { return NULL; } if (!pFieldDict) { return NULL; } CPDF_Object* pAttr = pFieldDict->GetDirectObjectBy(name); if (pAttr) { return pAttr; } CPDF_Dictionary* pParent = pFieldDict->GetDictBy("Parent"); if (!pParent) { return NULL; } return FPDF_GetFieldAttr(pParent, name, nLevel + 1); }