blob: b8b4b68e297efba6ac0a65c497b1ab2717024234 [file] [log] [blame]
// 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 <vector>
#include "core/fpdfapi/font/cpdf_font.h"
#include "core/fpdfapi/font/cpdf_fontencoding.h"
#include "core/fpdfapi/page/cpdf_page.h"
#include "core/fpdfapi/parser/cfdf_document.h"
#include "core/fpdfapi/parser/cpdf_array.h"
#include "core/fpdfapi/parser/cpdf_document.h"
#include "core/fpdfapi/parser/cpdf_reference.h"
#include "core/fpdfapi/parser/cpdf_string.h"
#include "core/fpdfdoc/cpdf_filespec.h"
#include "core/fpdfdoc/cpdf_formcontrol.h"
#include "core/fpdfdoc/cpdf_interform.h"
#include "core/fxge/cfx_substfont.h"
#include "core/fxge/fx_font.h"
#include "third_party/base/stl_util.h"
namespace {
const int nMaxRecursion = 32;
const struct SupportFieldEncoding {
const FX_CHAR* m_name;
uint16_t m_codePage;
} g_fieldEncoding[] = {
{"BigFive", 950},
{"GBK", 936},
{"Shift-JIS", 932},
{"UHC", 949},
};
CFX_WideString GetFieldValue(const CPDF_Dictionary& pFieldDict,
const CFX_ByteString& bsEncoding) {
const CFX_ByteString csBValue = pFieldDict.GetStringFor("V");
for (const auto& encoding : g_fieldEncoding) {
if (bsEncoding == encoding.m_name)
return CFX_WideString::FromCodePage(csBValue.AsStringC(),
encoding.m_codePage);
}
CFX_ByteString csTemp = csBValue.Left(2);
if (csTemp == "\xFF\xFE" || csTemp == "\xFE\xFF")
return PDF_DecodeText(csBValue);
return CFX_WideString::FromLocal(csBValue.AsStringC());
}
void AddFont(CPDF_Dictionary*& pFormDict,
CPDF_Document* pDocument,
const CPDF_Font* pFont,
CFX_ByteString& csNameTag);
void InitDict(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument) {
if (!pDocument)
return;
if (!pFormDict) {
pFormDict = new CPDF_Dictionary(pDocument->GetByteStringPool());
pDocument->GetRoot()->SetReferenceFor(
"AcroForm", pDocument, pDocument->AddIndirectObject(pFormDict));
}
CFX_ByteString csDA;
if (!pFormDict->KeyExist("DR")) {
CFX_ByteString csBaseName;
CFX_ByteString csDefault;
uint8_t charSet = CPDF_InterForm::GetNativeCharSet();
CPDF_Font* pFont = CPDF_InterForm::AddStandardFont(pDocument, "Helvetica");
if (pFont) {
AddFont(pFormDict, pDocument, pFont, csBaseName);
csDefault = csBaseName;
}
if (charSet != FXFONT_ANSI_CHARSET) {
CFX_ByteString csFontName =
CPDF_InterForm::GetNativeFont(charSet, nullptr);
if (!pFont || csFontName != "Helvetica") {
pFont = CPDF_InterForm::AddNativeFont(pDocument);
if (pFont) {
csBaseName = "";
AddFont(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->SetStringFor("DA", csDA);
}
CPDF_Font* GetFont(CPDF_Dictionary* pFormDict,
CPDF_Document* pDocument,
CFX_ByteString csNameTag) {
CFX_ByteString csAlias = PDF_NameDecode(csNameTag);
if (!pFormDict || csAlias.IsEmpty())
return nullptr;
CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR");
if (!pDR)
return nullptr;
CPDF_Dictionary* pFonts = pDR->GetDictFor("Font");
if (!pFonts)
return nullptr;
CPDF_Dictionary* pElement = pFonts->GetDictFor(csAlias);
if (!pElement)
return nullptr;
if (pElement->GetStringFor("Type") == "Font")
return pDocument->LoadFont(pElement);
return nullptr;
}
CPDF_Font* GetNativeFont(CPDF_Dictionary* pFormDict,
CPDF_Document* pDocument,
uint8_t charSet,
CFX_ByteString& csNameTag) {
if (!pFormDict)
return nullptr;
CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR");
if (!pDR)
return nullptr;
CPDF_Dictionary* pFonts = pDR->GetDictFor("Font");
if (!pFonts)
return nullptr;
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->GetStringFor("Type") != "Font")
continue;
CPDF_Font* pFind = pDocument->LoadFont(pElement);
if (!pFind)
continue;
CFX_SubstFont* pSubst = pFind->GetSubstFont();
if (!pSubst)
continue;
if (pSubst->m_Charset == (int)charSet) {
csNameTag = csKey;
return pFind;
}
}
return nullptr;
}
FX_BOOL FindFont(CPDF_Dictionary* pFormDict,
const CPDF_Font* pFont,
CFX_ByteString& csNameTag) {
if (!pFormDict || !pFont)
return FALSE;
CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR");
if (!pDR)
return FALSE;
CPDF_Dictionary* pFonts = pDR->GetDictFor("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->GetStringFor("Type") != "Font")
continue;
if (pFont->GetFontDict() == pElement) {
csNameTag = csKey;
return TRUE;
}
}
return FALSE;
}
FX_BOOL FindFont(CPDF_Dictionary* pFormDict,
CPDF_Document* pDocument,
CFX_ByteString csFontName,
CPDF_Font*& pFont,
CFX_ByteString& csNameTag) {
if (!pFormDict)
return FALSE;
CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR");
if (!pDR)
return FALSE;
CPDF_Dictionary* pFonts = pDR->GetDictFor("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->GetStringFor("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 AddFont(CPDF_Dictionary*& pFormDict,
CPDF_Document* pDocument,
const CPDF_Font* pFont,
CFX_ByteString& csNameTag) {
if (!pFont)
return;
if (!pFormDict)
InitDict(pFormDict, pDocument);
CFX_ByteString csTag;
if (FindFont(pFormDict, pFont, csTag)) {
csNameTag = csTag;
return;
}
if (!pFormDict)
InitDict(pFormDict, pDocument);
CPDF_Dictionary* pDR = pFormDict->GetDictFor("DR");
if (!pDR) {
pDR = new CPDF_Dictionary(pDocument->GetByteStringPool());
pFormDict->SetFor("DR", pDR);
}
CPDF_Dictionary* pFonts = pDR->GetDictFor("Font");
if (!pFonts) {
pFonts = new CPDF_Dictionary(pDocument->GetByteStringPool());
pDR->SetFor("Font", pFonts);
}
if (csNameTag.IsEmpty())
csNameTag = pFont->GetBaseFont();
csNameTag.Remove(' ');
csNameTag = CPDF_InterForm::GenerateNewResourceName(pDR, "Font", 4,
csNameTag.c_str());
pFonts->SetReferenceFor(csNameTag, pDocument,
pFont->GetFontDict()->GetObjNum());
}
CPDF_Font* AddNativeFont(CPDF_Dictionary*& pFormDict,
CPDF_Document* pDocument,
uint8_t charSet,
CFX_ByteString& csNameTag) {
if (!pFormDict)
InitDict(pFormDict, pDocument);
CFX_ByteString csTemp;
CPDF_Font* pFont = GetNativeFont(pFormDict, pDocument, charSet, csTemp);
if (pFont) {
csNameTag = csTemp;
return pFont;
}
CFX_ByteString csFontName = CPDF_InterForm::GetNativeFont(charSet, nullptr);
if (!csFontName.IsEmpty() &&
FindFont(pFormDict, pDocument, csFontName, pFont, csNameTag)) {
return pFont;
}
pFont = CPDF_InterForm::AddNativeFont(charSet, pDocument);
if (pFont)
AddFont(pFormDict, pDocument, pFont, csNameTag);
return pFont;
}
class CFieldNameExtractor {
public:
explicit CFieldNameExtractor(const CFX_WideString& full_name)
: m_FullName(full_name) {
m_pCur = m_FullName.c_str();
m_pEnd = m_pCur + m_FullName.GetLength();
}
void GetNext(const FX_WCHAR*& pSubName, FX_STRSIZE& size) {
pSubName = m_pCur;
while (m_pCur < m_pEnd && m_pCur[0] != L'.')
m_pCur++;
size = (FX_STRSIZE)(m_pCur - pSubName);
if (m_pCur < m_pEnd && m_pCur[0] == L'.')
m_pCur++;
}
protected:
CFX_WideString m_FullName;
const FX_WCHAR* m_pCur;
const FX_WCHAR* m_pEnd;
};
#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
typedef struct {
FX_BOOL bFind;
LOGFONTA lf;
} PDF_FONTDATA;
static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXA* lpelfe,
NEWTEXTMETRICEX* lpntme,
DWORD FontType,
LPARAM lParam) {
if (FontType != 0x004 || strchr(lpelfe->elfLogFont.lfFaceName, '@'))
return 1;
PDF_FONTDATA* pData = (PDF_FONTDATA*)lParam;
memcpy(&pData->lf, &lpelfe->elfLogFont, sizeof(LOGFONTA));
pData->bFind = TRUE;
return 0;
}
FX_BOOL RetrieveSpecificFont(LOGFONTA& lf) {
PDF_FONTDATA fd;
memset(&fd, 0, sizeof(PDF_FONTDATA));
HDC hDC = ::GetDC(nullptr);
EnumFontFamiliesExA(hDC, &lf, (FONTENUMPROCA)EnumFontFamExProc, (LPARAM)&fd,
0);
::ReleaseDC(nullptr, hDC);
if (fd.bFind)
memcpy(&lf, &fd.lf, sizeof(LOGFONTA));
return fd.bFind;
}
FX_BOOL RetrieveSpecificFont(uint8_t charSet,
uint8_t pitchAndFamily,
LPCSTR pcsFontName,
LOGFONTA& lf) {
memset(&lf, 0, sizeof(LOGFONTA));
lf.lfCharSet = charSet;
lf.lfPitchAndFamily = pitchAndFamily;
if (pcsFontName) {
// TODO(dsinclair): Should this be strncpy?
strcpy(lf.lfFaceName, pcsFontName);
}
return RetrieveSpecificFont(lf);
}
#endif // _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
int CompareFieldName(const CFX_WideString& name1, const CFX_WideString& name2) {
const FX_WCHAR* ptr1 = name1.c_str();
const FX_WCHAR* ptr2 = name2.c_str();
if (name1.GetLength() == name2.GetLength())
return name1 == name2 ? 1 : 0;
int i = 0;
while (ptr1[i] == ptr2[i])
i++;
if (i == name1.GetLength())
return 2;
if (i == name2.GetLength())
return 3;
return 0;
}
} // namespace
class CFieldTree {
public:
class Node {
public:
Node() : m_pField(nullptr) {}
Node(const CFX_WideString& short_name, CPDF_FormField* pField)
: m_ShortName(short_name), m_pField(pField) {}
~Node() {}
void AddChildNode(Node* pNode) { m_Children.push_back(pNode); }
size_t GetChildrenCount() const { return m_Children.size(); }
Node* GetChildAt(size_t i) { return m_Children[i]; }
const Node* GetChildAt(size_t i) const { return m_Children[i]; }
CPDF_FormField* GetFieldAtIndex(size_t index) {
size_t nFieldsToGo = index;
return GetFieldInternal(&nFieldsToGo);
}
size_t CountFields() const { return CountFieldsInternal(0); }
void SetField(CPDF_FormField* pField) { m_pField = pField; }
CPDF_FormField* GetField() { return m_pField; }
const CPDF_FormField* GetField() const { return m_pField; }
const CFX_WideString& GetShortName() const { return m_ShortName; }
private:
CPDF_FormField* GetFieldInternal(size_t* pFieldsToGo) {
if (m_pField) {
if (*pFieldsToGo == 0)
return m_pField;
--*pFieldsToGo;
}
for (size_t i = 0; i < GetChildrenCount(); ++i) {
CPDF_FormField* pField = GetChildAt(i)->GetFieldInternal(pFieldsToGo);
if (pField)
return pField;
}
return nullptr;
}
size_t CountFieldsInternal(int nLevel) const {
if (nLevel > nMaxRecursion)
return 0;
size_t count = 0;
if (m_pField)
++count;
for (size_t i = 0; i < GetChildrenCount(); ++i)
count += GetChildAt(i)->CountFieldsInternal(nLevel + 1);
return count;
}
std::vector<Node*> m_Children;
CFX_WideString m_ShortName;
CPDF_FormField* m_pField;
};
CFieldTree();
~CFieldTree();
void SetField(const CFX_WideString& full_name, CPDF_FormField* pField);
CPDF_FormField* GetField(const CFX_WideString& full_name);
void RemoveAll();
Node* FindNode(const CFX_WideString& full_name);
Node* AddChild(Node* pParent,
const CFX_WideString& short_name,
CPDF_FormField* pField);
void RemoveNode(Node* pNode, int nLevel = 0);
Node* Lookup(Node* pParent, const CFX_WideString& short_name);
Node m_Root;
};
CFieldTree::CFieldTree() {}
CFieldTree::~CFieldTree() {
RemoveAll();
}
CFieldTree::Node* CFieldTree::AddChild(Node* pParent,
const CFX_WideString& short_name,
CPDF_FormField* pField) {
if (!pParent)
return nullptr;
Node* pNode = new Node(short_name, pField);
pParent->AddChildNode(pNode);
return pNode;
}
void CFieldTree::RemoveNode(Node* pNode, int nLevel) {
if (!pNode)
return;
if (nLevel <= nMaxRecursion) {
for (size_t i = 0; i < pNode->GetChildrenCount(); ++i)
RemoveNode(pNode->GetChildAt(i), nLevel + 1);
}
delete pNode;
}
CFieldTree::Node* CFieldTree::Lookup(Node* pParent,
const CFX_WideString& short_name) {
if (!pParent)
return nullptr;
for (size_t i = 0; i < pParent->GetChildrenCount(); ++i) {
Node* pNode = pParent->GetChildAt(i);
if (pNode->GetShortName() == short_name)
return pNode;
}
return nullptr;
}
void CFieldTree::RemoveAll() {
for (size_t i = 0; i < m_Root.GetChildrenCount(); ++i)
RemoveNode(m_Root.GetChildAt(i));
}
void CFieldTree::SetField(const CFX_WideString& full_name,
CPDF_FormField* pField) {
if (full_name.IsEmpty())
return;
CFieldNameExtractor name_extractor(full_name);
const FX_WCHAR* pName;
FX_STRSIZE nLength;
name_extractor.GetNext(pName, nLength);
Node* pNode = &m_Root;
Node* pLast = nullptr;
while (nLength > 0) {
pLast = pNode;
CFX_WideString name = CFX_WideString(pName, nLength);
pNode = Lookup(pLast, name);
if (!pNode)
pNode = AddChild(pLast, name, nullptr);
name_extractor.GetNext(pName, nLength);
}
if (pNode != &m_Root)
pNode->SetField(pField);
}
CPDF_FormField* CFieldTree::GetField(const CFX_WideString& full_name) {
if (full_name.IsEmpty())
return nullptr;
CFieldNameExtractor name_extractor(full_name);
const FX_WCHAR* pName;
FX_STRSIZE nLength;
name_extractor.GetNext(pName, nLength);
Node* pNode = &m_Root;
Node* pLast = nullptr;
while (nLength > 0 && pNode) {
pLast = pNode;
CFX_WideString name = CFX_WideString(pName, nLength);
pNode = Lookup(pLast, name);
name_extractor.GetNext(pName, nLength);
}
return pNode ? pNode->GetField() : nullptr;
}
CFieldTree::Node* CFieldTree::FindNode(const CFX_WideString& full_name) {
if (full_name.IsEmpty())
return nullptr;
CFieldNameExtractor name_extractor(full_name);
const FX_WCHAR* pName;
FX_STRSIZE nLength;
name_extractor.GetNext(pName, nLength);
Node* pNode = &m_Root;
Node* pLast = nullptr;
while (nLength > 0 && pNode) {
pLast = pNode;
CFX_WideString name = CFX_WideString(pName, nLength);
pNode = Lookup(pLast, name);
name_extractor.GetNext(pName, nLength);
}
return pNode;
}
CPDF_Font* AddNativeInterFormFont(CPDF_Dictionary*& pFormDict,
CPDF_Document* pDocument,
CFX_ByteString& csNameTag) {
uint8_t charSet = CPDF_InterForm::GetNativeCharSet();
return AddNativeFont(pFormDict, pDocument, charSet, csNameTag);
}
// static
uint8_t CPDF_InterForm::GetNativeCharSet() {
#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
uint8_t charSet = FXFONT_ANSI_CHARSET;
UINT iCodePage = ::GetACP();
switch (iCodePage) {
case 932:
charSet = FXFONT_SHIFTJIS_CHARSET;
break;
case 936:
charSet = FXFONT_GB2312_CHARSET;
break;
case 950:
charSet = FXFONT_CHINESEBIG5_CHARSET;
break;
case 1252:
charSet = FXFONT_ANSI_CHARSET;
break;
case 874:
charSet = FXFONT_THAI_CHARSET;
break;
case 949:
charSet = FXFONT_HANGUL_CHARSET;
break;
case 1200:
charSet = FXFONT_ANSI_CHARSET;
break;
case 1250:
charSet = FXFONT_EASTEUROPE_CHARSET;
break;
case 1251:
charSet = FXFONT_RUSSIAN_CHARSET;
break;
case 1253:
charSet = FXFONT_GREEK_CHARSET;
break;
case 1254:
charSet = FXFONT_TURKISH_CHARSET;
break;
case 1255:
charSet = FXFONT_HEBREW_CHARSET;
break;
case 1256:
charSet = FXFONT_ARABIC_CHARSET;
break;
case 1257:
charSet = FXFONT_BALTIC_CHARSET;
break;
case 1258:
charSet = FXFONT_VIETNAMESE_CHARSET;
break;
case 1361:
charSet = FXFONT_JOHAB_CHARSET;
break;
}
return charSet;
#else
return 0;
#endif
}
CPDF_InterForm::CPDF_InterForm(CPDF_Document* pDocument)
: m_pDocument(pDocument),
m_pFormDict(nullptr),
m_pFieldTree(new CFieldTree),
m_pFormNotify(nullptr) {
CPDF_Dictionary* pRoot = m_pDocument->GetRoot();
if (!pRoot)
return;
m_pFormDict = pRoot->GetDictFor("AcroForm");
if (!m_pFormDict)
return;
CPDF_Array* pFields = m_pFormDict->GetArrayFor("Fields");
if (!pFields)
return;
for (size_t i = 0; i < pFields->GetCount(); ++i)
LoadField(pFields->GetDictAt(i), 0);
}
CPDF_InterForm::~CPDF_InterForm() {
for (auto it : m_ControlMap)
delete it.second;
size_t nCount = m_pFieldTree->m_Root.CountFields();
for (size_t i = 0; i < nCount; ++i)
delete m_pFieldTree->m_Root.GetFieldAtIndex(i);
}
bool CPDF_InterForm::s_bUpdateAP = true;
bool CPDF_InterForm::IsUpdateAPEnabled() {
return s_bUpdateAP;
}
void CPDF_InterForm::SetUpdateAP(bool bUpdateAP) {
s_bUpdateAP = bUpdateAP;
}
CFX_ByteString CPDF_InterForm::GenerateNewResourceName(
const CPDF_Dictionary* pResDict,
const FX_CHAR* csType,
int iMinLen,
const FX_CHAR* csPrefix) {
CFX_ByteString csStr = csPrefix;
CFX_ByteString csBType = csType;
if (csStr.IsEmpty()) {
if (csBType == "ExtGState")
csStr = "GS";
else if (csBType == "ColorSpace")
csStr = "CS";
else if (csBType == "Font")
csStr = "ZiTi";
else
csStr = "Res";
}
CFX_ByteString csTmp = csStr;
int iCount = csStr.GetLength();
int m = 0;
if (iMinLen > 0) {
csTmp = "";
while (m < iMinLen && m < iCount)
csTmp += csStr[m++];
while (m < iMinLen) {
csTmp += '0' + m % 10;
m++;
}
} else {
m = iCount;
}
if (!pResDict)
return csTmp;
CPDF_Dictionary* pDict = pResDict->GetDictFor(csType);
if (!pDict)
return csTmp;
int num = 0;
CFX_ByteString bsNum;
while (TRUE) {
CFX_ByteString csKey = csTmp + bsNum;
if (!pDict->KeyExist(csKey))
return csKey;
if (m < iCount)
csTmp += csStr[m++];
else
bsNum.Format("%d", num++);
m++;
}
return csTmp;
}
CPDF_Font* CPDF_InterForm::AddStandardFont(CPDF_Document* pDocument,
CFX_ByteString csFontName) {
if (!pDocument || csFontName.IsEmpty())
return nullptr;
if (csFontName == "ZapfDingbats")
return pDocument->AddStandardFont(csFontName.c_str(), nullptr);
CPDF_FontEncoding encoding(PDFFONT_ENCODING_WINANSI);
return pDocument->AddStandardFont(csFontName.c_str(), &encoding);
}
CFX_ByteString CPDF_InterForm::GetNativeFont(uint8_t charSet, void* pLogFont) {
CFX_ByteString csFontName;
#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
LOGFONTA lf = {};
if (charSet == FXFONT_ANSI_CHARSET) {
csFontName = "Helvetica";
return csFontName;
}
FX_BOOL bRet = FALSE;
if (charSet == FXFONT_SHIFTJIS_CHARSET) {
bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE,
"MS Mincho", lf);
} else if (charSet == FXFONT_GB2312_CHARSET) {
bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, "SimSun",
lf);
} else if (charSet == FXFONT_CHINESEBIG5_CHARSET) {
bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, "MingLiU",
lf);
}
if (!bRet) {
bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE,
"Arial Unicode MS", lf);
}
if (!bRet) {
bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE,
"Microsoft Sans Serif", lf);
}
if (!bRet) {
bRet =
RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, nullptr, lf);
}
if (bRet) {
if (pLogFont)
memcpy(pLogFont, &lf, sizeof(LOGFONTA));
csFontName = lf.lfFaceName;
return csFontName;
}
#endif
return csFontName;
}
CPDF_Font* CPDF_InterForm::AddNativeFont(uint8_t charSet,
CPDF_Document* pDocument) {
if (!pDocument)
return nullptr;
#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
LOGFONTA lf;
CFX_ByteString csFontName = GetNativeFont(charSet, &lf);
if (!csFontName.IsEmpty()) {
if (csFontName == "Helvetica")
return AddStandardFont(pDocument, csFontName);
return pDocument->AddWindowsFont(&lf, FALSE, TRUE);
}
#endif
return nullptr;
}
CPDF_Font* CPDF_InterForm::AddNativeFont(CPDF_Document* pDocument) {
return pDocument ? AddNativeFont(GetNativeCharSet(), pDocument) : nullptr;
}
bool CPDF_InterForm::ValidateFieldName(
CFX_WideString& csNewFieldName,
int iType,
const CPDF_FormField* pExcludedField,
const CPDF_FormControl* pExcludedControl) const {
if (csNewFieldName.IsEmpty())
return false;
int iPos = 0;
int iLength = csNewFieldName.GetLength();
CFX_WideString csSub;
while (true) {
while (iPos < iLength &&
(csNewFieldName[iPos] == L'.' || csNewFieldName[iPos] == L' ')) {
iPos++;
}
if (iPos < iLength && !csSub.IsEmpty())
csSub += L'.';
while (iPos < iLength && csNewFieldName[iPos] != L'.')
csSub += csNewFieldName[iPos++];
for (int i = csSub.GetLength() - 1; i > -1; i--) {
if (csSub[i] != L' ' && csSub[i] != L'.')
break;
csSub.SetAt(i, L'\0');
}
size_t dwCount = m_pFieldTree->m_Root.CountFields();
for (size_t m = 0; m < dwCount; ++m) {
CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(m);
if (!pField)
continue;
if (pField == pExcludedField) {
if (!pExcludedControl || pField->CountControls() < 2)
continue;
}
CFX_WideString csFullName = pField->GetFullName();
int iRet = CompareFieldName(csSub, csFullName);
if (iRet == 1) {
if (pField->GetFieldType() != iType)
return false;
} else if (iRet == 2 && csSub == csNewFieldName) {
if (csFullName[iPos] == L'.')
return false;
} else if (iRet == 3 && csSub == csNewFieldName) {
if (csNewFieldName[csFullName.GetLength()] == L'.')
return false;
}
}
if (iPos >= iLength)
break;
}
if (csSub.IsEmpty())
return false;
csNewFieldName = csSub;
return true;
}
size_t CPDF_InterForm::CountFields(const CFX_WideString& csFieldName) const {
if (csFieldName.IsEmpty())
return m_pFieldTree->m_Root.CountFields();
CFieldTree::Node* pNode = m_pFieldTree->FindNode(csFieldName);
return pNode ? pNode->CountFields() : 0;
}
CPDF_FormField* CPDF_InterForm::GetField(
uint32_t index,
const CFX_WideString& csFieldName) const {
if (csFieldName.IsEmpty())
return m_pFieldTree->m_Root.GetFieldAtIndex(index);
CFieldTree::Node* pNode = m_pFieldTree->FindNode(csFieldName);
return pNode ? pNode->GetFieldAtIndex(index) : nullptr;
}
CPDF_FormField* CPDF_InterForm::GetFieldByDict(
CPDF_Dictionary* pFieldDict) const {
if (!pFieldDict)
return nullptr;
CFX_WideString csWName = FPDF_GetFullName(pFieldDict);
return m_pFieldTree->GetField(csWName);
}
CPDF_FormControl* CPDF_InterForm::GetControlAtPoint(CPDF_Page* pPage,
FX_FLOAT pdf_x,
FX_FLOAT pdf_y,
int* z_order) const {
CPDF_Array* pAnnotList = pPage->m_pFormDict->GetArrayFor("Annots");
if (!pAnnotList)
return nullptr;
for (size_t i = pAnnotList->GetCount(); i > 0; --i) {
size_t annot_index = i - 1;
CPDF_Dictionary* pAnnot = pAnnotList->GetDictAt(annot_index);
if (!pAnnot)
continue;
const auto it = m_ControlMap.find(pAnnot);
if (it == m_ControlMap.end())
continue;
CPDF_FormControl* pControl = it->second;
CFX_FloatRect rect = pControl->GetRect();
if (!rect.Contains(pdf_x, pdf_y))
continue;
if (z_order)
*z_order = static_cast<int>(annot_index);
return pControl;
}
return nullptr;
}
CPDF_FormControl* CPDF_InterForm::GetControlByDict(
const CPDF_Dictionary* pWidgetDict) const {
const auto it = m_ControlMap.find(pWidgetDict);
return it != m_ControlMap.end() ? it->second : nullptr;
}
FX_BOOL CPDF_InterForm::NeedConstructAP() const {
return m_pFormDict && m_pFormDict->GetBooleanFor("NeedAppearances");
}
int CPDF_InterForm::CountFieldsInCalculationOrder() {
if (!m_pFormDict)
return 0;
CPDF_Array* pArray = m_pFormDict->GetArrayFor("CO");
return pArray ? pArray->GetCount() : 0;
}
CPDF_FormField* CPDF_InterForm::GetFieldInCalculationOrder(int index) {
if (!m_pFormDict || index < 0)
return nullptr;
CPDF_Array* pArray = m_pFormDict->GetArrayFor("CO");
if (!pArray)
return nullptr;
CPDF_Dictionary* pElement = ToDictionary(pArray->GetDirectObjectAt(index));
return pElement ? GetFieldByDict(pElement) : nullptr;
}
int CPDF_InterForm::FindFieldInCalculationOrder(const CPDF_FormField* pField) {
if (!m_pFormDict || !pField)
return -1;
CPDF_Array* pArray = m_pFormDict->GetArrayFor("CO");
if (!pArray)
return -1;
for (size_t i = 0; i < pArray->GetCount(); i++) {
CPDF_Object* pElement = pArray->GetDirectObjectAt(i);
if (pElement == pField->m_pDict)
return i;
}
return -1;
}
CPDF_Font* CPDF_InterForm::GetFormFont(CFX_ByteString csNameTag) {
return GetFont(m_pFormDict, m_pDocument, csNameTag);
}
CPDF_DefaultAppearance CPDF_InterForm::GetDefaultAppearance() const {
if (!m_pFormDict)
return CPDF_DefaultAppearance();
return CPDF_DefaultAppearance(m_pFormDict->GetStringFor("DA"));
}
int CPDF_InterForm::GetFormAlignment() const {
return m_pFormDict ? m_pFormDict->GetIntegerFor("Q", 0) : 0;
}
bool CPDF_InterForm::ResetForm(const std::vector<CPDF_FormField*>& fields,
bool bIncludeOrExclude,
bool bNotify) {
if (bNotify && m_pFormNotify && m_pFormNotify->BeforeFormReset(this) < 0)
return false;
size_t nCount = m_pFieldTree->m_Root.CountFields();
for (size_t i = 0; i < nCount; ++i) {
CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i);
if (!pField)
continue;
if (bIncludeOrExclude == pdfium::ContainsValue(fields, pField))
pField->ResetField(bNotify);
}
if (bNotify && m_pFormNotify)
m_pFormNotify->AfterFormReset(this);
return true;
}
bool CPDF_InterForm::ResetForm(bool bNotify) {
if (bNotify && m_pFormNotify && m_pFormNotify->BeforeFormReset(this) < 0)
return false;
size_t nCount = m_pFieldTree->m_Root.CountFields();
for (size_t i = 0; i < nCount; ++i) {
CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i);
if (!pField)
continue;
pField->ResetField(bNotify);
}
if (bNotify && m_pFormNotify)
m_pFormNotify->AfterFormReset(this);
return true;
}
void CPDF_InterForm::LoadField(CPDF_Dictionary* pFieldDict, int nLevel) {
if (nLevel > nMaxRecursion)
return;
if (!pFieldDict)
return;
uint32_t dwParentObjNum = pFieldDict->GetObjNum();
CPDF_Array* pKids = pFieldDict->GetArrayFor("Kids");
if (!pKids) {
AddTerminalField(pFieldDict);
return;
}
CPDF_Dictionary* pFirstKid = pKids->GetDictAt(0);
if (!pFirstKid)
return;
if (pFirstKid->KeyExist("T") || pFirstKid->KeyExist("Kids")) {
for (size_t i = 0; i < pKids->GetCount(); i++) {
CPDF_Dictionary* pChildDict = pKids->GetDictAt(i);
if (pChildDict) {
if (pChildDict->GetObjNum() != dwParentObjNum)
LoadField(pChildDict, nLevel + 1);
}
}
} else {
AddTerminalField(pFieldDict);
}
}
FX_BOOL CPDF_InterForm::HasXFAForm() const {
return m_pFormDict && m_pFormDict->GetArrayFor("XFA");
}
void CPDF_InterForm::FixPageFields(const CPDF_Page* pPage) {
CPDF_Dictionary* pPageDict = pPage->m_pFormDict;
if (!pPageDict)
return;
CPDF_Array* pAnnots = pPageDict->GetArrayFor("Annots");
if (!pAnnots)
return;
for (size_t i = 0; i < pAnnots->GetCount(); i++) {
CPDF_Dictionary* pAnnot = pAnnots->GetDictAt(i);
if (pAnnot && pAnnot->GetStringFor("Subtype") == "Widget")
LoadField(pAnnot, 0);
}
}
CPDF_FormField* CPDF_InterForm::AddTerminalField(CPDF_Dictionary* pFieldDict) {
if (!pFieldDict->KeyExist("T"))
return nullptr;
CPDF_Dictionary* pDict = pFieldDict;
CFX_WideString csWName = FPDF_GetFullName(pFieldDict);
if (csWName.IsEmpty())
return nullptr;
CPDF_FormField* pField = nullptr;
pField = m_pFieldTree->GetField(csWName);
if (!pField) {
CPDF_Dictionary* pParent = pFieldDict;
if (!pFieldDict->KeyExist("T") &&
pFieldDict->GetStringFor("Subtype") == "Widget") {
pParent = pFieldDict->GetDictFor("Parent");
if (!pParent)
pParent = pFieldDict;
}
if (pParent && pParent != pFieldDict && !pParent->KeyExist("FT")) {
if (pFieldDict->KeyExist("FT")) {
CPDF_Object* pFTValue = pFieldDict->GetDirectObjectFor("FT");
if (pFTValue)
pParent->SetFor("FT", pFTValue->Clone());
}
if (pFieldDict->KeyExist("Ff")) {
CPDF_Object* pFfValue = pFieldDict->GetDirectObjectFor("Ff");
if (pFfValue)
pParent->SetFor("Ff", pFfValue->Clone());
}
}
pField = new CPDF_FormField(this, pParent);
CPDF_Object* pTObj = pDict->GetObjectFor("T");
if (ToReference(pTObj)) {
CPDF_Object* pClone = pTObj->CloneDirectObject();
if (pClone)
pDict->SetFor("T", pClone);
else
pDict->SetNameFor("T", "");
}
m_pFieldTree->SetField(csWName, pField);
}
CPDF_Array* pKids = pFieldDict->GetArrayFor("Kids");
if (pKids) {
for (size_t i = 0; i < pKids->GetCount(); i++) {
CPDF_Dictionary* pKid = pKids->GetDictAt(i);
if (!pKid)
continue;
if (pKid->GetStringFor("Subtype") != "Widget")
continue;
AddControl(pField, pKid);
}
} else {
if (pFieldDict->GetStringFor("Subtype") == "Widget")
AddControl(pField, pFieldDict);
}
return pField;
}
CPDF_FormControl* CPDF_InterForm::AddControl(CPDF_FormField* pField,
CPDF_Dictionary* pWidgetDict) {
const auto it = m_ControlMap.find(pWidgetDict);
if (it != m_ControlMap.end())
return it->second;
CPDF_FormControl* pControl = new CPDF_FormControl(pField, pWidgetDict);
m_ControlMap[pWidgetDict] = pControl;
pField->m_ControlList.Add(pControl);
return pControl;
}
CPDF_FormField* CPDF_InterForm::CheckRequiredFields(
const std::vector<CPDF_FormField*>* fields,
bool bIncludeOrExclude) const {
size_t nCount = m_pFieldTree->m_Root.CountFields();
for (size_t i = 0; i < nCount; ++i) {
CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i);
if (!pField)
continue;
int32_t iType = pField->GetType();
if (iType == CPDF_FormField::PushButton ||
iType == CPDF_FormField::CheckBox || iType == CPDF_FormField::ListBox) {
continue;
}
uint32_t dwFlags = pField->GetFieldFlags();
// TODO(thestig): Look up these magic numbers and add constants for them.
if (dwFlags & 0x04)
continue;
bool bFind = true;
if (fields)
bFind = pdfium::ContainsValue(*fields, pField);
if (bIncludeOrExclude == bFind) {
CPDF_Dictionary* pFieldDict = pField->m_pDict;
if ((dwFlags & 0x02) != 0 && pFieldDict->GetStringFor("V").IsEmpty())
return pField;
}
}
return nullptr;
}
CFDF_Document* CPDF_InterForm::ExportToFDF(const CFX_WideStringC& pdf_path,
bool bSimpleFileSpec) const {
std::vector<CPDF_FormField*> fields;
size_t nCount = m_pFieldTree->m_Root.CountFields();
for (size_t i = 0; i < nCount; ++i)
fields.push_back(m_pFieldTree->m_Root.GetFieldAtIndex(i));
return ExportToFDF(pdf_path, fields, true, bSimpleFileSpec);
}
CFDF_Document* CPDF_InterForm::ExportToFDF(
const CFX_WideStringC& pdf_path,
const std::vector<CPDF_FormField*>& fields,
bool bIncludeOrExclude,
bool bSimpleFileSpec) const {
CFDF_Document* pDoc = CFDF_Document::CreateNewDoc();
if (!pDoc)
return nullptr;
CPDF_Dictionary* pMainDict = pDoc->GetRoot()->GetDictFor("FDF");
if (!pdf_path.IsEmpty()) {
if (bSimpleFileSpec) {
CFX_WideString wsFilePath = CPDF_FileSpec::EncodeFileName(pdf_path);
pMainDict->SetStringFor("F", CFX_ByteString::FromUnicode(wsFilePath));
pMainDict->SetStringFor("UF", PDF_EncodeText(wsFilePath));
} else {
CPDF_FileSpec filespec(pDoc->GetByteStringPool());
filespec.SetFileName(pdf_path);
pMainDict->SetFor("F", filespec.GetObj());
}
}
CPDF_Array* pFields = new CPDF_Array;
pMainDict->SetFor("Fields", pFields);
size_t nCount = m_pFieldTree->m_Root.CountFields();
for (size_t i = 0; i < nCount; ++i) {
CPDF_FormField* pField = m_pFieldTree->m_Root.GetFieldAtIndex(i);
if (!pField || pField->GetType() == CPDF_FormField::PushButton)
continue;
uint32_t dwFlags = pField->GetFieldFlags();
if (dwFlags & 0x04)
continue;
if (bIncludeOrExclude == pdfium::ContainsValue(fields, pField)) {
if ((dwFlags & 0x02) != 0 && pField->m_pDict->GetStringFor("V").IsEmpty())
continue;
CFX_WideString fullname = FPDF_GetFullName(pField->GetFieldDict());
CPDF_Dictionary* pFieldDict =
new CPDF_Dictionary(pDoc->GetByteStringPool());
pFieldDict->SetFor("T", new CPDF_String(fullname));
if (pField->GetType() == CPDF_FormField::CheckBox ||
pField->GetType() == CPDF_FormField::RadioButton) {
CFX_WideString csExport = pField->GetCheckValue(FALSE);
CFX_ByteString csBExport = PDF_EncodeText(csExport);
CPDF_Object* pOpt = FPDF_GetFieldAttr(pField->m_pDict, "Opt");
if (pOpt)
pFieldDict->SetStringFor("V", csBExport);
else
pFieldDict->SetNameFor("V", csBExport);
} else {
CPDF_Object* pV = FPDF_GetFieldAttr(pField->m_pDict, "V");
if (pV)
pFieldDict->SetFor("V", pV->CloneDirectObject());
}
pFields->Add(pFieldDict);
}
}
return pDoc;
}
void CPDF_InterForm::FDF_ImportField(CPDF_Dictionary* pFieldDict,
const CFX_WideString& parent_name,
FX_BOOL bNotify,
int nLevel) {
CFX_WideString name;
if (!parent_name.IsEmpty())
name = parent_name + L".";
name += pFieldDict->GetUnicodeTextFor("T");
CPDF_Array* pKids = pFieldDict->GetArrayFor("Kids");
if (pKids) {
for (size_t i = 0; i < pKids->GetCount(); i++) {
CPDF_Dictionary* pKid = pKids->GetDictAt(i);
if (!pKid)
continue;
if (nLevel <= nMaxRecursion)
FDF_ImportField(pKid, name, bNotify, nLevel + 1);
}
return;
}
if (!pFieldDict->KeyExist("V"))
return;
CPDF_FormField* pField = m_pFieldTree->GetField(name);
if (!pField)
return;
CFX_WideString csWValue = GetFieldValue(*pFieldDict, m_bsEncoding);
int iType = pField->GetFieldType();
if (bNotify && m_pFormNotify) {
int iRet = 0;
if (iType == FIELDTYPE_LISTBOX)
iRet = m_pFormNotify->BeforeSelectionChange(pField, csWValue);
else if (iType == FIELDTYPE_COMBOBOX || iType == FIELDTYPE_TEXTFIELD)
iRet = m_pFormNotify->BeforeValueChange(pField, csWValue);
if (iRet < 0)
return;
}
pField->SetValue(csWValue);
CPDF_FormField::Type eType = pField->GetType();
if ((eType == CPDF_FormField::ListBox || eType == CPDF_FormField::ComboBox) &&
pFieldDict->KeyExist("Opt")) {
pField->m_pDict->SetFor(
"Opt", pFieldDict->GetDirectObjectFor("Opt")->CloneDirectObject());
}
if (bNotify && m_pFormNotify) {
if (iType == FIELDTYPE_CHECKBOX || iType == FIELDTYPE_RADIOBUTTON)
m_pFormNotify->AfterCheckedStatusChange(pField);
else if (iType == FIELDTYPE_LISTBOX)
m_pFormNotify->AfterSelectionChange(pField);
else if (iType == FIELDTYPE_COMBOBOX || iType == FIELDTYPE_TEXTFIELD)
m_pFormNotify->AfterValueChange(pField);
}
}
void CPDF_InterForm::SetFormNotify(IPDF_FormNotify* pNotify) {
m_pFormNotify = pNotify;
}