blob: cf728a7d4bda77a3957a3593b8205d0ee17b8be3 [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/fpdf_font/include/cpdf_font.h"
#include "core/fpdfapi/fpdf_font/include/cpdf_fontencoding.h"
#include "core/fpdfapi/fpdf_page/include/cpdf_page.h"
#include "core/fpdfapi/fpdf_parser/include/cfdf_document.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_string.h"
#include "core/fpdfdoc/include/cpdf_filespec.h"
#include "core/fpdfdoc/include/cpdf_formcontrol.h"
#include "core/fpdfdoc/include/cpdf_interform.h"
#include "core/fxge/include/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.GetStringBy("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;
uint32_t dwObjNum = pDocument->AddIndirectObject(pFormDict);
CPDF_Dictionary* pRoot = pDocument->GetRoot();
pRoot->SetAtReference("AcroForm", pDocument, dwObjNum);
}
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->SetAtString("DA", csDA);
}
uint32_t CountFonts(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* GetFont(CPDF_Dictionary* pFormDict,
CPDF_Document* pDocument,
uint32_t index,
CFX_ByteString& csNameTag) {
if (!pFormDict)
return nullptr;
CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR");
if (!pDR)
return nullptr;
CPDF_Dictionary* pFonts = pDR->GetDictBy("Font");
if (!pFonts)
return nullptr;
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 nullptr;
}
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->GetDictBy("DR");
if (!pDR)
return nullptr;
CPDF_Dictionary* pFonts = pDR->GetDictBy("Font");
if (!pFonts)
return nullptr;
CPDF_Dictionary* pElement = pFonts->GetDictBy(csAlias);
if (!pElement)
return nullptr;
if (pElement->GetStringBy("Type") == "Font")
return pDocument->LoadFont(pElement);
return nullptr;
}
CPDF_Font* GetFont(CPDF_Dictionary* pFormDict,
CPDF_Document* pDocument,
CFX_ByteString csFontName,
CFX_ByteString& csNameTag) {
if (!pFormDict || csFontName.IsEmpty())
return nullptr;
CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR");
if (!pDR)
return nullptr;
CPDF_Dictionary* pFonts = pDR->GetDictBy("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->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 nullptr;
}
CPDF_Font* GetNativeFont(CPDF_Dictionary* pFormDict,
CPDF_Document* pDocument,
uint8_t charSet,
CFX_ByteString& csNameTag) {
if (!pFormDict)
return nullptr;
CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR");
if (!pDR)
return nullptr;
CPDF_Dictionary* pFonts = pDR->GetDictBy("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->GetStringBy("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;
}
CPDF_Font* GetDefaultFont(CPDF_Dictionary* pFormDict,
CPDF_Document* pDocument) {
if (!pFormDict)
return nullptr;
CPDF_DefaultAppearance cDA(pFormDict->GetStringBy("DA"));
CFX_ByteString csFontNameTag;
FX_FLOAT fFontSize;
cDA.GetFont(csFontNameTag, fFontSize);
return GetFont(pFormDict, pDocument, csFontNameTag);
}
FX_BOOL FindFont(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;
}
CPDF_Font* GetNativeFont(CPDF_Dictionary* pFormDict,
CPDF_Document* pDocument,
CFX_ByteString& csNameTag) {
csNameTag.clear();
uint8_t charSet = CPDF_InterForm::GetNativeCharSet();
CPDF_Font* pFont = GetDefaultFont(pFormDict, pDocument);
if (pFont) {
CFX_SubstFont* pSubst = pFont->GetSubstFont();
if (pSubst && pSubst->m_Charset == (int)charSet) {
FindFont(pFormDict, pFont, csNameTag);
return pFont;
}
}
return GetNativeFont(pFormDict, pDocument, charSet, csNameTag);
}
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->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 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->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.c_str());
pFonts->SetAtReference(csNameTag, pDocument, pFont->GetFontDict());
}
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);
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;
}
void RemoveFont(CPDF_Dictionary* pFormDict, const CPDF_Font* pFont) {
if (!pFormDict || !pFont)
return;
CFX_ByteString csTag;
if (!FindFont(pFormDict, pFont, csTag))
return;
CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR");
CPDF_Dictionary* pFonts = pDR->GetDictBy("Font");
pFonts->RemoveAt(csTag);
}
void RemoveFont(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);
}
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_
} // namespace
class CFieldTree {
public:
struct Node {
Node* parent;
CFX_ArrayTemplate<Node*> children;
CFX_WideString short_name;
CPDF_FormField* field_ptr;
int CountFields(int nLevel = 0) {
if (nLevel > nMaxRecursion)
return 0;
if (field_ptr)
return 1;
int count = 0;
for (int i = 0; i < children.GetSize(); i++)
count += children.GetAt(i)->CountFields(nLevel + 1);
return count;
}
CPDF_FormField* GetField(int* fields_to_go) {
if (field_ptr) {
if (*fields_to_go == 0)
return field_ptr;
--*fields_to_go;
return nullptr;
}
for (int i = 0; i < children.GetSize(); i++) {
if (CPDF_FormField* pField = children.GetAt(i)->GetField(fields_to_go))
return pField;
}
return nullptr;
}
CPDF_FormField* GetField(int index) {
int fields_to_go = index;
return GetField(&fields_to_go);
}
};
CFieldTree();
~CFieldTree();
void SetField(const CFX_WideString& full_name, CPDF_FormField* field_ptr);
CPDF_FormField* GetField(const CFX_WideString& full_name);
CPDF_FormField* RemoveField(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* field_ptr);
void RemoveNode(Node* pNode, int nLevel = 0);
Node* Lookup(Node* pParent, const CFX_WideString& short_name);
Node m_Root;
};
CFieldTree::CFieldTree() {
m_Root.parent = nullptr;
m_Root.field_ptr = nullptr;
}
CFieldTree::~CFieldTree() {
RemoveAll();
}
CFieldTree::Node* CFieldTree::AddChild(Node* pParent,
const CFX_WideString& short_name,
CPDF_FormField* field_ptr) {
if (!pParent)
return nullptr;
Node* pNode = new Node;
pNode->parent = pParent;
pNode->short_name = short_name;
pNode->field_ptr = field_ptr;
pParent->children.Add(pNode);
return pNode;
}
void CFieldTree::RemoveNode(Node* pNode, int nLevel) {
if (!pNode)
return;
if (nLevel <= nMaxRecursion) {
for (int i = 0; i < pNode->children.GetSize(); i++)
RemoveNode(pNode->children[i], nLevel + 1);
}
delete pNode;
}
CFieldTree::Node* CFieldTree::Lookup(Node* pParent,
const CFX_WideString& short_name) {
if (!pParent)
return nullptr;
for (int i = 0; i < pParent->children.GetSize(); i++) {
Node* pNode = pParent->children[i];
if (pNode->short_name.GetLength() == short_name.GetLength() &&
FXSYS_memcmp(pNode->short_name.c_str(), short_name.c_str(),
short_name.GetLength() * sizeof(FX_WCHAR)) == 0) {
return pNode;
}
}
return nullptr;
}
void CFieldTree::RemoveAll() {
for (int i = 0; i < m_Root.children.GetSize(); i++)
RemoveNode(m_Root.children[i]);
}
void CFieldTree::SetField(const CFX_WideString& full_name,
CPDF_FormField* field_ptr) {
if (full_name == L"")
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->field_ptr = field_ptr;
}
CPDF_FormField* CFieldTree::GetField(const CFX_WideString& full_name) {
if (full_name == L"")
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->field_ptr : nullptr;
}
CPDF_FormField* CFieldTree::RemoveField(const CFX_WideString& full_name) {
if (full_name == L"")
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);
}
if (pNode && pNode != &m_Root) {
for (int i = 0; i < pLast->children.GetSize(); i++) {
if (pNode == pLast->children[i]) {
pLast->children.RemoveAt(i);
break;
}
}
CPDF_FormField* pField = pNode->field_ptr;
RemoveNode(pNode);
return pField;
}
return nullptr;
}
CFieldTree::Node* CFieldTree::FindNode(const CFX_WideString& full_name) {
if (full_name == L"")
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 = ANSI_CHARSET;
UINT iCodePage = ::GetACP();
switch (iCodePage) {
case 932:
charSet = SHIFTJIS_CHARSET;
break;
case 936:
charSet = GB2312_CHARSET;
break;
case 950:
charSet = CHINESEBIG5_CHARSET;
break;
case 1252:
charSet = ANSI_CHARSET;
break;
case 874:
charSet = THAI_CHARSET;
break;
case 949:
charSet = HANGUL_CHARSET;
break;
case 1200:
charSet = ANSI_CHARSET;
break;
case 1250:
charSet = EASTEUROPE_CHARSET;
break;
case 1251:
charSet = RUSSIAN_CHARSET;
break;
case 1253:
charSet = GREEK_CHARSET;
break;
case 1254:
charSet = TURKISH_CHARSET;
break;
case 1255:
charSet = HEBREW_CHARSET;
break;
case 1256:
charSet = ARABIC_CHARSET;
break;
case 1257:
charSet = BALTIC_CHARSET;
break;
case 1258:
charSet = VIETNAMESE_CHARSET;
break;
case 1361:
charSet = 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->GetDictBy("AcroForm");
if (!m_pFormDict)
return;
CPDF_Array* pFields = m_pFormDict->GetArrayBy("Fields");
if (!pFields)
return;
for (size_t i = 0; i < pFields->GetCount(); i++)
LoadField(pFields->GetDictAt(i));
}
CPDF_InterForm::~CPDF_InterForm() {
for (auto it : m_ControlMap)
delete it.second;
int nCount = m_pFieldTree->m_Root.CountFields();
for (int i = 0; i < nCount; ++i)
delete m_pFieldTree->m_Root.GetField(i);
}
FX_BOOL CPDF_InterForm::s_bUpdateAP = TRUE;
FX_BOOL CPDF_InterForm::IsUpdateAPEnabled() {
return s_bUpdateAP;
}
void CPDF_InterForm::SetUpdateAP(FX_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->GetDictBy(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 == ANSI_CHARSET) {
csFontName = "Helvetica";
return csFontName;
}
FX_BOOL bRet = FALSE;
if (charSet == SHIFTJIS_CHARSET) {
bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE,
"MS Mincho", lf);
} else if (charSet == GB2312_CHARSET) {
bRet = RetrieveSpecificFont(charSet, DEFAULT_PITCH | FF_DONTCARE, "SimSun",
lf);
} else if (charSet == 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;
}
CFX_ByteString CPDF_InterForm::GetNativeFont(void* pLogFont) {
#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
return GetNativeFont(GetNativeCharSet(), pLogFont);
#else
return CFX_ByteString();
#endif
}
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;
}
FX_BOOL CPDF_InterForm::ValidateFieldName(
CFX_WideString& csNewFieldName,
int iType,
const CPDF_FormField* pExcludedField,
const CPDF_FormControl* pExcludedControl) {
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'.')
csSub.SetAt(i, L'\0');
else
break;
}
uint32_t dwCount = m_pFieldTree->m_Root.CountFields();
for (uint32_t m = 0; m < dwCount; m++) {
CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(m);
if (!pField)
continue;
if (pField == pExcludedField) {
if (pExcludedControl) {
if (pField->CountControls() < 2)
continue;
} else {
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;
}
FX_BOOL CPDF_InterForm::ValidateFieldName(CFX_WideString& csNewFieldName,
int iType) {
return ValidateFieldName(csNewFieldName, iType, nullptr, nullptr);
}
FX_BOOL CPDF_InterForm::ValidateFieldName(const CPDF_FormField* pField,
CFX_WideString& csNewFieldName) {
return pField && !csNewFieldName.IsEmpty() &&
ValidateFieldName(csNewFieldName, pField->GetFieldType(), pField,
nullptr);
}
FX_BOOL CPDF_InterForm::ValidateFieldName(const CPDF_FormControl* pControl,
CFX_WideString& csNewFieldName) {
if (!pControl || csNewFieldName.IsEmpty())
return FALSE;
CPDF_FormField* pField = pControl->GetField();
return ValidateFieldName(csNewFieldName, pField->GetFieldType(), pField,
pControl);
}
int CPDF_InterForm::CompareFieldName(const CFX_ByteString& name1,
const CFX_ByteString& name2) {
if (name1.GetLength() == name2.GetLength())
return name1 == name2 ? 1 : 0;
const FX_CHAR* ptr1 = name1.c_str();
const FX_CHAR* ptr2 = name2.c_str();
int i = 0;
while (ptr1[i] == ptr2[i])
i++;
if (i == name1.GetLength())
return 2;
if (i == name2.GetLength())
return 3;
return 0;
}
int CPDF_InterForm::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;
}
uint32_t CPDF_InterForm::CountFields(const CFX_WideString& csFieldName) {
if (csFieldName.IsEmpty())
return (uint32_t)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) {
if (csFieldName == L"")
return m_pFieldTree->m_Root.GetField(index);
CFieldTree::Node* pNode = m_pFieldTree->FindNode(csFieldName);
return pNode ? pNode->GetField(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->GetArrayBy("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->GetBooleanBy("NeedAppearances");
}
int CPDF_InterForm::CountFieldsInCalculationOrder() {
if (!m_pFormDict)
return 0;
CPDF_Array* pArray = m_pFormDict->GetArrayBy("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->GetArrayBy("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->GetArrayBy("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;
}
uint32_t CPDF_InterForm::CountFormFonts() {
return CountFonts(m_pFormDict);
}
CPDF_Font* CPDF_InterForm::GetFormFont(uint32_t index,
CFX_ByteString& csNameTag) {
return GetFont(m_pFormDict, m_pDocument, index, csNameTag);
}
CPDF_Font* CPDF_InterForm::GetFormFont(CFX_ByteString csNameTag) {
return GetFont(m_pFormDict, m_pDocument, csNameTag);
}
CPDF_Font* CPDF_InterForm::GetFormFont(CFX_ByteString csFontName,
CFX_ByteString& csNameTag) {
return GetFont(m_pFormDict, m_pDocument, csFontName, csNameTag);
}
CPDF_Font* CPDF_InterForm::GetNativeFormFont(uint8_t charSet,
CFX_ByteString& csNameTag) {
return ::GetNativeFont(m_pFormDict, m_pDocument, charSet, csNameTag);
}
CPDF_Font* CPDF_InterForm::GetNativeFormFont(CFX_ByteString& csNameTag) {
return ::GetNativeFont(m_pFormDict, m_pDocument, csNameTag);
}
FX_BOOL CPDF_InterForm::FindFormFont(const CPDF_Font* pFont,
CFX_ByteString& csNameTag) {
return FindFont(m_pFormDict, pFont, csNameTag);
}
FX_BOOL CPDF_InterForm::FindFormFont(CFX_ByteString csFontName,
CPDF_Font*& pFont,
CFX_ByteString& csNameTag) {
return FindFont(m_pFormDict, m_pDocument, csFontName, pFont, csNameTag);
}
void CPDF_InterForm::AddFormFont(const CPDF_Font* pFont,
CFX_ByteString& csNameTag) {
AddFont(m_pFormDict, m_pDocument, pFont, csNameTag);
}
CPDF_Font* CPDF_InterForm::AddNativeFormFont(uint8_t charSet,
CFX_ByteString& csNameTag) {
return ::AddNativeFont(m_pFormDict, m_pDocument, charSet, csNameTag);
}
CPDF_Font* CPDF_InterForm::AddNativeFormFont(CFX_ByteString& csNameTag) {
return AddNativeInterFormFont(m_pFormDict, m_pDocument, csNameTag);
}
void CPDF_InterForm::RemoveFormFont(const CPDF_Font* pFont) {
RemoveFont(m_pFormDict, pFont);
}
void CPDF_InterForm::RemoveFormFont(CFX_ByteString csNameTag) {
RemoveFont(m_pFormDict, csNameTag);
}
CPDF_DefaultAppearance CPDF_InterForm::GetDefaultAppearance() {
if (!m_pFormDict)
return CPDF_DefaultAppearance();
return CPDF_DefaultAppearance(m_pFormDict->GetStringBy("DA"));
}
CPDF_Font* CPDF_InterForm::GetDefaultFormFont() {
return GetDefaultFont(m_pFormDict, m_pDocument);
}
int CPDF_InterForm::GetFormAlignment() {
return m_pFormDict ? m_pFormDict->GetIntegerBy("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;
int nCount = m_pFieldTree->m_Root.CountFields();
for (int i = 0; i < nCount; ++i) {
CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(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;
int nCount = m_pFieldTree->m_Root.CountFields();
for (int i = 0; i < nCount; ++i) {
CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(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->GetArrayBy("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->GetArrayBy("XFA");
}
void CPDF_InterForm::FixPageFields(const CPDF_Page* pPage) {
CPDF_Dictionary* pPageDict = pPage->m_pFormDict;
if (!pPageDict)
return;
CPDF_Array* pAnnots = pPageDict->GetArrayBy("Annots");
if (!pAnnots)
return;
for (size_t i = 0; i < pAnnots->GetCount(); i++) {
CPDF_Dictionary* pAnnot = pAnnots->GetDictAt(i);
if (pAnnot && pAnnot->GetStringBy("Subtype") == "Widget")
LoadField(pAnnot);
}
}
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->GetStringBy("Subtype") == "Widget") {
pParent = pFieldDict->GetDictBy("Parent");
if (!pParent)
pParent = pFieldDict;
}
if (pParent && pParent != pFieldDict && !pParent->KeyExist("FT")) {
if (pFieldDict->KeyExist("FT")) {
CPDF_Object* pFTValue = pFieldDict->GetDirectObjectBy("FT");
if (pFTValue)
pParent->SetAt("FT", pFTValue->Clone());
}
if (pFieldDict->KeyExist("Ff")) {
CPDF_Object* pFfValue = pFieldDict->GetDirectObjectBy("Ff");
if (pFfValue)
pParent->SetAt("Ff", pFfValue->Clone());
}
}
pField = new CPDF_FormField(this, pParent);
CPDF_Object* pTObj = pDict->GetObjectBy("T");
if (ToReference(pTObj)) {
CPDF_Object* pClone = pTObj->Clone(TRUE);
if (pClone)
pDict->SetAt("T", pClone);
else
pDict->SetAtName("T", "");
}
m_pFieldTree->SetField(csWName, pField);
}
CPDF_Array* pKids = pFieldDict->GetArrayBy("Kids");
if (!pKids) {
if (pFieldDict->GetStringBy("Subtype") == "Widget")
AddControl(pField, pFieldDict);
} else {
for (size_t i = 0; i < pKids->GetCount(); i++) {
CPDF_Dictionary* pKid = pKids->GetDictAt(i);
if (!pKid)
continue;
if (pKid->GetStringBy("Subtype") != "Widget")
continue;
AddControl(pField, pKid);
}
}
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 {
int nCount = m_pFieldTree->m_Root.CountFields();
for (int i = 0; i < nCount; ++i) {
CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(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->GetStringBy("V").IsEmpty())
return pField;
}
}
return nullptr;
}
CFDF_Document* CPDF_InterForm::ExportToFDF(const CFX_WideStringC& pdf_path,
bool bSimpleFileSpec) const {
std::vector<CPDF_FormField*> fields;
int nCount = m_pFieldTree->m_Root.CountFields();
for (int i = 0; i < nCount; ++i)
fields.push_back(m_pFieldTree->m_Root.GetField(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()->GetDictBy("FDF");
if (!pdf_path.IsEmpty()) {
if (bSimpleFileSpec) {
CFX_WideString wsFilePath = CPDF_FileSpec::EncodeFileName(pdf_path);
pMainDict->SetAtString("F", CFX_ByteString::FromUnicode(wsFilePath));
pMainDict->SetAtString("UF", PDF_EncodeText(wsFilePath));
} else {
CPDF_FileSpec filespec;
filespec.SetFileName(pdf_path);
pMainDict->SetAt("F", filespec.GetObj());
}
}
CPDF_Array* pFields = new CPDF_Array;
pMainDict->SetAt("Fields", pFields);
int nCount = m_pFieldTree->m_Root.CountFields();
for (int i = 0; i < nCount; i++) {
CPDF_FormField* pField = m_pFieldTree->m_Root.GetField(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->GetStringBy("V").IsEmpty())
continue;
CFX_WideString fullname = FPDF_GetFullName(pField->GetFieldDict());
CPDF_Dictionary* pFieldDict = new CPDF_Dictionary;
pFieldDict->SetAt("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->SetAtString("V", csBExport);
else
pFieldDict->SetAtName("V", csBExport);
} else {
CPDF_Object* pV = FPDF_GetFieldAttr(pField->m_pDict, "V");
if (pV)
pFieldDict->SetAt("V", pV->Clone(TRUE));
}
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->GetUnicodeTextBy("T");
CPDF_Array* pKids = pFieldDict->GetArrayBy("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->SetAt("Opt",
pFieldDict->GetDirectObjectBy("Opt")->Clone(TRUE));
}
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);
}
}
FX_BOOL CPDF_InterForm::ImportFromFDF(const CFDF_Document* pFDF,
FX_BOOL bNotify) {
if (!pFDF)
return FALSE;
CPDF_Dictionary* pMainDict = pFDF->GetRoot()->GetDictBy("FDF");
if (!pMainDict)
return FALSE;
CPDF_Array* pFields = pMainDict->GetArrayBy("Fields");
if (!pFields)
return FALSE;
m_bsEncoding = pMainDict->GetStringBy("Encoding");
if (bNotify && m_pFormNotify && m_pFormNotify->BeforeFormImportData(this) < 0)
return FALSE;
for (size_t i = 0; i < pFields->GetCount(); i++) {
CPDF_Dictionary* pField = pFields->GetDictAt(i);
if (!pField)
continue;
FDF_ImportField(pField, L"", bNotify);
}
if (bNotify && m_pFormNotify)
m_pFormNotify->AfterFormImportData(this);
return TRUE;
}
void CPDF_InterForm::SetFormNotify(IPDF_FormNotify* pNotify) {
m_pFormNotify = pNotify;
}