From 27053d81ca80a2f9433abf3e9c393d2914c91ad8 Mon Sep 17 00:00:00 2001 From: dsinclair Date: Tue, 2 Aug 2016 15:43:46 -0700 Subject: Splitting fpdfdoc/doc_* part III. This CL cleans up the remaining doc_* files, splitting into .h and .pp files as needed. Review-Url: https://codereview.chromium.org/2190983002 --- core/fpdfdoc/cpdf_apsettings.cpp | 119 +++ core/fpdfdoc/cpdf_defaultappearance.cpp | 222 +++++ core/fpdfdoc/cpdf_formcontrol.cpp | 329 +++++++ core/fpdfdoc/cpdf_formfield.cpp | 997 +++++++++++++++++++ core/fpdfdoc/cpdf_iconfit.cpp | 48 + core/fpdfdoc/cpdf_interform.cpp | 1635 +++++++++++++++++++++++++++++++ core/fpdfdoc/cpdf_numbertree.cpp | 52 + core/fpdfdoc/cpdf_numbertree.h | 23 + core/fpdfdoc/cpdf_pagelabel.cpp | 2 +- core/fpdfdoc/cpvt_fontmap.cpp | 2 +- core/fpdfdoc/doc_form.cpp | 1203 ----------------------- core/fpdfdoc/doc_formcontrol.cpp | 438 --------- core/fpdfdoc/doc_formfield.cpp | 987 ------------------- core/fpdfdoc/doc_utils.cpp | 770 --------------- core/fpdfdoc/doc_utils.h | 79 -- core/fpdfdoc/include/cpdf_formfield.h | 1 + core/fpdfdoc/include/cpdf_interform.h | 4 + 17 files changed, 3432 insertions(+), 3479 deletions(-) create mode 100644 core/fpdfdoc/cpdf_apsettings.cpp create mode 100644 core/fpdfdoc/cpdf_defaultappearance.cpp create mode 100644 core/fpdfdoc/cpdf_formcontrol.cpp create mode 100644 core/fpdfdoc/cpdf_formfield.cpp create mode 100644 core/fpdfdoc/cpdf_iconfit.cpp create mode 100644 core/fpdfdoc/cpdf_interform.cpp create mode 100644 core/fpdfdoc/cpdf_numbertree.cpp create mode 100644 core/fpdfdoc/cpdf_numbertree.h delete mode 100644 core/fpdfdoc/doc_form.cpp delete mode 100644 core/fpdfdoc/doc_formcontrol.cpp delete mode 100644 core/fpdfdoc/doc_formfield.cpp delete mode 100644 core/fpdfdoc/doc_utils.cpp delete mode 100644 core/fpdfdoc/doc_utils.h (limited to 'core/fpdfdoc') diff --git a/core/fpdfdoc/cpdf_apsettings.cpp b/core/fpdfdoc/cpdf_apsettings.cpp new file mode 100644 index 0000000000..f2a802b445 --- /dev/null +++ b/core/fpdfdoc/cpdf_apsettings.cpp @@ -0,0 +1,119 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfdoc/cpdf_apsettings.h" + +#include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" +#include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" +#include "core/fpdfdoc/include/cpdf_formcontrol.h" + +CPDF_ApSettings::CPDF_ApSettings(CPDF_Dictionary* pDict) : m_pDict(pDict) {} + +bool CPDF_ApSettings::HasMKEntry(const CFX_ByteString& csEntry) const { + return m_pDict && m_pDict->KeyExist(csEntry); +} + +int CPDF_ApSettings::GetRotation() const { + return m_pDict ? m_pDict->GetIntegerBy("R") : 0; +} + +FX_ARGB CPDF_ApSettings::GetColor(int& iColorType, + const CFX_ByteString& csEntry) const { + iColorType = COLORTYPE_TRANSPARENT; + if (!m_pDict) + return 0; + + CPDF_Array* pEntry = m_pDict->GetArrayBy(csEntry); + if (!pEntry) + return 0; + + FX_ARGB color = 0; + size_t dwCount = pEntry->GetCount(); + if (dwCount == 1) { + iColorType = COLORTYPE_GRAY; + FX_FLOAT g = pEntry->GetNumberAt(0) * 255; + return ArgbEncode(255, (int)g, (int)g, (int)g); + } + if (dwCount == 3) { + iColorType = COLORTYPE_RGB; + FX_FLOAT r = pEntry->GetNumberAt(0) * 255; + FX_FLOAT g = pEntry->GetNumberAt(1) * 255; + FX_FLOAT b = pEntry->GetNumberAt(2) * 255; + return ArgbEncode(255, (int)r, (int)g, (int)b); + } + if (dwCount == 4) { + iColorType = COLORTYPE_CMYK; + FX_FLOAT c = pEntry->GetNumberAt(0); + FX_FLOAT m = pEntry->GetNumberAt(1); + FX_FLOAT y = pEntry->GetNumberAt(2); + FX_FLOAT k = pEntry->GetNumberAt(3); + 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); + return ArgbEncode(255, (int)(r * 255), (int)(g * 255), (int)(b * 255)); + } + return color; +} + +FX_FLOAT CPDF_ApSettings::GetOriginalColor( + int index, + const CFX_ByteString& csEntry) const { + if (!m_pDict) + return 0; + + CPDF_Array* pEntry = m_pDict->GetArrayBy(csEntry); + return pEntry ? pEntry->GetNumberAt(index) : 0; +} + +void CPDF_ApSettings::GetOriginalColor(int& iColorType, + FX_FLOAT fc[4], + const CFX_ByteString& csEntry) const { + iColorType = COLORTYPE_TRANSPARENT; + for (int i = 0; i < 4; i++) + fc[i] = 0; + + if (!m_pDict) + return; + + CPDF_Array* pEntry = m_pDict->GetArrayBy(csEntry); + if (!pEntry) + return; + + size_t dwCount = pEntry->GetCount(); + if (dwCount == 1) { + iColorType = COLORTYPE_GRAY; + fc[0] = pEntry->GetNumberAt(0); + } else if (dwCount == 3) { + iColorType = COLORTYPE_RGB; + fc[0] = pEntry->GetNumberAt(0); + fc[1] = pEntry->GetNumberAt(1); + fc[2] = pEntry->GetNumberAt(2); + } else if (dwCount == 4) { + iColorType = COLORTYPE_CMYK; + fc[0] = pEntry->GetNumberAt(0); + fc[1] = pEntry->GetNumberAt(1); + fc[2] = pEntry->GetNumberAt(2); + fc[3] = pEntry->GetNumberAt(3); + } +} + +CFX_WideString CPDF_ApSettings::GetCaption( + const CFX_ByteString& csEntry) const { + return m_pDict ? m_pDict->GetUnicodeTextBy(csEntry) : CFX_WideString(); +} + +CPDF_Stream* CPDF_ApSettings::GetIcon(const CFX_ByteString& csEntry) const { + return m_pDict ? m_pDict->GetStreamBy(csEntry) : nullptr; +} + +CPDF_IconFit CPDF_ApSettings::GetIconFit() const { + return CPDF_IconFit(m_pDict ? m_pDict->GetDictBy("IF") : nullptr); +} + +int CPDF_ApSettings::GetTextPosition() const { + return m_pDict ? m_pDict->GetIntegerBy("TP", TEXTPOS_CAPTION) + : TEXTPOS_CAPTION; +} diff --git a/core/fpdfdoc/cpdf_defaultappearance.cpp b/core/fpdfdoc/cpdf_defaultappearance.cpp new file mode 100644 index 0000000000..1c71ae5826 --- /dev/null +++ b/core/fpdfdoc/cpdf_defaultappearance.cpp @@ -0,0 +1,222 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfdoc/include/cpdf_defaultappearance.h" + +#include "core/fpdfapi/fpdf_parser/include/cpdf_simple_parser.h" +#include "core/fpdfapi/fpdf_parser/include/fpdf_parser_decode.h" +#include "core/fpdfdoc/include/cpdf_formcontrol.h" + +FX_BOOL CPDF_DefaultAppearance::HasFont() { + if (m_csDA.IsEmpty()) + return FALSE; + + CPDF_SimpleParser syntax(m_csDA.AsStringC()); + return syntax.FindTagParamFromStart("Tf", 2); +} + +CFX_ByteString CPDF_DefaultAppearance::GetFontString() { + CFX_ByteString csFont; + if (m_csDA.IsEmpty()) + return csFont; + + CPDF_SimpleParser syntax(m_csDA.AsStringC()); + if (syntax.FindTagParamFromStart("Tf", 2)) { + csFont += syntax.GetWord(); + csFont += " "; + csFont += syntax.GetWord(); + csFont += " "; + csFont += 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.AsStringC()); + 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(PaintOperation nOperation) { + if (m_csDA.IsEmpty()) + return FALSE; + + CPDF_SimpleParser syntax(m_csDA.AsStringC()); + if (syntax.FindTagParamFromStart( + (nOperation == PaintOperation::STROKE ? "G" : "g"), 1)) { + return TRUE; + } + if (syntax.FindTagParamFromStart( + (nOperation == PaintOperation::STROKE ? "RG" : "rg"), 3)) { + return TRUE; + } + return syntax.FindTagParamFromStart( + (nOperation == PaintOperation::STROKE ? "K" : "k"), 4); +} + +CFX_ByteString CPDF_DefaultAppearance::GetColorString( + PaintOperation nOperation) { + CFX_ByteString csColor; + if (m_csDA.IsEmpty()) + return csColor; + + CPDF_SimpleParser syntax(m_csDA.AsStringC()); + if (syntax.FindTagParamFromStart( + (nOperation == PaintOperation::STROKE ? "G" : "g"), 1)) { + csColor += syntax.GetWord(); + csColor += " "; + csColor += syntax.GetWord(); + return csColor; + } + if (syntax.FindTagParamFromStart( + (nOperation == PaintOperation::STROKE ? "RG" : "rg"), 3)) { + csColor += syntax.GetWord(); + csColor += " "; + csColor += syntax.GetWord(); + csColor += " "; + csColor += syntax.GetWord(); + csColor += " "; + csColor += syntax.GetWord(); + return csColor; + } + if (syntax.FindTagParamFromStart( + (nOperation == PaintOperation::STROKE ? "K" : "k"), 4)) { + csColor += syntax.GetWord(); + csColor += " "; + csColor += syntax.GetWord(); + csColor += " "; + csColor += syntax.GetWord(); + csColor += " "; + csColor += syntax.GetWord(); + csColor += " "; + csColor += syntax.GetWord(); + } + return csColor; +} + +void CPDF_DefaultAppearance::GetColor(int& iColorType, + FX_FLOAT fc[4], + PaintOperation nOperation) { + iColorType = COLORTYPE_TRANSPARENT; + for (int c = 0; c < 4; c++) + fc[c] = 0; + + if (m_csDA.IsEmpty()) + return; + + CPDF_SimpleParser syntax(m_csDA.AsStringC()); + if (syntax.FindTagParamFromStart( + (nOperation == PaintOperation::STROKE ? "G" : "g"), 1)) { + iColorType = COLORTYPE_GRAY; + fc[0] = FX_atof(syntax.GetWord()); + return; + } + if (syntax.FindTagParamFromStart( + (nOperation == PaintOperation::STROKE ? "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( + (nOperation == PaintOperation::STROKE ? "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, + PaintOperation nOperation) { + color = 0; + iColorType = COLORTYPE_TRANSPARENT; + if (m_csDA.IsEmpty()) + return; + + CPDF_SimpleParser syntax(m_csDA.AsStringC()); + if (syntax.FindTagParamFromStart( + (nOperation == PaintOperation::STROKE ? "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( + (nOperation == PaintOperation::STROKE ? "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( + (nOperation == PaintOperation::STROKE ? "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.AsStringC()); + return syntax.FindTagParamFromStart("Tm", 6); +} + +CFX_ByteString CPDF_DefaultAppearance::GetTextMatrixString() { + CFX_ByteString csTM; + if (m_csDA.IsEmpty()) + return csTM; + + CPDF_SimpleParser syntax(m_csDA.AsStringC()); + if (syntax.FindTagParamFromStart("Tm", 6)) { + for (int i = 0; i < 6; i++) { + csTM += syntax.GetWord(); + csTM += " "; + } + csTM += syntax.GetWord(); + } + return csTM; +} + +CFX_Matrix CPDF_DefaultAppearance::GetTextMatrix() { + CFX_Matrix tm; + if (m_csDA.IsEmpty()) + return tm; + + CPDF_SimpleParser syntax(m_csDA.AsStringC()); + 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; +} diff --git a/core/fpdfdoc/cpdf_formcontrol.cpp b/core/fpdfdoc/cpdf_formcontrol.cpp new file mode 100644 index 0000000000..e6c505869c --- /dev/null +++ b/core/fpdfdoc/cpdf_formcontrol.cpp @@ -0,0 +1,329 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfdoc/include/cpdf_formcontrol.h" + +#include + +#include "core/fpdfapi/fpdf_page/include/cpdf_form.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_stream.h" +#include "core/fpdfapi/fpdf_parser/include/fpdf_parser_decode.h" +#include "core/fpdfapi/fpdf_render/include/cpdf_rendercontext.h" +#include "core/fpdfdoc/include/cpdf_interform.h" + +namespace { + +const FX_CHAR* const g_sHighlightingMode[] = { + // Must match order of HighlightingMode enum. + "N", "I", "O", "P", "T"}; + +} // namespace + +CPDF_FormControl::CPDF_FormControl(CPDF_FormField* pField, + CPDF_Dictionary* pWidgetDict) + : m_pField(pField), + m_pWidgetDict(pWidgetDict), + m_pForm(m_pField->m_pForm) {} + +CFX_ByteString CPDF_FormControl::GetOnStateName() const { + ASSERT(GetType() == CPDF_FormField::CheckBox || + GetType() == CPDF_FormField::RadioButton); + CFX_ByteString csOn; + CPDF_Dictionary* pAP = m_pWidgetDict->GetDictBy("AP"); + if (!pAP) + return csOn; + + CPDF_Dictionary* pN = pAP->GetDictBy("N"); + if (!pN) + return csOn; + + for (const auto& it : *pN) { + if (it.first != "Off") + return it.first; + } + return CFX_ByteString(); +} + +void CPDF_FormControl::SetOnStateName(const CFX_ByteString& csOn) { + ASSERT(GetType() == CPDF_FormField::CheckBox || + GetType() == CPDF_FormField::RadioButton); + CFX_ByteString csValue = csOn; + if (csValue.IsEmpty()) + csValue = "Yes"; + else if (csValue == "Off") + csValue = "Yes"; + + CFX_ByteString csAS = m_pWidgetDict->GetStringBy("AS", "Off"); + if (csAS != "Off") + m_pWidgetDict->SetAtName("AS", csValue); + + CPDF_Dictionary* pAP = m_pWidgetDict->GetDictBy("AP"); + if (!pAP) + return; + + for (const auto& it : *pAP) { + CPDF_Object* pObj1 = it.second; + if (!pObj1) + continue; + + CPDF_Object* pObjDirect1 = pObj1->GetDirect(); + CPDF_Dictionary* pSubDict = pObjDirect1->AsDictionary(); + if (!pSubDict) + continue; + + auto subdict_it = pSubDict->begin(); + while (subdict_it != pSubDict->end()) { + const CFX_ByteString& csKey2 = subdict_it->first; + CPDF_Object* pObj2 = subdict_it->second; + ++subdict_it; + if (!pObj2) + continue; + if (csKey2 != "Off") { + pSubDict->ReplaceKey(csKey2, csValue); + break; + } + } + } +} + +CFX_ByteString CPDF_FormControl::GetCheckedAPState() { + ASSERT(GetType() == CPDF_FormField::CheckBox || + GetType() == CPDF_FormField::RadioButton); + CFX_ByteString csOn = GetOnStateName(); + if (GetType() == CPDF_FormField::RadioButton || + GetType() == CPDF_FormField::CheckBox) { + if (ToArray(FPDF_GetFieldAttr(m_pField->m_pDict, "Opt"))) { + int iIndex = m_pField->GetControlIndex(this); + csOn.Format("%d", iIndex); + } + } + if (csOn.IsEmpty()) + csOn = "Yes"; + return csOn; +} + +CFX_WideString CPDF_FormControl::GetExportValue() const { + ASSERT(GetType() == CPDF_FormField::CheckBox || + GetType() == CPDF_FormField::RadioButton); + CFX_ByteString csOn = GetOnStateName(); + if (GetType() == CPDF_FormField::RadioButton || + GetType() == CPDF_FormField::CheckBox) { + if (CPDF_Array* pArray = + ToArray(FPDF_GetFieldAttr(m_pField->m_pDict, "Opt"))) { + int iIndex = m_pField->GetControlIndex(this); + csOn = pArray->GetStringAt(iIndex); + } + } + if (csOn.IsEmpty()) + csOn = "Yes"; + return PDF_DecodeText(csOn); +} + +bool CPDF_FormControl::IsChecked() const { + ASSERT(GetType() == CPDF_FormField::CheckBox || + GetType() == CPDF_FormField::RadioButton); + CFX_ByteString csOn = GetOnStateName(); + CFX_ByteString csAS = m_pWidgetDict->GetStringBy("AS"); + return csAS == csOn; +} + +bool CPDF_FormControl::IsDefaultChecked() const { + ASSERT(GetType() == CPDF_FormField::CheckBox || + GetType() == CPDF_FormField::RadioButton); + CPDF_Object* pDV = FPDF_GetFieldAttr(m_pField->m_pDict, "DV"); + if (!pDV) + return FALSE; + + CFX_ByteString csDV = pDV->GetString(); + CFX_ByteString csOn = GetOnStateName(); + return (csDV == csOn); +} + +void CPDF_FormControl::CheckControl(FX_BOOL bChecked) { + ASSERT(GetType() == CPDF_FormField::CheckBox || + GetType() == CPDF_FormField::RadioButton); + CFX_ByteString csOn = GetOnStateName(); + CFX_ByteString csOldAS = m_pWidgetDict->GetStringBy("AS", "Off"); + CFX_ByteString csAS = "Off"; + if (bChecked) + csAS = csOn; + if (csOldAS == csAS) + return; + m_pWidgetDict->SetAtName("AS", csAS); +} + +void CPDF_FormControl::DrawControl(CFX_RenderDevice* pDevice, + CFX_Matrix* pMatrix, + CPDF_Page* pPage, + CPDF_Annot::AppearanceMode mode, + const CPDF_RenderOptions* pOptions) { + if (m_pWidgetDict->GetIntegerBy("F") & ANNOTFLAG_HIDDEN) + return; + + CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(m_pWidgetDict, mode); + if (!pStream) + return; + + CFX_FloatRect form_bbox = pStream->GetDict()->GetRectBy("BBox"); + CFX_Matrix form_matrix = pStream->GetDict()->GetMatrixBy("Matrix"); + form_matrix.TransformRect(form_bbox); + CFX_FloatRect arect = m_pWidgetDict->GetRectBy("Rect"); + CFX_Matrix matrix; + matrix.MatchRect(arect, form_bbox); + matrix.Concat(*pMatrix); + CPDF_Form form(m_pField->m_pForm->m_pDocument, + m_pField->m_pForm->m_pFormDict->GetDictBy("DR"), pStream); + form.ParseContent(nullptr, nullptr, nullptr); + CPDF_RenderContext context(pPage); + context.AppendLayer(&form, &matrix); + context.Render(pDevice, pOptions, nullptr); +} + +CPDF_FormControl::HighlightingMode CPDF_FormControl::GetHighlightingMode() { + if (!m_pWidgetDict) + return Invert; + + CFX_ByteString csH = m_pWidgetDict->GetStringBy("H", "I"); + for (size_t i = 0; i < FX_ArraySize(g_sHighlightingMode); ++i) { + if (csH == g_sHighlightingMode[i]) + return static_cast(i); + } + return Invert; +} + +CPDF_ApSettings CPDF_FormControl::GetMK() const { + return CPDF_ApSettings(m_pWidgetDict ? m_pWidgetDict->GetDictBy("MK") + : nullptr); +} + +bool CPDF_FormControl::HasMKEntry(const CFX_ByteString& csEntry) const { + return GetMK().HasMKEntry(csEntry); +} + +int CPDF_FormControl::GetRotation() { + return GetMK().GetRotation(); +} + +FX_ARGB CPDF_FormControl::GetColor(int& iColorType, + const CFX_ByteString& csEntry) { + return GetMK().GetColor(iColorType, csEntry); +} + +FX_FLOAT CPDF_FormControl::GetOriginalColor(int index, + const CFX_ByteString& csEntry) { + return GetMK().GetOriginalColor(index, csEntry); +} + +void CPDF_FormControl::GetOriginalColor(int& iColorType, + FX_FLOAT fc[4], + const CFX_ByteString& csEntry) { + GetMK().GetOriginalColor(iColorType, fc, csEntry); +} + +CFX_WideString CPDF_FormControl::GetCaption(const CFX_ByteString& csEntry) { + return GetMK().GetCaption(csEntry); +} + +CPDF_Stream* CPDF_FormControl::GetIcon(const CFX_ByteString& csEntry) { + return GetMK().GetIcon(csEntry); +} + +CPDF_IconFit CPDF_FormControl::GetIconFit() { + return GetMK().GetIconFit(); +} + +int CPDF_FormControl::GetTextPosition() { + return GetMK().GetTextPosition(); +} + +CPDF_Action CPDF_FormControl::GetAction() { + if (!m_pWidgetDict) + return CPDF_Action(); + + if (m_pWidgetDict->KeyExist("A")) + return CPDF_Action(m_pWidgetDict->GetDictBy("A")); + + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "A"); + if (!pObj) + return CPDF_Action(); + + return CPDF_Action(pObj->GetDict()); +} + +CPDF_AAction CPDF_FormControl::GetAdditionalAction() { + if (!m_pWidgetDict) + return CPDF_AAction(); + + if (m_pWidgetDict->KeyExist("AA")) + return CPDF_AAction(m_pWidgetDict->GetDictBy("AA")); + return m_pField->GetAdditionalAction(); +} + +CPDF_DefaultAppearance CPDF_FormControl::GetDefaultAppearance() { + if (!m_pWidgetDict) + return CPDF_DefaultAppearance(); + + if (m_pWidgetDict->KeyExist("DA")) + return CPDF_DefaultAppearance(m_pWidgetDict->GetStringBy("DA")); + + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "DA"); + if (pObj) + return CPDF_DefaultAppearance(pObj->GetString()); + return m_pField->m_pForm->GetDefaultAppearance(); +} + +CPDF_Font* CPDF_FormControl::GetDefaultControlFont() { + CPDF_DefaultAppearance cDA = GetDefaultAppearance(); + CFX_ByteString csFontNameTag; + FX_FLOAT fFontSize; + cDA.GetFont(csFontNameTag, fFontSize); + if (csFontNameTag.IsEmpty()) + return nullptr; + + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pWidgetDict, "DR"); + if (CPDF_Dictionary* pDict = ToDictionary(pObj)) { + CPDF_Dictionary* pFonts = pDict->GetDictBy("Font"); + if (pFonts) { + CPDF_Dictionary* pElement = pFonts->GetDictBy(csFontNameTag); + if (pElement) { + CPDF_Font* pFont = m_pField->m_pForm->m_pDocument->LoadFont(pElement); + if (pFont) + return pFont; + } + } + } + if (CPDF_Font* pFormFont = m_pField->m_pForm->GetFormFont(csFontNameTag)) + return pFormFont; + + CPDF_Dictionary* pPageDict = m_pWidgetDict->GetDictBy("P"); + pObj = FPDF_GetFieldAttr(pPageDict, "Resources"); + if (CPDF_Dictionary* pDict = ToDictionary(pObj)) { + CPDF_Dictionary* pFonts = pDict->GetDictBy("Font"); + if (pFonts) { + CPDF_Dictionary* pElement = pFonts->GetDictBy(csFontNameTag); + if (pElement) { + CPDF_Font* pFont = m_pField->m_pForm->m_pDocument->LoadFont(pElement); + if (pFont) + return pFont; + } + } + } + return nullptr; +} + +int CPDF_FormControl::GetControlAlignment() { + if (!m_pWidgetDict) + return 0; + if (m_pWidgetDict->KeyExist("Q")) + return m_pWidgetDict->GetIntegerBy("Q", 0); + + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "Q"); + if (pObj) + return pObj->GetInteger(); + return m_pField->m_pForm->GetFormAlignment(); +} diff --git a/core/fpdfdoc/cpdf_formfield.cpp b/core/fpdfdoc/cpdf_formfield.cpp new file mode 100644 index 0000000000..81d2178820 --- /dev/null +++ b/core/fpdfdoc/cpdf_formfield.cpp @@ -0,0 +1,997 @@ +// 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/include/cpdf_formfield.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_number.h" +#include "core/fpdfapi/fpdf_parser/include/cpdf_simple_parser.h" +#include "core/fpdfapi/fpdf_parser/include/cpdf_string.h" +#include "core/fpdfapi/fpdf_parser/include/fpdf_parser_decode.h" +#include "core/fpdfdoc/cpvt_generateap.h" +#include "core/fpdfdoc/include/cpdf_formcontrol.h" +#include "core/fpdfdoc/include/cpdf_interform.h" + +namespace { + +const int kMaxRecursion = 32; + +const int kFormListMultiSelect = 0x100; + +const int kFormComboEdit = 0x100; + +const int kFormFieldReadOnly = 0x01; +const int kFormFieldRequired = 0x02; +const int kFormFieldNoExport = 0x04; + +const int kFormRadioNoToggleOff = 0x100; +const int kFormRadioUnison = 0x200; + +const int kFormTextMultiLine = 0x100; +const int kFormTextPassword = 0x200; +const int kFormTextNoScroll = 0x400; +const int kFormTextComb = 0x800; + +bool IsUnison(CPDF_FormField* pField) { + if (pField->GetType() == CPDF_FormField::CheckBox) + return true; + return (pField->GetFieldFlags() & 0x2000000) != 0; +} + +} // namespace + +CPDF_Object* FPDF_GetFieldAttr(CPDF_Dictionary* pFieldDict, + const FX_CHAR* name, + int nLevel) { + if (nLevel > kMaxRecursion) + return nullptr; + if (!pFieldDict) + return nullptr; + + CPDF_Object* pAttr = pFieldDict->GetDirectObjectBy(name); + if (pAttr) + return pAttr; + + CPDF_Dictionary* pParent = pFieldDict->GetDictBy("Parent"); + if (!pParent) + return nullptr; + return FPDF_GetFieldAttr(pParent, name, nLevel + 1); +} + +CFX_WideString FPDF_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; +} + +CPDF_FormField::CPDF_FormField(CPDF_InterForm* pForm, CPDF_Dictionary* pDict) + : m_Type(Unknown), + m_pForm(pForm), + m_pDict(pDict), + m_FontSize(0), + m_pFont(nullptr) { + SyncFieldFlags(); +} + +CPDF_FormField::~CPDF_FormField() {} + +void CPDF_FormField::SyncFieldFlags() { + CFX_ByteString type_name = FPDF_GetFieldAttr(m_pDict, "FT") + ? FPDF_GetFieldAttr(m_pDict, "FT")->GetString() + : CFX_ByteString(); + uint32_t flags = FPDF_GetFieldAttr(m_pDict, "Ff") + ? FPDF_GetFieldAttr(m_pDict, "Ff")->GetInteger() + : 0; + m_Flags = 0; + if (flags & 1) + m_Flags |= kFormFieldReadOnly; + if (flags & 2) + m_Flags |= kFormFieldRequired; + if (flags & 4) + m_Flags |= kFormFieldNoExport; + + if (type_name == "Btn") { + if (flags & 0x8000) { + m_Type = RadioButton; + if (flags & 0x4000) + m_Flags |= kFormRadioNoToggleOff; + if (flags & 0x2000000) + m_Flags |= kFormRadioUnison; + } else if (flags & 0x10000) { + m_Type = PushButton; + } else { + m_Type = CheckBox; + } + } else if (type_name == "Tx") { + if (flags & 0x100000) { + m_Type = File; + } else if (flags & 0x2000000) { + m_Type = RichText; + } else { + m_Type = Text; + if (flags & 0x1000) + m_Flags |= kFormTextMultiLine; + if (flags & 0x2000) + m_Flags |= kFormTextPassword; + if (flags & 0x800000) + m_Flags |= kFormTextNoScroll; + if (flags & 0x100000) + m_Flags |= kFormTextComb; + } + LoadDA(); + } else if (type_name == "Ch") { + if (flags & 0x20000) { + m_Type = ComboBox; + if (flags & 0x40000) + m_Flags |= kFormComboEdit; + } else { + m_Type = ListBox; + if (flags & 0x200000) + m_Flags |= kFormListMultiSelect; + } + LoadDA(); + } else if (type_name == "Sig") { + m_Type = Sign; + } +} + +CFX_WideString CPDF_FormField::GetFullName() const { + return FPDF_GetFullName(m_pDict); +} + +FX_BOOL CPDF_FormField::ResetField(FX_BOOL bNotify) { + switch (m_Type) { + case CPDF_FormField::CheckBox: + case CPDF_FormField::RadioButton: { + int iCount = CountControls(); + if (iCount) { + // TODO(weili): Check whether anything special needs to be done for + // unison field. Otherwise, merge these branches. + if (IsUnison(this)) { + for (int i = 0; i < iCount; i++) + CheckControl(i, GetControl(i)->IsDefaultChecked(), FALSE); + } else { + for (int i = 0; i < iCount; i++) + CheckControl(i, GetControl(i)->IsDefaultChecked(), FALSE); + } + } + if (bNotify && m_pForm->m_pFormNotify) + m_pForm->m_pFormNotify->AfterCheckedStatusChange(this); + break; + } + case CPDF_FormField::ComboBox: + case CPDF_FormField::ListBox: { + CFX_WideString csValue; + ClearSelection(); + int iIndex = GetDefaultSelectedItem(); + if (iIndex >= 0) + csValue = GetOptionLabel(iIndex); + + if (bNotify && !NotifyListOrComboBoxBeforeChange(csValue)) + return FALSE; + + SetItemSelection(iIndex, TRUE); + if (bNotify) + NotifyListOrComboBoxAfterChange(); + break; + } + case CPDF_FormField::Text: + case CPDF_FormField::RichText: + case CPDF_FormField::File: + default: { + CPDF_Object* pDV = FPDF_GetFieldAttr(m_pDict, "DV"); + CFX_WideString csDValue; + if (pDV) + csDValue = pDV->GetUnicodeText(); + + CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V"); + CFX_WideString csValue; + if (pV) + csValue = pV->GetUnicodeText(); + + CPDF_Object* pRV = FPDF_GetFieldAttr(m_pDict, "RV"); + if (!pRV && (csDValue == csValue)) + return FALSE; + + if (bNotify && !NotifyBeforeValueChange(csDValue)) + return FALSE; + + if (pDV) { + CPDF_Object* pClone = pDV->Clone(); + if (!pClone) + return FALSE; + + m_pDict->SetAt("V", pClone); + if (pRV) { + CPDF_Object* pCloneR = pDV->Clone(); + m_pDict->SetAt("RV", pCloneR); + } + } else { + m_pDict->RemoveAt("V"); + m_pDict->RemoveAt("RV"); + } + if (bNotify) + NotifyAfterValueChange(); + break; + } + } + return TRUE; +} + +int CPDF_FormField::GetControlIndex(const CPDF_FormControl* pControl) const { + if (!pControl) + return -1; + + for (int i = 0; i < m_ControlList.GetSize(); i++) { + if (m_ControlList.GetAt(i) == pControl) + return i; + } + return -1; +} + +int CPDF_FormField::GetFieldType() const { + switch (m_Type) { + case PushButton: + return FIELDTYPE_PUSHBUTTON; + case CheckBox: + return FIELDTYPE_CHECKBOX; + case RadioButton: + return FIELDTYPE_RADIOBUTTON; + case ComboBox: + return FIELDTYPE_COMBOBOX; + case ListBox: + return FIELDTYPE_LISTBOX; + case Text: + case RichText: + case File: + return FIELDTYPE_TEXTFIELD; + case Sign: + return FIELDTYPE_SIGNATURE; + default: + break; + } + return FIELDTYPE_UNKNOWN; +} + +CPDF_AAction CPDF_FormField::GetAdditionalAction() const { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "AA"); + return CPDF_AAction(pObj ? pObj->GetDict() : nullptr); +} + +CFX_WideString CPDF_FormField::GetAlternateName() const { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TU"); + return pObj ? pObj->GetUnicodeText() : L""; +} + +CFX_WideString CPDF_FormField::GetMappingName() const { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TM"); + return pObj ? pObj->GetUnicodeText() : L""; +} + +uint32_t CPDF_FormField::GetFieldFlags() const { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "Ff"); + return pObj ? pObj->GetInteger() : 0; +} + +CFX_ByteString CPDF_FormField::GetDefaultStyle() const { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "DS"); + return pObj ? pObj->GetString() : ""; +} + +CFX_WideString CPDF_FormField::GetRichTextString() const { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "RV"); + return pObj ? pObj->GetUnicodeText() : L""; +} + +CFX_WideString CPDF_FormField::GetValue(FX_BOOL bDefault) const { + if (GetType() == CheckBox || GetType() == RadioButton) + return GetCheckValue(bDefault); + + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, bDefault ? "DV" : "V"); + if (!pValue) { + if (!bDefault) { + if (m_Type == RichText) + pValue = FPDF_GetFieldAttr(m_pDict, "V"); + if (!pValue && m_Type != Text) + pValue = FPDF_GetFieldAttr(m_pDict, "DV"); + } + if (!pValue) + return CFX_WideString(); + } + + switch (pValue->GetType()) { + case CPDF_Object::STRING: + case CPDF_Object::STREAM: + return pValue->GetUnicodeText(); + case CPDF_Object::ARRAY: + pValue = pValue->AsArray()->GetDirectObjectAt(0); + if (pValue) + return pValue->GetUnicodeText(); + break; + default: + break; + } + return CFX_WideString(); +} + +CFX_WideString CPDF_FormField::GetValue() const { + return GetValue(FALSE); +} + +CFX_WideString CPDF_FormField::GetDefaultValue() const { + return GetValue(TRUE); +} + +FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, + FX_BOOL bDefault, + FX_BOOL bNotify) { + switch (m_Type) { + case CheckBox: + case RadioButton: { + SetCheckValue(value, bDefault, bNotify); + return TRUE; + } + case File: + case RichText: + case Text: + case ComboBox: { + CFX_WideString csValue = value; + if (bNotify && !NotifyBeforeValueChange(csValue)) + return FALSE; + + int iIndex = FindOptionValue(csValue); + if (iIndex < 0) { + CFX_ByteString bsEncodeText = PDF_EncodeText(csValue); + m_pDict->SetAtString(bDefault ? "DV" : "V", bsEncodeText); + if (m_Type == RichText && !bDefault) + m_pDict->SetAtString("RV", bsEncodeText); + m_pDict->RemoveAt("I"); + } else { + m_pDict->SetAtString(bDefault ? "DV" : "V", PDF_EncodeText(csValue)); + if (!bDefault) { + ClearSelection(); + SetItemSelection(iIndex, TRUE); + } + } + if (bNotify) + NotifyAfterValueChange(); + break; + } + case ListBox: { + int iIndex = FindOptionValue(value); + if (iIndex < 0) + return FALSE; + + if (bDefault && iIndex == GetDefaultSelectedItem()) + return FALSE; + + if (bNotify && !NotifyBeforeSelectionChange(value)) + return FALSE; + + if (!bDefault) { + ClearSelection(); + SetItemSelection(iIndex, TRUE); + } + if (bNotify) + NotifyAfterSelectionChange(); + break; + } + default: + break; + } + return TRUE; +} + +FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, FX_BOOL bNotify) { + return SetValue(value, FALSE, bNotify); +} + +int CPDF_FormField::GetMaxLen() const { + if (CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "MaxLen")) + return pObj->GetInteger(); + + for (int i = 0; i < m_ControlList.GetSize(); i++) { + CPDF_FormControl* pControl = m_ControlList.GetAt(i); + if (!pControl) + continue; + + CPDF_Dictionary* pWidgetDict = pControl->m_pWidgetDict; + if (pWidgetDict->KeyExist("MaxLen")) + return pWidgetDict->GetIntegerBy("MaxLen"); + } + return 0; +} + +int CPDF_FormField::CountSelectedItems() const { + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); + if (!pValue) { + pValue = FPDF_GetFieldAttr(m_pDict, "I"); + if (!pValue) + return 0; + } + + if (pValue->IsString() || pValue->IsNumber()) + return pValue->GetString().IsEmpty() ? 0 : 1; + if (CPDF_Array* pArray = pValue->AsArray()) + return pArray->GetCount(); + return 0; +} + +int CPDF_FormField::GetSelectedIndex(int index) const { + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); + if (!pValue) { + pValue = FPDF_GetFieldAttr(m_pDict, "I"); + if (!pValue) + return -1; + } + if (pValue->IsNumber()) + return pValue->GetInteger(); + + CFX_WideString sel_value; + if (pValue->IsString()) { + if (index != 0) + return -1; + sel_value = pValue->GetUnicodeText(); + } else { + CPDF_Array* pArray = pValue->AsArray(); + if (!pArray || index < 0) + return -1; + + CPDF_Object* elementValue = pArray->GetDirectObjectAt(index); + sel_value = + elementValue ? elementValue->GetUnicodeText() : CFX_WideString(); + } + if (index < CountSelectedOptions()) { + int iOptIndex = GetSelectedOptionIndex(index); + CFX_WideString csOpt = GetOptionValue(iOptIndex); + if (csOpt == sel_value) + return iOptIndex; + } + for (int i = 0; i < CountOptions(); i++) { + if (sel_value == GetOptionValue(i)) + return i; + } + return -1; +} + +FX_BOOL CPDF_FormField::ClearSelection(FX_BOOL bNotify) { + if (bNotify && m_pForm->m_pFormNotify) { + CFX_WideString csValue; + int iIndex = GetSelectedIndex(0); + if (iIndex >= 0) + csValue = GetOptionLabel(iIndex); + + if (!NotifyListOrComboBoxBeforeChange(csValue)) + return FALSE; + } + m_pDict->RemoveAt("V"); + m_pDict->RemoveAt("I"); + if (bNotify) + NotifyListOrComboBoxAfterChange(); + return TRUE; +} + +FX_BOOL CPDF_FormField::IsItemSelected(int index) const { + ASSERT(GetType() == ComboBox || GetType() == ListBox); + if (index < 0 || index >= CountOptions()) + return FALSE; + if (IsOptionSelected(index)) + return TRUE; + + CFX_WideString opt_value = GetOptionValue(index); + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); + if (!pValue) { + pValue = FPDF_GetFieldAttr(m_pDict, "I"); + if (!pValue) + return FALSE; + } + + if (pValue->IsString()) + return pValue->GetUnicodeText() == opt_value; + + if (pValue->IsNumber()) { + if (pValue->GetString().IsEmpty()) + return FALSE; + return (pValue->GetInteger() == index); + } + + CPDF_Array* pArray = pValue->AsArray(); + if (!pArray) + return FALSE; + + int iPos = -1; + for (int j = 0; j < CountSelectedOptions(); j++) { + if (GetSelectedOptionIndex(j) == index) { + iPos = j; + break; + } + } + for (int i = 0; i < static_cast(pArray->GetCount()); i++) + if (pArray->GetDirectObjectAt(i)->GetUnicodeText() == opt_value && + i == iPos) { + return TRUE; + } + return FALSE; +} + +FX_BOOL CPDF_FormField::SetItemSelection(int index, + FX_BOOL bSelected, + FX_BOOL bNotify) { + ASSERT(GetType() == ComboBox || GetType() == ListBox); + if (index < 0 || index >= CountOptions()) + return FALSE; + + CFX_WideString opt_value = GetOptionValue(index); + if (bNotify && !NotifyListOrComboBoxBeforeChange(opt_value)) + return FALSE; + + if (bSelected) { + if (GetType() == ListBox) { + SelectOption(index, TRUE); + if (!(m_Flags & kFormListMultiSelect)) { + m_pDict->SetAtString("V", PDF_EncodeText(opt_value)); + } else { + CPDF_Array* pArray = new CPDF_Array; + for (int i = 0; i < CountOptions(); i++) { + if (i == index || IsItemSelected(i)) { + opt_value = GetOptionValue(i); + pArray->AddString(PDF_EncodeText(opt_value)); + } + } + m_pDict->SetAt("V", pArray); + } + } else { + m_pDict->SetAtString("V", PDF_EncodeText(opt_value)); + CPDF_Array* pI = new CPDF_Array; + pI->AddInteger(index); + m_pDict->SetAt("I", pI); + } + } else { + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); + if (pValue) { + if (GetType() == ListBox) { + SelectOption(index, FALSE); + if (pValue->IsString()) { + if (pValue->GetUnicodeText() == opt_value) + m_pDict->RemoveAt("V"); + } else if (pValue->IsArray()) { + CPDF_Array* pArray = new CPDF_Array; + for (int i = 0; i < CountOptions(); i++) { + if (i != index && IsItemSelected(i)) { + opt_value = GetOptionValue(i); + pArray->AddString(PDF_EncodeText(opt_value)); + } + } + if (pArray->GetCount() < 1) + pArray->Release(); + else + m_pDict->SetAt("V", pArray); + } + } else { + m_pDict->RemoveAt("V"); + m_pDict->RemoveAt("I"); + } + } + } + if (bNotify) + NotifyListOrComboBoxAfterChange(); + return TRUE; +} + +FX_BOOL CPDF_FormField::IsItemDefaultSelected(int index) const { + ASSERT(GetType() == ComboBox || GetType() == ListBox); + if (index < 0 || index >= CountOptions()) + return FALSE; + int iDVIndex = GetDefaultSelectedItem(); + return iDVIndex >= 0 && iDVIndex == index; +} + +int CPDF_FormField::GetDefaultSelectedItem() const { + ASSERT(GetType() == ComboBox || GetType() == ListBox); + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "DV"); + if (!pValue) + return -1; + CFX_WideString csDV = pValue->GetUnicodeText(); + if (csDV.IsEmpty()) + return -1; + for (int i = 0; i < CountOptions(); i++) { + if (csDV == GetOptionValue(i)) + return i; + } + return -1; +} + +int CPDF_FormField::CountOptions() const { + CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt")); + return pArray ? pArray->GetCount() : 0; +} + +CFX_WideString CPDF_FormField::GetOptionText(int index, int sub_index) const { + CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt")); + if (!pArray) + return CFX_WideString(); + + CPDF_Object* pOption = pArray->GetDirectObjectAt(index); + if (!pOption) + return CFX_WideString(); + if (CPDF_Array* pOptionArray = pOption->AsArray()) + pOption = pOptionArray->GetDirectObjectAt(sub_index); + + CPDF_String* pString = ToString(pOption); + return pString ? pString->GetUnicodeText() : CFX_WideString(); +} + +CFX_WideString CPDF_FormField::GetOptionLabel(int index) const { + return GetOptionText(index, 1); +} + +CFX_WideString CPDF_FormField::GetOptionValue(int index) const { + return GetOptionText(index, 0); +} + +int CPDF_FormField::FindOption(CFX_WideString csOptLabel) const { + for (int i = 0; i < CountOptions(); i++) { + if (GetOptionValue(i) == csOptLabel) + return i; + } + return -1; +} + +int CPDF_FormField::FindOptionValue(const CFX_WideString& csOptValue) const { + for (int i = 0; i < CountOptions(); i++) { + if (GetOptionValue(i) == csOptValue) + return i; + } + return -1; +} + +#ifdef PDF_ENABLE_XFA +int CPDF_FormField::InsertOption(CFX_WideString csOptLabel, + int index, + FX_BOOL bNotify) { + if (csOptLabel.IsEmpty()) + return -1; + + if (bNotify && !NotifyListOrComboBoxBeforeChange(csOptLabel)) + return -1; + + CFX_ByteString csStr = + PDF_EncodeText(csOptLabel.c_str(), csOptLabel.GetLength()); + CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt"); + CPDF_Array* pOpt = ToArray(pValue); + if (!pOpt) { + pOpt = new CPDF_Array; + m_pDict->SetAt("Opt", pOpt); + } + + int iCount = (int)pOpt->GetCount(); + if (index < 0 || index >= iCount) { + pOpt->AddString(csStr); + index = iCount; + } else { + CPDF_String* pString = new CPDF_String(csStr, FALSE); + pOpt->InsertAt(index, pString); + } + + if (bNotify) + NotifyListOrComboBoxAfterChange(); + return index; +} + +FX_BOOL CPDF_FormField::ClearOptions(FX_BOOL bNotify) { + if (bNotify && m_pForm->m_pFormNotify) { + CFX_WideString csValue; + int iIndex = GetSelectedIndex(0); + if (iIndex >= 0) + csValue = GetOptionLabel(iIndex); + if (!NotifyListOrComboBoxBeforeChange(csValue)) + return FALSE; + } + + m_pDict->RemoveAt("Opt"); + m_pDict->RemoveAt("V"); + m_pDict->RemoveAt("DV"); + m_pDict->RemoveAt("I"); + m_pDict->RemoveAt("TI"); + + if (bNotify) + NotifyListOrComboBoxAfterChange(); + + return TRUE; +} +#endif // PDF_ENABLE_XFA + +FX_BOOL CPDF_FormField::CheckControl(int iControlIndex, + bool bChecked, + bool bNotify) { + ASSERT(GetType() == CheckBox || GetType() == RadioButton); + CPDF_FormControl* pControl = GetControl(iControlIndex); + if (!pControl) + return FALSE; + if (!bChecked && pControl->IsChecked() == bChecked) + return FALSE; + + CFX_WideString csWExport = pControl->GetExportValue(); + CFX_ByteString csBExport = PDF_EncodeText(csWExport); + int iCount = CountControls(); + bool bUnison = IsUnison(this); + for (int i = 0; i < iCount; i++) { + CPDF_FormControl* pCtrl = GetControl(i); + if (bUnison) { + CFX_WideString csEValue = pCtrl->GetExportValue(); + if (csEValue == csWExport) { + if (pCtrl->GetOnStateName() == pControl->GetOnStateName()) + pCtrl->CheckControl(bChecked); + else if (bChecked) + pCtrl->CheckControl(FALSE); + } else if (bChecked) { + pCtrl->CheckControl(FALSE); + } + } else { + if (i == iControlIndex) + pCtrl->CheckControl(bChecked); + else if (bChecked) + pCtrl->CheckControl(FALSE); + } + } + + CPDF_Object* pOpt = FPDF_GetFieldAttr(m_pDict, "Opt"); + if (!ToArray(pOpt)) { + if (bChecked) { + m_pDict->SetAtName("V", csBExport); + } else { + CFX_ByteString csV; + CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V"); + if (pV) + csV = pV->GetString(); + if (csV == csBExport) + m_pDict->SetAtName("V", "Off"); + } + } else if (bChecked) { + CFX_ByteString csIndex; + csIndex.Format("%d", iControlIndex); + m_pDict->SetAtName("V", csIndex); + } + if (bNotify && m_pForm->m_pFormNotify) + m_pForm->m_pFormNotify->AfterCheckedStatusChange(this); + return TRUE; +} + +CFX_WideString CPDF_FormField::GetCheckValue(FX_BOOL bDefault) const { + ASSERT(GetType() == CheckBox || GetType() == RadioButton); + CFX_WideString csExport = L"Off"; + int iCount = CountControls(); + for (int i = 0; i < iCount; i++) { + CPDF_FormControl* pControl = GetControl(i); + FX_BOOL bChecked = + bDefault ? pControl->IsDefaultChecked() : pControl->IsChecked(); + if (bChecked) { + csExport = pControl->GetExportValue(); + break; + } + } + return csExport; +} + +FX_BOOL CPDF_FormField::SetCheckValue(const CFX_WideString& value, + FX_BOOL bDefault, + FX_BOOL bNotify) { + ASSERT(GetType() == CheckBox || GetType() == RadioButton); + int iCount = CountControls(); + for (int i = 0; i < iCount; i++) { + CPDF_FormControl* pControl = GetControl(i); + CFX_WideString csExport = pControl->GetExportValue(); + bool val = csExport == value; + if (!bDefault) + CheckControl(GetControlIndex(pControl), val); + if (val) + break; + } + if (bNotify && m_pForm->m_pFormNotify) + m_pForm->m_pFormNotify->AfterCheckedStatusChange(this); + return TRUE; +} + +int CPDF_FormField::GetTopVisibleIndex() const { + CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TI"); + return pObj ? pObj->GetInteger() : 0; +} + +int CPDF_FormField::CountSelectedOptions() const { + CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I")); + return pArray ? pArray->GetCount() : 0; +} + +int CPDF_FormField::GetSelectedOptionIndex(int index) const { + CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I")); + if (!pArray) + return -1; + + int iCount = pArray->GetCount(); + if (iCount < 0 || index >= iCount) + return -1; + return pArray->GetIntegerAt(index); +} + +FX_BOOL CPDF_FormField::IsOptionSelected(int iOptIndex) const { + CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I")); + if (!pArray) + return FALSE; + + for (CPDF_Object* pObj : *pArray) { + if (pObj->GetInteger() == iOptIndex) + return TRUE; + } + return FALSE; +} + +FX_BOOL CPDF_FormField::SelectOption(int iOptIndex, + FX_BOOL bSelected, + FX_BOOL bNotify) { + CPDF_Array* pArray = m_pDict->GetArrayBy("I"); + if (!pArray) { + if (!bSelected) + return TRUE; + + pArray = new CPDF_Array; + m_pDict->SetAt("I", pArray); + } + + FX_BOOL bReturn = FALSE; + for (size_t i = 0; i < pArray->GetCount(); i++) { + int iFind = pArray->GetIntegerAt(i); + if (iFind == iOptIndex) { + if (bSelected) + return TRUE; + + if (bNotify && m_pForm->m_pFormNotify) { + CFX_WideString csValue = GetOptionLabel(iOptIndex); + if (!NotifyListOrComboBoxBeforeChange(csValue)) + return FALSE; + } + pArray->RemoveAt(i); + bReturn = TRUE; + break; + } + + if (iFind > iOptIndex) { + if (!bSelected) + continue; + + if (bNotify && m_pForm->m_pFormNotify) { + CFX_WideString csValue = GetOptionLabel(iOptIndex); + if (!NotifyListOrComboBoxBeforeChange(csValue)) + return FALSE; + } + pArray->InsertAt(i, new CPDF_Number(iOptIndex)); + bReturn = TRUE; + break; + } + } + if (!bReturn) { + if (bSelected) + pArray->AddInteger(iOptIndex); + + if (pArray->GetCount() == 0) + m_pDict->RemoveAt("I"); + } + if (bNotify) + NotifyListOrComboBoxAfterChange(); + + return TRUE; +} + +FX_BOOL CPDF_FormField::ClearSelectedOptions(FX_BOOL bNotify) { + if (bNotify && m_pForm->m_pFormNotify) { + CFX_WideString csValue; + int iIndex = GetSelectedIndex(0); + if (iIndex >= 0) + csValue = GetOptionLabel(iIndex); + + if (!NotifyListOrComboBoxBeforeChange(csValue)) + return FALSE; + } + m_pDict->RemoveAt("I"); + if (bNotify) + NotifyListOrComboBoxAfterChange(); + + return TRUE; +} + +void CPDF_FormField::LoadDA() { + CPDF_Dictionary* pFormDict = m_pForm->m_pFormDict; + if (!pFormDict) + return; + + CFX_ByteString DA; + if (CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "DA")) + DA = pObj->GetString(); + + if (DA.IsEmpty()) + DA = pFormDict->GetStringBy("DA"); + + if (DA.IsEmpty()) + return; + + CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); + if (!pDR) + return; + + CPDF_Dictionary* pFont = pDR->GetDictBy("Font"); + if (!pFont) + return; + + CPDF_SimpleParser syntax(DA.AsStringC()); + syntax.FindTagParamFromStart("Tf", 2); + CFX_ByteString font_name(syntax.GetWord()); + CPDF_Dictionary* pFontDict = pFont->GetDictBy(font_name); + if (!pFontDict) + return; + + m_pFont = m_pForm->m_pDocument->LoadFont(pFontDict); + m_FontSize = FX_atof(syntax.GetWord()); +} + +bool CPDF_FormField::NotifyBeforeSelectionChange(const CFX_WideString& value) { + if (!m_pForm->m_pFormNotify) + return true; + return m_pForm->m_pFormNotify->BeforeSelectionChange(this, value) >= 0; +} + +void CPDF_FormField::NotifyAfterSelectionChange() { + if (!m_pForm->m_pFormNotify) + return; + m_pForm->m_pFormNotify->AfterSelectionChange(this); +} + +bool CPDF_FormField::NotifyBeforeValueChange(const CFX_WideString& value) { + if (!m_pForm->m_pFormNotify) + return true; + return m_pForm->m_pFormNotify->BeforeValueChange(this, value) >= 0; +} + +void CPDF_FormField::NotifyAfterValueChange() { + if (!m_pForm->m_pFormNotify) + return; + m_pForm->m_pFormNotify->AfterValueChange(this); +} + +bool CPDF_FormField::NotifyListOrComboBoxBeforeChange( + const CFX_WideString& value) { + switch (GetType()) { + case ListBox: + return NotifyBeforeSelectionChange(value); + case ComboBox: + return NotifyBeforeValueChange(value); + default: + return true; + } +} + +void CPDF_FormField::NotifyListOrComboBoxAfterChange() { + switch (GetType()) { + case ListBox: + NotifyAfterSelectionChange(); + break; + case ComboBox: + NotifyAfterValueChange(); + break; + default: + break; + } +} diff --git a/core/fpdfdoc/cpdf_iconfit.cpp b/core/fpdfdoc/cpdf_iconfit.cpp new file mode 100644 index 0000000000..3b3a09a54b --- /dev/null +++ b/core/fpdfdoc/cpdf_iconfit.cpp @@ -0,0 +1,48 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfdoc/include/cpdf_iconfit.h" + +#include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" +#include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" +#include "core/fxcrt/include/fx_string.h" + +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() { + return m_pDict ? m_pDict->GetStringBy("S", "P") != "A" : TRUE; +} + +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); + } +} + +bool CPDF_IconFit::GetFittingBounds() { + return m_pDict ? m_pDict->GetBooleanBy("FB") : false; +} diff --git a/core/fpdfdoc/cpdf_interform.cpp b/core/fpdfdoc/cpdf_interform.cpp new file mode 100644 index 0000000000..cf728a7d4b --- /dev/null +++ b/core/fpdfdoc/cpdf_interform.cpp @@ -0,0 +1,1635 @@ +// 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 + +#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 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(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& 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* 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 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& 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; +} diff --git a/core/fpdfdoc/cpdf_numbertree.cpp b/core/fpdfdoc/cpdf_numbertree.cpp new file mode 100644 index 0000000000..9e2881f414 --- /dev/null +++ b/core/fpdfdoc/cpdf_numbertree.cpp @@ -0,0 +1,52 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfdoc/cpdf_numbertree.h" + +#include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" +#include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" + +namespace { + +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 nullptr; + } + CPDF_Array* pNumbers = pNode->GetArrayBy("Nums"); + if (pNumbers) { + for (size_t i = 0; i < pNumbers->GetCount() / 2; i++) { + int index = pNumbers->GetIntegerAt(i * 2); + if (num == index) + return pNumbers->GetDirectObjectAt(i * 2 + 1); + if (index > num) + break; + } + return nullptr; + } + + CPDF_Array* pKids = pNode->GetArrayBy("Kids"); + if (!pKids) + return nullptr; + + for (size_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 nullptr; +} + +} // namespace + +CPDF_Object* CPDF_NumberTree::LookupValue(int num) const { + return SearchNumberNode(m_pRoot, num); +} diff --git a/core/fpdfdoc/cpdf_numbertree.h b/core/fpdfdoc/cpdf_numbertree.h new file mode 100644 index 0000000000..bfe44fddb9 --- /dev/null +++ b/core/fpdfdoc/cpdf_numbertree.h @@ -0,0 +1,23 @@ +// 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 + +#ifndef CORE_FPDFDOC_CPDF_NUMBERTREE_H_ +#define CORE_FPDFDOC_CPDF_NUMBERTREE_H_ + +class CPDF_Dictionary; +class CPDF_Object; + +class CPDF_NumberTree { + public: + explicit CPDF_NumberTree(CPDF_Dictionary* pRoot) : m_pRoot(pRoot) {} + + CPDF_Object* LookupValue(int num) const; + + protected: + CPDF_Dictionary* const m_pRoot; +}; + +#endif // CORE_FPDFDOC_CPDF_NUMBERTREE_H_ diff --git a/core/fpdfdoc/cpdf_pagelabel.cpp b/core/fpdfdoc/cpdf_pagelabel.cpp index 886e8448b2..4b888b9a61 100644 --- a/core/fpdfdoc/cpdf_pagelabel.cpp +++ b/core/fpdfdoc/cpdf_pagelabel.cpp @@ -9,7 +9,7 @@ #include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_document.h" #include "core/fpdfapi/fpdf_parser/include/fpdf_parser_decode.h" -#include "core/fpdfdoc/doc_utils.h" +#include "core/fpdfdoc/cpdf_numbertree.h" namespace { diff --git a/core/fpdfdoc/cpvt_fontmap.cpp b/core/fpdfdoc/cpvt_fontmap.cpp index 35a56f811d..ea4aad96d3 100644 --- a/core/fpdfdoc/cpvt_fontmap.cpp +++ b/core/fpdfdoc/cpvt_fontmap.cpp @@ -9,7 +9,7 @@ #include "core/fpdfapi/fpdf_font/include/cpdf_font.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" #include "core/fpdfapi/fpdf_parser/include/cpdf_document.h" -#include "core/fpdfdoc/doc_utils.h" +#include "core/fpdfdoc/include/cpdf_interform.h" CPVT_FontMap::CPVT_FontMap(CPDF_Document* pDoc, CPDF_Dictionary* pResDict, diff --git a/core/fpdfdoc/doc_form.cpp b/core/fpdfdoc/doc_form.cpp deleted file mode 100644 index 3dde448a24..0000000000 --- a/core/fpdfdoc/doc_form.cpp +++ /dev/null @@ -1,1203 +0,0 @@ -// 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 - -#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/fpdfdoc/doc_utils.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 FPDFDOC_FDF_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()); -} - -} // namespace - -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; -}; - -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, *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, *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, *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_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; -} -#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_ -typedef struct PDF_FONTDATA_ { - FX_BOOL bFind; - LOGFONTA lf; -} PDF_FONTDATA, FAR* LPDF_FONTDATA; -static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEXA* lpelfe, - NEWTEXTMETRICEX* lpntme, - DWORD FontType, - LPARAM lParam) { - if (FontType != 0x004 || strchr(lpelfe->elfLogFont.lfFaceName, '@')) { - return 1; - } - LPDF_FONTDATA pData = (LPDF_FONTDATA)lParam; - memcpy(&pData->lf, &lpelfe->elfLogFont, sizeof(LOGFONTA)); - pData->bFind = TRUE; - return 0; -} -static 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; -} -static 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_ - -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 -} - -// 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_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 = 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(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 CountInterFormFonts(m_pFormDict); -} - -CPDF_Font* CPDF_InterForm::GetFormFont(uint32_t index, - CFX_ByteString& csNameTag) { - return GetInterFormFont(m_pFormDict, m_pDocument, index, csNameTag); -} -CPDF_Font* CPDF_InterForm::GetFormFont(CFX_ByteString csNameTag) { - return GetInterFormFont(m_pFormDict, m_pDocument, csNameTag); -} -CPDF_Font* CPDF_InterForm::GetFormFont(CFX_ByteString csFontName, - CFX_ByteString& csNameTag) { - return GetInterFormFont(m_pFormDict, m_pDocument, csFontName, csNameTag); -} -CPDF_Font* CPDF_InterForm::GetNativeFormFont(uint8_t charSet, - CFX_ByteString& csNameTag) { - return GetNativeInterFormFont(m_pFormDict, m_pDocument, charSet, csNameTag); -} -CPDF_Font* CPDF_InterForm::GetNativeFormFont(CFX_ByteString& csNameTag) { - return GetNativeInterFormFont(m_pFormDict, m_pDocument, csNameTag); -} -FX_BOOL CPDF_InterForm::FindFormFont(const CPDF_Font* pFont, - CFX_ByteString& csNameTag) { - return FindInterFormFont(m_pFormDict, pFont, csNameTag); -} -FX_BOOL CPDF_InterForm::FindFormFont(CFX_ByteString csFontName, - CPDF_Font*& pFont, - CFX_ByteString& csNameTag) { - return FindInterFormFont(m_pFormDict, m_pDocument, csFontName, pFont, - csNameTag); -} -void CPDF_InterForm::AddFormFont(const CPDF_Font* pFont, - CFX_ByteString& csNameTag) { - AddInterFormFont(m_pFormDict, m_pDocument, pFont, csNameTag); -} - -CPDF_Font* CPDF_InterForm::AddNativeFormFont(uint8_t charSet, - CFX_ByteString& csNameTag) { - return AddNativeInterFormFont(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) { - RemoveInterFormFont(m_pFormDict, pFont); -} - -void CPDF_InterForm::RemoveFormFont(CFX_ByteString csNameTag) { - RemoveInterFormFont(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 GetDefaultInterFormFont(m_pFormDict, m_pDocument); -} -int CPDF_InterForm::GetFormAlignment() { - return m_pFormDict ? m_pFormDict->GetIntegerBy("Q", 0) : 0; -} - -bool CPDF_InterForm::ResetForm(const std::vector& 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 = 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* 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 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& 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 = 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 = - FPDFDOC_FDF_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; -} diff --git a/core/fpdfdoc/doc_formcontrol.cpp b/core/fpdfdoc/doc_formcontrol.cpp deleted file mode 100644 index 932a006be5..0000000000 --- a/core/fpdfdoc/doc_formcontrol.cpp +++ /dev/null @@ -1,438 +0,0 @@ -// 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/include/cpdf_formcontrol.h" - -#include - -#include "core/fpdfapi/fpdf_page/include/cpdf_form.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_stream.h" -#include "core/fpdfapi/fpdf_parser/include/fpdf_parser_decode.h" -#include "core/fpdfapi/fpdf_render/include/cpdf_rendercontext.h" -#include "core/fpdfdoc/include/cpdf_interform.h" - -namespace { - -const FX_CHAR* const g_sHighlightingMode[] = { - // Must match order of HighlightingMode enum. - "N", "I", "O", "P", "T"}; - -} // namespace - -CPDF_FormControl::CPDF_FormControl(CPDF_FormField* pField, - CPDF_Dictionary* pWidgetDict) - : m_pField(pField), - m_pWidgetDict(pWidgetDict), - m_pForm(m_pField->m_pForm) {} - -CFX_ByteString CPDF_FormControl::GetOnStateName() const { - ASSERT(GetType() == CPDF_FormField::CheckBox || - GetType() == CPDF_FormField::RadioButton); - CFX_ByteString csOn; - CPDF_Dictionary* pAP = m_pWidgetDict->GetDictBy("AP"); - if (!pAP) - return csOn; - - CPDF_Dictionary* pN = pAP->GetDictBy("N"); - if (!pN) - return csOn; - - for (const auto& it : *pN) { - if (it.first != "Off") - return it.first; - } - return CFX_ByteString(); -} - -void CPDF_FormControl::SetOnStateName(const CFX_ByteString& csOn) { - ASSERT(GetType() == CPDF_FormField::CheckBox || - GetType() == CPDF_FormField::RadioButton); - CFX_ByteString csValue = csOn; - if (csValue.IsEmpty()) { - csValue = "Yes"; - } - if (csValue == "Off") { - csValue = "Yes"; - } - CFX_ByteString csAS = m_pWidgetDict->GetStringBy("AS", "Off"); - if (csAS != "Off") { - m_pWidgetDict->SetAtName("AS", csValue); - } - CPDF_Dictionary* pAP = m_pWidgetDict->GetDictBy("AP"); - if (!pAP) { - return; - } - for (const auto& it : *pAP) { - CPDF_Object* pObj1 = it.second; - if (!pObj1) { - continue; - } - CPDF_Object* pObjDirect1 = pObj1->GetDirect(); - CPDF_Dictionary* pSubDict = pObjDirect1->AsDictionary(); - if (!pSubDict) - continue; - - auto subdict_it = pSubDict->begin(); - while (subdict_it != pSubDict->end()) { - const CFX_ByteString& csKey2 = subdict_it->first; - CPDF_Object* pObj2 = subdict_it->second; - ++subdict_it; - if (!pObj2) { - continue; - } - if (csKey2 != "Off") { - pSubDict->ReplaceKey(csKey2, csValue); - break; - } - } - } -} -CFX_ByteString CPDF_FormControl::GetCheckedAPState() { - ASSERT(GetType() == CPDF_FormField::CheckBox || - GetType() == CPDF_FormField::RadioButton); - CFX_ByteString csOn = GetOnStateName(); - if (GetType() == CPDF_FormField::RadioButton || - GetType() == CPDF_FormField::CheckBox) { - if (ToArray(FPDF_GetFieldAttr(m_pField->m_pDict, "Opt"))) { - int iIndex = m_pField->GetControlIndex(this); - csOn.Format("%d", iIndex); - } - } - if (csOn.IsEmpty()) - csOn = "Yes"; - return csOn; -} - -CFX_WideString CPDF_FormControl::GetExportValue() const { - ASSERT(GetType() == CPDF_FormField::CheckBox || - GetType() == CPDF_FormField::RadioButton); - CFX_ByteString csOn = GetOnStateName(); - if (GetType() == CPDF_FormField::RadioButton || - GetType() == CPDF_FormField::CheckBox) { - if (CPDF_Array* pArray = - ToArray(FPDF_GetFieldAttr(m_pField->m_pDict, "Opt"))) { - int iIndex = m_pField->GetControlIndex(this); - csOn = pArray->GetStringAt(iIndex); - } - } - if (csOn.IsEmpty()) - csOn = "Yes"; - return PDF_DecodeText(csOn); -} - -bool CPDF_FormControl::IsChecked() const { - ASSERT(GetType() == CPDF_FormField::CheckBox || - GetType() == CPDF_FormField::RadioButton); - CFX_ByteString csOn = GetOnStateName(); - CFX_ByteString csAS = m_pWidgetDict->GetStringBy("AS"); - return csAS == csOn; -} - -bool CPDF_FormControl::IsDefaultChecked() const { - ASSERT(GetType() == CPDF_FormField::CheckBox || - GetType() == CPDF_FormField::RadioButton); - CPDF_Object* pDV = FPDF_GetFieldAttr(m_pField->m_pDict, "DV"); - if (!pDV) { - return FALSE; - } - CFX_ByteString csDV = pDV->GetString(); - CFX_ByteString csOn = GetOnStateName(); - return (csDV == csOn); -} - -void CPDF_FormControl::CheckControl(FX_BOOL bChecked) { - ASSERT(GetType() == CPDF_FormField::CheckBox || - GetType() == CPDF_FormField::RadioButton); - CFX_ByteString csOn = GetOnStateName(); - CFX_ByteString csOldAS = m_pWidgetDict->GetStringBy("AS", "Off"); - CFX_ByteString csAS = "Off"; - if (bChecked) - csAS = csOn; - if (csOldAS == csAS) - return; - m_pWidgetDict->SetAtName("AS", csAS); -} - -void CPDF_FormControl::DrawControl(CFX_RenderDevice* pDevice, - CFX_Matrix* pMatrix, - CPDF_Page* pPage, - CPDF_Annot::AppearanceMode mode, - const CPDF_RenderOptions* pOptions) { - if (m_pWidgetDict->GetIntegerBy("F") & ANNOTFLAG_HIDDEN) - return; - - CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(m_pWidgetDict, mode); - if (!pStream) - return; - - CFX_FloatRect form_bbox = pStream->GetDict()->GetRectBy("BBox"); - CFX_Matrix form_matrix = pStream->GetDict()->GetMatrixBy("Matrix"); - form_matrix.TransformRect(form_bbox); - CFX_FloatRect arect = m_pWidgetDict->GetRectBy("Rect"); - CFX_Matrix matrix; - matrix.MatchRect(arect, form_bbox); - matrix.Concat(*pMatrix); - CPDF_Form form(m_pField->m_pForm->m_pDocument, - m_pField->m_pForm->m_pFormDict->GetDictBy("DR"), pStream); - form.ParseContent(nullptr, nullptr, nullptr); - CPDF_RenderContext context(pPage); - context.AppendLayer(&form, &matrix); - context.Render(pDevice, pOptions, nullptr); -} - -CPDF_FormControl::HighlightingMode CPDF_FormControl::GetHighlightingMode() { - if (!m_pWidgetDict) - return Invert; - - CFX_ByteString csH = m_pWidgetDict->GetStringBy("H", "I"); - for (size_t i = 0; i < FX_ArraySize(g_sHighlightingMode); ++i) { - if (csH == g_sHighlightingMode[i]) - return static_cast(i); - } - return Invert; -} - -CPDF_ApSettings CPDF_FormControl::GetMK() const { - return CPDF_ApSettings(m_pWidgetDict ? m_pWidgetDict->GetDictBy("MK") - : nullptr); -} - -bool CPDF_FormControl::HasMKEntry(const CFX_ByteString& csEntry) const { - return GetMK().HasMKEntry(csEntry); -} - -int CPDF_FormControl::GetRotation() { - return GetMK().GetRotation(); -} - -FX_ARGB CPDF_FormControl::GetColor(int& iColorType, - const CFX_ByteString& csEntry) { - return GetMK().GetColor(iColorType, csEntry); -} - -FX_FLOAT CPDF_FormControl::GetOriginalColor(int index, - const CFX_ByteString& csEntry) { - return GetMK().GetOriginalColor(index, csEntry); -} - -void CPDF_FormControl::GetOriginalColor(int& iColorType, - FX_FLOAT fc[4], - const CFX_ByteString& csEntry) { - GetMK().GetOriginalColor(iColorType, fc, csEntry); -} -CFX_WideString CPDF_FormControl::GetCaption(const CFX_ByteString& csEntry) { - return GetMK().GetCaption(csEntry); -} - -CPDF_Stream* CPDF_FormControl::GetIcon(const CFX_ByteString& csEntry) { - return GetMK().GetIcon(csEntry); -} - -CPDF_IconFit CPDF_FormControl::GetIconFit() { - return GetMK().GetIconFit(); -} - -int CPDF_FormControl::GetTextPosition() { - return GetMK().GetTextPosition(); -} - -CPDF_Action CPDF_FormControl::GetAction() { - if (!m_pWidgetDict) - return CPDF_Action(); - - if (m_pWidgetDict->KeyExist("A")) - return CPDF_Action(m_pWidgetDict->GetDictBy("A")); - - CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "A"); - if (!pObj) - return CPDF_Action(); - - return CPDF_Action(pObj->GetDict()); -} - -CPDF_AAction CPDF_FormControl::GetAdditionalAction() { - if (!m_pWidgetDict) - return CPDF_AAction(); - - if (m_pWidgetDict->KeyExist("AA")) - return CPDF_AAction(m_pWidgetDict->GetDictBy("AA")); - return m_pField->GetAdditionalAction(); -} - -CPDF_DefaultAppearance CPDF_FormControl::GetDefaultAppearance() { - if (!m_pWidgetDict) - return CPDF_DefaultAppearance(); - - if (m_pWidgetDict->KeyExist("DA")) - return CPDF_DefaultAppearance(m_pWidgetDict->GetStringBy("DA")); - - CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "DA"); - if (pObj) - return CPDF_DefaultAppearance(pObj->GetString()); - return m_pField->m_pForm->GetDefaultAppearance(); -} - -CPDF_Font* CPDF_FormControl::GetDefaultControlFont() { - CPDF_DefaultAppearance cDA = GetDefaultAppearance(); - CFX_ByteString csFontNameTag; - FX_FLOAT fFontSize; - cDA.GetFont(csFontNameTag, fFontSize); - if (csFontNameTag.IsEmpty()) - return nullptr; - - CPDF_Object* pObj = FPDF_GetFieldAttr(m_pWidgetDict, "DR"); - if (CPDF_Dictionary* pDict = ToDictionary(pObj)) { - CPDF_Dictionary* pFonts = pDict->GetDictBy("Font"); - if (pFonts) { - CPDF_Dictionary* pElement = pFonts->GetDictBy(csFontNameTag); - if (pElement) { - CPDF_Font* pFont = m_pField->m_pForm->m_pDocument->LoadFont(pElement); - if (pFont) { - return pFont; - } - } - } - } - if (CPDF_Font* pFormFont = m_pField->m_pForm->GetFormFont(csFontNameTag)) - return pFormFont; - - CPDF_Dictionary* pPageDict = m_pWidgetDict->GetDictBy("P"); - pObj = FPDF_GetFieldAttr(pPageDict, "Resources"); - if (CPDF_Dictionary* pDict = ToDictionary(pObj)) { - CPDF_Dictionary* pFonts = pDict->GetDictBy("Font"); - if (pFonts) { - CPDF_Dictionary* pElement = pFonts->GetDictBy(csFontNameTag); - if (pElement) { - CPDF_Font* pFont = m_pField->m_pForm->m_pDocument->LoadFont(pElement); - if (pFont) { - return pFont; - } - } - } - } - return nullptr; -} - -int CPDF_FormControl::GetControlAlignment() { - if (!m_pWidgetDict) { - return 0; - } - if (m_pWidgetDict->KeyExist("Q")) { - return m_pWidgetDict->GetIntegerBy("Q", 0); - } - CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "Q"); - if (pObj) - return pObj->GetInteger(); - return m_pField->m_pForm->GetFormAlignment(); -} - -CPDF_ApSettings::CPDF_ApSettings(CPDF_Dictionary* pDict) : m_pDict(pDict) {} - -bool CPDF_ApSettings::HasMKEntry(const CFX_ByteString& csEntry) const { - return m_pDict && m_pDict->KeyExist(csEntry); -} - -int CPDF_ApSettings::GetRotation() const { - return m_pDict ? m_pDict->GetIntegerBy("R") : 0; -} - -FX_ARGB CPDF_ApSettings::GetColor(int& iColorType, - const CFX_ByteString& csEntry) const { - iColorType = COLORTYPE_TRANSPARENT; - if (!m_pDict) - return 0; - - CPDF_Array* pEntry = m_pDict->GetArrayBy(csEntry); - if (!pEntry) - return 0; - - FX_ARGB color = 0; - size_t dwCount = pEntry->GetCount(); - if (dwCount == 1) { - iColorType = COLORTYPE_GRAY; - FX_FLOAT g = pEntry->GetNumberAt(0) * 255; - color = ArgbEncode(255, (int)g, (int)g, (int)g); - } else if (dwCount == 3) { - iColorType = COLORTYPE_RGB; - FX_FLOAT r = pEntry->GetNumberAt(0) * 255; - FX_FLOAT g = pEntry->GetNumberAt(1) * 255; - FX_FLOAT b = pEntry->GetNumberAt(2) * 255; - color = ArgbEncode(255, (int)r, (int)g, (int)b); - } else if (dwCount == 4) { - iColorType = COLORTYPE_CMYK; - FX_FLOAT c = pEntry->GetNumberAt(0); - FX_FLOAT m = pEntry->GetNumberAt(1); - FX_FLOAT y = pEntry->GetNumberAt(2); - FX_FLOAT k = pEntry->GetNumberAt(3); - 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), (int)(g * 255), (int)(b * 255)); - } - return color; -} - -FX_FLOAT CPDF_ApSettings::GetOriginalColor( - int index, - const CFX_ByteString& csEntry) const { - if (!m_pDict) - return 0; - - CPDF_Array* pEntry = m_pDict->GetArrayBy(csEntry); - return pEntry ? pEntry->GetNumberAt(index) : 0; -} - -void CPDF_ApSettings::GetOriginalColor(int& iColorType, - FX_FLOAT fc[4], - const CFX_ByteString& csEntry) const { - iColorType = COLORTYPE_TRANSPARENT; - for (int i = 0; i < 4; i++) { - fc[i] = 0; - } - if (!m_pDict) { - return; - } - CPDF_Array* pEntry = m_pDict->GetArrayBy(csEntry); - if (!pEntry) { - return; - } - size_t dwCount = pEntry->GetCount(); - if (dwCount == 1) { - iColorType = COLORTYPE_GRAY; - fc[0] = pEntry->GetNumberAt(0); - } else if (dwCount == 3) { - iColorType = COLORTYPE_RGB; - fc[0] = pEntry->GetNumberAt(0); - fc[1] = pEntry->GetNumberAt(1); - fc[2] = pEntry->GetNumberAt(2); - } else if (dwCount == 4) { - iColorType = COLORTYPE_CMYK; - fc[0] = pEntry->GetNumberAt(0); - fc[1] = pEntry->GetNumberAt(1); - fc[2] = pEntry->GetNumberAt(2); - fc[3] = pEntry->GetNumberAt(3); - } -} - -CFX_WideString CPDF_ApSettings::GetCaption( - const CFX_ByteString& csEntry) const { - return m_pDict ? m_pDict->GetUnicodeTextBy(csEntry) : CFX_WideString(); -} - -CPDF_Stream* CPDF_ApSettings::GetIcon(const CFX_ByteString& csEntry) const { - return m_pDict ? m_pDict->GetStreamBy(csEntry) : nullptr; -} - -CPDF_IconFit CPDF_ApSettings::GetIconFit() const { - return CPDF_IconFit(m_pDict ? m_pDict->GetDictBy("IF") : nullptr); -} - -int CPDF_ApSettings::GetTextPosition() const { - return m_pDict ? m_pDict->GetIntegerBy("TP", TEXTPOS_CAPTION) - : TEXTPOS_CAPTION; -} diff --git a/core/fpdfdoc/doc_formfield.cpp b/core/fpdfdoc/doc_formfield.cpp deleted file mode 100644 index cb1b0a4566..0000000000 --- a/core/fpdfdoc/doc_formfield.cpp +++ /dev/null @@ -1,987 +0,0 @@ -// 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/include/cpdf_formfield.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_number.h" -#include "core/fpdfapi/fpdf_parser/include/cpdf_simple_parser.h" -#include "core/fpdfapi/fpdf_parser/include/cpdf_string.h" -#include "core/fpdfapi/fpdf_parser/include/fpdf_parser_decode.h" -#include "core/fpdfdoc/cpvt_generateap.h" -#include "core/fpdfdoc/doc_utils.h" -#include "core/fpdfdoc/include/cpdf_formcontrol.h" -#include "core/fpdfdoc/include/cpdf_interform.h" - -namespace { - -const int kFormListMultiSelect = 0x100; - -const int kFormComboEdit = 0x100; - -const int kFormFieldReadOnly = 0x01; -const int kFormFieldRequired = 0x02; -const int kFormFieldNoExport = 0x04; - -const int kFormRadioNoToggleOff = 0x100; -const int kFormRadioUnison = 0x200; - -const int kFormTextMultiLine = 0x100; -const int kFormTextPassword = 0x200; -const int kFormTextNoScroll = 0x400; -const int kFormTextComb = 0x800; - -bool PDF_FormField_IsUnison(CPDF_FormField* pField) { - if (pField->GetType() == CPDF_FormField::CheckBox) - return true; - - return (pField->GetFieldFlags() & 0x2000000) != 0; -} - -} // namespace - -CPDF_FormField::CPDF_FormField(CPDF_InterForm* pForm, CPDF_Dictionary* pDict) - : m_Type(Unknown), - m_pForm(pForm), - m_pDict(pDict), - m_FontSize(0), - m_pFont(nullptr) { - SyncFieldFlags(); -} - -CPDF_FormField::~CPDF_FormField() {} - -void CPDF_FormField::SyncFieldFlags() { - CFX_ByteString type_name = FPDF_GetFieldAttr(m_pDict, "FT") - ? FPDF_GetFieldAttr(m_pDict, "FT")->GetString() - : CFX_ByteString(); - uint32_t flags = FPDF_GetFieldAttr(m_pDict, "Ff") - ? FPDF_GetFieldAttr(m_pDict, "Ff")->GetInteger() - : 0; - m_Flags = 0; - if (flags & 1) { - m_Flags |= kFormFieldReadOnly; - } - if (flags & 2) { - m_Flags |= kFormFieldRequired; - } - if (flags & 4) { - m_Flags |= kFormFieldNoExport; - } - if (type_name == "Btn") { - if (flags & 0x8000) { - m_Type = RadioButton; - if (flags & 0x4000) { - m_Flags |= kFormRadioNoToggleOff; - } - if (flags & 0x2000000) { - m_Flags |= kFormRadioUnison; - } - } else if (flags & 0x10000) { - m_Type = PushButton; - } else { - m_Type = CheckBox; - } - } else if (type_name == "Tx") { - if (flags & 0x100000) { - m_Type = File; - } else if (flags & 0x2000000) { - m_Type = RichText; - } else { - m_Type = Text; - if (flags & 0x1000) { - m_Flags |= kFormTextMultiLine; - } - if (flags & 0x2000) { - m_Flags |= kFormTextPassword; - } - if (flags & 0x800000) { - m_Flags |= kFormTextNoScroll; - } - if (flags & 0x100000) { - m_Flags |= kFormTextComb; - } - } - LoadDA(); - } else if (type_name == "Ch") { - if (flags & 0x20000) { - m_Type = ComboBox; - if (flags & 0x40000) { - m_Flags |= kFormComboEdit; - } - } else { - m_Type = ListBox; - if (flags & 0x200000) { - m_Flags |= kFormListMultiSelect; - } - } - LoadDA(); - } else if (type_name == "Sig") { - m_Type = Sign; - } -} -CFX_WideString CPDF_FormField::GetFullName() const { - return ::GetFullName(m_pDict); -} - -FX_BOOL CPDF_FormField::ResetField(FX_BOOL bNotify) { - switch (m_Type) { - case CPDF_FormField::CheckBox: - case CPDF_FormField::RadioButton: { - int iCount = CountControls(); - if (iCount) { - // TODO(weili): Check whether anything special needs to be done for - // unison field. Otherwise, merge these branches. - if (PDF_FormField_IsUnison(this)) { - for (int i = 0; i < iCount; i++) { - CheckControl(i, GetControl(i)->IsDefaultChecked(), FALSE); - } - } else { - for (int i = 0; i < iCount; i++) { - CheckControl(i, GetControl(i)->IsDefaultChecked(), FALSE); - } - } - } - if (bNotify && m_pForm->m_pFormNotify) { - m_pForm->m_pFormNotify->AfterCheckedStatusChange(this); - } - } break; - case CPDF_FormField::ComboBox: - case CPDF_FormField::ListBox: { - CFX_WideString csValue; - ClearSelection(); - int iIndex = GetDefaultSelectedItem(); - if (iIndex >= 0) - csValue = GetOptionLabel(iIndex); - - if (bNotify && !NotifyListOrComboBoxBeforeChange(csValue)) - return FALSE; - - SetItemSelection(iIndex, TRUE); - if (bNotify) - NotifyListOrComboBoxAfterChange(); - } break; - case CPDF_FormField::Text: - case CPDF_FormField::RichText: - case CPDF_FormField::File: - default: { - CPDF_Object* pDV = FPDF_GetFieldAttr(m_pDict, "DV"); - CFX_WideString csDValue; - if (pDV) - csDValue = pDV->GetUnicodeText(); - - CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V"); - CFX_WideString csValue; - if (pV) - csValue = pV->GetUnicodeText(); - - CPDF_Object* pRV = FPDF_GetFieldAttr(m_pDict, "RV"); - if (!pRV && (csDValue == csValue)) - return FALSE; - - if (bNotify && !NotifyBeforeValueChange(csDValue)) - return FALSE; - - if (pDV) { - CPDF_Object* pClone = pDV->Clone(); - if (!pClone) - return FALSE; - - m_pDict->SetAt("V", pClone); - if (pRV) { - CPDF_Object* pCloneR = pDV->Clone(); - m_pDict->SetAt("RV", pCloneR); - } - } else { - m_pDict->RemoveAt("V"); - m_pDict->RemoveAt("RV"); - } - if (bNotify) - NotifyAfterValueChange(); - } break; - } - return TRUE; -} - -int CPDF_FormField::GetControlIndex(const CPDF_FormControl* pControl) const { - if (!pControl) - return -1; - - for (int i = 0; i < m_ControlList.GetSize(); i++) { - if (m_ControlList.GetAt(i) == pControl) - return i; - } - return -1; -} - -int CPDF_FormField::GetFieldType() const { - switch (m_Type) { - case PushButton: - return FIELDTYPE_PUSHBUTTON; - case CheckBox: - return FIELDTYPE_CHECKBOX; - case RadioButton: - return FIELDTYPE_RADIOBUTTON; - case ComboBox: - return FIELDTYPE_COMBOBOX; - case ListBox: - return FIELDTYPE_LISTBOX; - case Text: - case RichText: - case File: - return FIELDTYPE_TEXTFIELD; - case Sign: - return FIELDTYPE_SIGNATURE; - default: - break; - } - return FIELDTYPE_UNKNOWN; -} - -CPDF_AAction CPDF_FormField::GetAdditionalAction() const { - CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "AA"); - return CPDF_AAction(pObj ? pObj->GetDict() : nullptr); -} - -CFX_WideString CPDF_FormField::GetAlternateName() const { - CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TU"); - if (!pObj) { - return L""; - } - return pObj->GetUnicodeText(); -} -CFX_WideString CPDF_FormField::GetMappingName() const { - CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TM"); - if (!pObj) { - return L""; - } - return pObj->GetUnicodeText(); -} -uint32_t CPDF_FormField::GetFieldFlags() const { - CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "Ff"); - if (!pObj) { - return 0; - } - return pObj->GetInteger(); -} -CFX_ByteString CPDF_FormField::GetDefaultStyle() const { - CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "DS"); - if (!pObj) { - return ""; - } - return pObj->GetString(); -} -CFX_WideString CPDF_FormField::GetRichTextString() const { - CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "RV"); - if (!pObj) { - return L""; - } - return pObj->GetUnicodeText(); -} -CFX_WideString CPDF_FormField::GetValue(FX_BOOL bDefault) const { - if (GetType() == CheckBox || GetType() == RadioButton) - return GetCheckValue(bDefault); - - CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, bDefault ? "DV" : "V"); - if (!pValue) { - if (!bDefault) { - if (m_Type == RichText) { - pValue = FPDF_GetFieldAttr(m_pDict, "V"); - } - if (!pValue && m_Type != Text) { - pValue = FPDF_GetFieldAttr(m_pDict, "DV"); - } - } - if (!pValue) - return CFX_WideString(); - } - switch (pValue->GetType()) { - case CPDF_Object::STRING: - case CPDF_Object::STREAM: - return pValue->GetUnicodeText(); - case CPDF_Object::ARRAY: - pValue = pValue->AsArray()->GetDirectObjectAt(0); - if (pValue) - return pValue->GetUnicodeText(); - break; - default: - break; - } - return CFX_WideString(); -} - -CFX_WideString CPDF_FormField::GetValue() const { - return GetValue(FALSE); -} - -CFX_WideString CPDF_FormField::GetDefaultValue() const { - return GetValue(TRUE); -} - -FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, - FX_BOOL bDefault, - FX_BOOL bNotify) { - switch (m_Type) { - case CheckBox: - case RadioButton: { - SetCheckValue(value, bDefault, bNotify); - return TRUE; - } - case File: - case RichText: - case Text: - case ComboBox: { - CFX_WideString csValue = value; - if (bNotify && !NotifyBeforeValueChange(csValue)) - return FALSE; - - int iIndex = FindOptionValue(csValue); - if (iIndex < 0) { - CFX_ByteString bsEncodeText = PDF_EncodeText(csValue); - m_pDict->SetAtString(bDefault ? "DV" : "V", bsEncodeText); - if (m_Type == RichText && !bDefault) - m_pDict->SetAtString("RV", bsEncodeText); - m_pDict->RemoveAt("I"); - } else { - m_pDict->SetAtString(bDefault ? "DV" : "V", PDF_EncodeText(csValue)); - if (!bDefault) { - ClearSelection(); - SetItemSelection(iIndex, TRUE); - } - } - if (bNotify) - NotifyAfterValueChange(); - } break; - case ListBox: { - int iIndex = FindOptionValue(value); - if (iIndex < 0) - return FALSE; - - if (bDefault && iIndex == GetDefaultSelectedItem()) - return FALSE; - - if (bNotify && !NotifyBeforeSelectionChange(value)) - return FALSE; - - if (!bDefault) { - ClearSelection(); - SetItemSelection(iIndex, TRUE); - } - if (bNotify) - NotifyAfterSelectionChange(); - break; - } - default: - break; - } - return TRUE; -} - -FX_BOOL CPDF_FormField::SetValue(const CFX_WideString& value, FX_BOOL bNotify) { - return SetValue(value, FALSE, bNotify); -} - -int CPDF_FormField::GetMaxLen() const { - if (CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "MaxLen")) - return pObj->GetInteger(); - - for (int i = 0; i < m_ControlList.GetSize(); i++) { - CPDF_FormControl* pControl = m_ControlList.GetAt(i); - if (!pControl) - continue; - - CPDF_Dictionary* pWidgetDict = pControl->m_pWidgetDict; - if (pWidgetDict->KeyExist("MaxLen")) - return pWidgetDict->GetIntegerBy("MaxLen"); - } - return 0; -} - -int CPDF_FormField::CountSelectedItems() const { - CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); - if (!pValue) { - pValue = FPDF_GetFieldAttr(m_pDict, "I"); - if (!pValue) - return 0; - } - - if (pValue->IsString() || pValue->IsNumber()) - return pValue->GetString().IsEmpty() ? 0 : 1; - if (CPDF_Array* pArray = pValue->AsArray()) - return pArray->GetCount(); - return 0; -} - -int CPDF_FormField::GetSelectedIndex(int index) const { - CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); - if (!pValue) { - pValue = FPDF_GetFieldAttr(m_pDict, "I"); - if (!pValue) - return -1; - } - if (pValue->IsNumber()) - return pValue->GetInteger(); - - CFX_WideString sel_value; - if (pValue->IsString()) { - if (index != 0) - return -1; - sel_value = pValue->GetUnicodeText(); - } else { - CPDF_Array* pArray = pValue->AsArray(); - if (!pArray || index < 0) - return -1; - - CPDF_Object* elementValue = pArray->GetDirectObjectAt(index); - sel_value = - elementValue ? elementValue->GetUnicodeText() : CFX_WideString(); - } - if (index < CountSelectedOptions()) { - int iOptIndex = GetSelectedOptionIndex(index); - CFX_WideString csOpt = GetOptionValue(iOptIndex); - if (csOpt == sel_value) { - return iOptIndex; - } - } - for (int i = 0; i < CountOptions(); i++) { - if (sel_value == GetOptionValue(i)) - return i; - } - return -1; -} - -FX_BOOL CPDF_FormField::ClearSelection(FX_BOOL bNotify) { - if (bNotify && m_pForm->m_pFormNotify) { - CFX_WideString csValue; - int iIndex = GetSelectedIndex(0); - if (iIndex >= 0) - csValue = GetOptionLabel(iIndex); - - if (!NotifyListOrComboBoxBeforeChange(csValue)) - return FALSE; - } - m_pDict->RemoveAt("V"); - m_pDict->RemoveAt("I"); - if (bNotify) - NotifyListOrComboBoxAfterChange(); - return TRUE; -} - -FX_BOOL CPDF_FormField::IsItemSelected(int index) const { - ASSERT(GetType() == ComboBox || GetType() == ListBox); - if (index < 0 || index >= CountOptions()) { - return FALSE; - } - if (IsOptionSelected(index)) { - return TRUE; - } - CFX_WideString opt_value = GetOptionValue(index); - CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); - if (!pValue) { - pValue = FPDF_GetFieldAttr(m_pDict, "I"); - if (!pValue) { - return FALSE; - } - } - - if (pValue->IsString()) - return pValue->GetUnicodeText() == opt_value; - - if (pValue->IsNumber()) { - if (pValue->GetString().IsEmpty()) - return FALSE; - return (pValue->GetInteger() == index); - } - - CPDF_Array* pArray = pValue->AsArray(); - if (!pArray) - return FALSE; - - int iPos = -1; - for (int j = 0; j < CountSelectedOptions(); j++) { - if (GetSelectedOptionIndex(j) == index) { - iPos = j; - break; - } - } - for (int i = 0; i < static_cast(pArray->GetCount()); i++) - if (pArray->GetDirectObjectAt(i)->GetUnicodeText() == opt_value && - i == iPos) { - return TRUE; - } - return FALSE; -} - -FX_BOOL CPDF_FormField::SetItemSelection(int index, - FX_BOOL bSelected, - FX_BOOL bNotify) { - ASSERT(GetType() == ComboBox || GetType() == ListBox); - if (index < 0 || index >= CountOptions()) - return FALSE; - - CFX_WideString opt_value = GetOptionValue(index); - if (bNotify && !NotifyListOrComboBoxBeforeChange(opt_value)) - return FALSE; - - if (bSelected) { - if (GetType() == ListBox) { - SelectOption(index, TRUE); - if (!(m_Flags & kFormListMultiSelect)) { - m_pDict->SetAtString("V", PDF_EncodeText(opt_value)); - } else { - CPDF_Array* pArray = new CPDF_Array; - for (int i = 0; i < CountOptions(); i++) { - if (i == index || IsItemSelected(i)) { - opt_value = GetOptionValue(i); - pArray->AddString(PDF_EncodeText(opt_value)); - } - } - m_pDict->SetAt("V", pArray); - } - } else { - m_pDict->SetAtString("V", PDF_EncodeText(opt_value)); - CPDF_Array* pI = new CPDF_Array; - pI->AddInteger(index); - m_pDict->SetAt("I", pI); - } - } else { - CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "V"); - if (pValue) { - if (GetType() == ListBox) { - SelectOption(index, FALSE); - if (pValue->IsString()) { - if (pValue->GetUnicodeText() == opt_value) - m_pDict->RemoveAt("V"); - } else if (pValue->IsArray()) { - CPDF_Array* pArray = new CPDF_Array; - for (int i = 0; i < CountOptions(); i++) { - if (i != index && IsItemSelected(i)) { - opt_value = GetOptionValue(i); - pArray->AddString(PDF_EncodeText(opt_value)); - } - } - if (pArray->GetCount() < 1) - pArray->Release(); - else - m_pDict->SetAt("V", pArray); - } - } else { - m_pDict->RemoveAt("V"); - m_pDict->RemoveAt("I"); - } - } - } - if (bNotify) - NotifyListOrComboBoxAfterChange(); - return TRUE; -} - -FX_BOOL CPDF_FormField::IsItemDefaultSelected(int index) const { - ASSERT(GetType() == ComboBox || GetType() == ListBox); - if (index < 0 || index >= CountOptions()) - return FALSE; - int iDVIndex = GetDefaultSelectedItem(); - return iDVIndex >= 0 && iDVIndex == index; -} - -int CPDF_FormField::GetDefaultSelectedItem() const { - ASSERT(GetType() == ComboBox || GetType() == ListBox); - CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "DV"); - if (!pValue) - return -1; - CFX_WideString csDV = pValue->GetUnicodeText(); - if (csDV.IsEmpty()) - return -1; - for (int i = 0; i < CountOptions(); i++) { - if (csDV == GetOptionValue(i)) - return i; - } - return -1; -} - -int CPDF_FormField::CountOptions() const { - CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt")); - return pArray ? pArray->GetCount() : 0; -} - -CFX_WideString CPDF_FormField::GetOptionText(int index, int sub_index) const { - CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "Opt")); - if (!pArray) - return CFX_WideString(); - - CPDF_Object* pOption = pArray->GetDirectObjectAt(index); - if (!pOption) - return CFX_WideString(); - if (CPDF_Array* pOptionArray = pOption->AsArray()) - pOption = pOptionArray->GetDirectObjectAt(sub_index); - - CPDF_String* pString = ToString(pOption); - return pString ? pString->GetUnicodeText() : CFX_WideString(); -} -CFX_WideString CPDF_FormField::GetOptionLabel(int index) const { - return GetOptionText(index, 1); -} -CFX_WideString CPDF_FormField::GetOptionValue(int index) const { - return GetOptionText(index, 0); -} - -int CPDF_FormField::FindOption(CFX_WideString csOptLabel) const { - for (int i = 0; i < CountOptions(); i++) { - if (GetOptionValue(i) == csOptLabel) - return i; - } - return -1; -} - -int CPDF_FormField::FindOptionValue(const CFX_WideString& csOptValue) const { - for (int i = 0; i < CountOptions(); i++) { - if (GetOptionValue(i) == csOptValue) - return i; - } - return -1; -} - -#ifdef PDF_ENABLE_XFA -int CPDF_FormField::InsertOption(CFX_WideString csOptLabel, - int index, - FX_BOOL bNotify) { - if (csOptLabel.IsEmpty()) - return -1; - - if (bNotify && !NotifyListOrComboBoxBeforeChange(csOptLabel)) - return -1; - - CFX_ByteString csStr = - PDF_EncodeText(csOptLabel.c_str(), csOptLabel.GetLength()); - CPDF_Object* pValue = FPDF_GetFieldAttr(m_pDict, "Opt"); - CPDF_Array* pOpt = ToArray(pValue); - if (!pOpt) { - pOpt = new CPDF_Array; - m_pDict->SetAt("Opt", pOpt); - } - - int iCount = (int)pOpt->GetCount(); - if (index < 0 || index >= iCount) { - pOpt->AddString(csStr); - index = iCount; - } else { - CPDF_String* pString = new CPDF_String(csStr, FALSE); - pOpt->InsertAt(index, pString); - } - - if (bNotify) - NotifyListOrComboBoxAfterChange(); - return index; -} - -FX_BOOL CPDF_FormField::ClearOptions(FX_BOOL bNotify) { - if (bNotify && m_pForm->m_pFormNotify) { - CFX_WideString csValue; - int iIndex = GetSelectedIndex(0); - if (iIndex >= 0) - csValue = GetOptionLabel(iIndex); - if (!NotifyListOrComboBoxBeforeChange(csValue)) - return FALSE; - } - - m_pDict->RemoveAt("Opt"); - m_pDict->RemoveAt("V"); - m_pDict->RemoveAt("DV"); - m_pDict->RemoveAt("I"); - m_pDict->RemoveAt("TI"); - - if (bNotify) - NotifyListOrComboBoxAfterChange(); - - return TRUE; -} -#endif // PDF_ENABLE_XFA - -FX_BOOL CPDF_FormField::CheckControl(int iControlIndex, - bool bChecked, - bool bNotify) { - ASSERT(GetType() == CheckBox || GetType() == RadioButton); - CPDF_FormControl* pControl = GetControl(iControlIndex); - if (!pControl) { - return FALSE; - } - if (!bChecked && pControl->IsChecked() == bChecked) { - return FALSE; - } - CFX_WideString csWExport = pControl->GetExportValue(); - CFX_ByteString csBExport = PDF_EncodeText(csWExport); - int iCount = CountControls(); - bool bUnison = PDF_FormField_IsUnison(this); - for (int i = 0; i < iCount; i++) { - CPDF_FormControl* pCtrl = GetControl(i); - if (bUnison) { - CFX_WideString csEValue = pCtrl->GetExportValue(); - if (csEValue == csWExport) { - if (pCtrl->GetOnStateName() == pControl->GetOnStateName()) { - pCtrl->CheckControl(bChecked); - } else if (bChecked) { - pCtrl->CheckControl(FALSE); - } - } else if (bChecked) { - pCtrl->CheckControl(FALSE); - } - } else { - if (i == iControlIndex) { - pCtrl->CheckControl(bChecked); - } else if (bChecked) { - pCtrl->CheckControl(FALSE); - } - } - } - CPDF_Object* pOpt = FPDF_GetFieldAttr(m_pDict, "Opt"); - if (!ToArray(pOpt)) { - if (bChecked) { - m_pDict->SetAtName("V", csBExport); - } else { - CFX_ByteString csV; - CPDF_Object* pV = FPDF_GetFieldAttr(m_pDict, "V"); - if (pV) { - csV = pV->GetString(); - } - if (csV == csBExport) { - m_pDict->SetAtName("V", "Off"); - } - } - } else if (bChecked) { - CFX_ByteString csIndex; - csIndex.Format("%d", iControlIndex); - m_pDict->SetAtName("V", csIndex); - } - if (bNotify && m_pForm->m_pFormNotify) - m_pForm->m_pFormNotify->AfterCheckedStatusChange(this); - return TRUE; -} - -CFX_WideString CPDF_FormField::GetCheckValue(FX_BOOL bDefault) const { - ASSERT(GetType() == CheckBox || GetType() == RadioButton); - CFX_WideString csExport = L"Off"; - int iCount = CountControls(); - for (int i = 0; i < iCount; i++) { - CPDF_FormControl* pControl = GetControl(i); - FX_BOOL bChecked = - bDefault ? pControl->IsDefaultChecked() : pControl->IsChecked(); - if (bChecked) { - csExport = pControl->GetExportValue(); - break; - } - } - return csExport; -} - -FX_BOOL CPDF_FormField::SetCheckValue(const CFX_WideString& value, - FX_BOOL bDefault, - FX_BOOL bNotify) { - ASSERT(GetType() == CheckBox || GetType() == RadioButton); - int iCount = CountControls(); - for (int i = 0; i < iCount; i++) { - CPDF_FormControl* pControl = GetControl(i); - CFX_WideString csExport = pControl->GetExportValue(); - bool val = csExport == value; - if (!bDefault) - CheckControl(GetControlIndex(pControl), val); - if (val) - break; - } - if (bNotify && m_pForm->m_pFormNotify) - m_pForm->m_pFormNotify->AfterCheckedStatusChange(this); - return TRUE; -} - -int CPDF_FormField::GetTopVisibleIndex() const { - CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "TI"); - return pObj ? pObj->GetInteger() : 0; -} - -int CPDF_FormField::CountSelectedOptions() const { - CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I")); - return pArray ? pArray->GetCount() : 0; -} - -int CPDF_FormField::GetSelectedOptionIndex(int index) const { - CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I")); - if (!pArray) - return -1; - - int iCount = pArray->GetCount(); - if (iCount < 0 || index >= iCount) - return -1; - return pArray->GetIntegerAt(index); -} - -FX_BOOL CPDF_FormField::IsOptionSelected(int iOptIndex) const { - CPDF_Array* pArray = ToArray(FPDF_GetFieldAttr(m_pDict, "I")); - if (!pArray) - return FALSE; - - for (CPDF_Object* pObj : *pArray) { - if (pObj->GetInteger() == iOptIndex) - return TRUE; - } - return FALSE; -} - -FX_BOOL CPDF_FormField::SelectOption(int iOptIndex, - FX_BOOL bSelected, - FX_BOOL bNotify) { - CPDF_Array* pArray = m_pDict->GetArrayBy("I"); - if (!pArray) { - if (!bSelected) - return TRUE; - - pArray = new CPDF_Array; - m_pDict->SetAt("I", pArray); - } - - FX_BOOL bReturn = FALSE; - for (size_t i = 0; i < pArray->GetCount(); i++) { - int iFind = pArray->GetIntegerAt(i); - if (iFind == iOptIndex) { - if (bSelected) - return TRUE; - - if (bNotify && m_pForm->m_pFormNotify) { - CFX_WideString csValue = GetOptionLabel(iOptIndex); - if (!NotifyListOrComboBoxBeforeChange(csValue)) - return FALSE; - } - pArray->RemoveAt(i); - bReturn = TRUE; - break; - } - - if (iFind > iOptIndex) { - if (!bSelected) - continue; - - if (bNotify && m_pForm->m_pFormNotify) { - CFX_WideString csValue = GetOptionLabel(iOptIndex); - if (!NotifyListOrComboBoxBeforeChange(csValue)) - return FALSE; - } - pArray->InsertAt(i, new CPDF_Number(iOptIndex)); - bReturn = TRUE; - break; - } - } - if (!bReturn) { - if (bSelected) - pArray->AddInteger(iOptIndex); - - if (pArray->GetCount() == 0) - m_pDict->RemoveAt("I"); - } - if (bNotify) - NotifyListOrComboBoxAfterChange(); - - return TRUE; -} - -FX_BOOL CPDF_FormField::ClearSelectedOptions(FX_BOOL bNotify) { - if (bNotify && m_pForm->m_pFormNotify) { - CFX_WideString csValue; - int iIndex = GetSelectedIndex(0); - if (iIndex >= 0) - csValue = GetOptionLabel(iIndex); - - if (!NotifyListOrComboBoxBeforeChange(csValue)) - return FALSE; - } - m_pDict->RemoveAt("I"); - if (bNotify) - NotifyListOrComboBoxAfterChange(); - - return TRUE; -} - -void CPDF_FormField::LoadDA() { - CPDF_Dictionary* pFormDict = m_pForm->m_pFormDict; - if (!pFormDict) - return; - - CFX_ByteString DA; - if (CPDF_Object* pObj = FPDF_GetFieldAttr(m_pDict, "DA")) - DA = pObj->GetString(); - - if (DA.IsEmpty()) - DA = pFormDict->GetStringBy("DA"); - - if (DA.IsEmpty()) - return; - - CPDF_Dictionary* pDR = pFormDict->GetDictBy("DR"); - if (!pDR) - return; - - CPDF_Dictionary* pFont = pDR->GetDictBy("Font"); - if (!pFont) - return; - - CPDF_SimpleParser syntax(DA.AsStringC()); - syntax.FindTagParamFromStart("Tf", 2); - CFX_ByteString font_name(syntax.GetWord()); - CPDF_Dictionary* pFontDict = pFont->GetDictBy(font_name); - if (!pFontDict) - return; - - m_pFont = m_pForm->m_pDocument->LoadFont(pFontDict); - m_FontSize = FX_atof(syntax.GetWord()); -} - -bool CPDF_FormField::NotifyBeforeSelectionChange(const CFX_WideString& value) { - if (!m_pForm->m_pFormNotify) - return true; - return m_pForm->m_pFormNotify->BeforeSelectionChange(this, value) >= 0; -} - -void CPDF_FormField::NotifyAfterSelectionChange() { - if (!m_pForm->m_pFormNotify) - return; - m_pForm->m_pFormNotify->AfterSelectionChange(this); -} - -bool CPDF_FormField::NotifyBeforeValueChange(const CFX_WideString& value) { - if (!m_pForm->m_pFormNotify) - return true; - return m_pForm->m_pFormNotify->BeforeValueChange(this, value) >= 0; -} - -void CPDF_FormField::NotifyAfterValueChange() { - if (!m_pForm->m_pFormNotify) - return; - m_pForm->m_pFormNotify->AfterValueChange(this); -} - -bool CPDF_FormField::NotifyListOrComboBoxBeforeChange( - const CFX_WideString& value) { - switch (GetType()) { - case ListBox: - return NotifyBeforeSelectionChange(value); - case ComboBox: - return NotifyBeforeValueChange(value); - default: - return true; - } -} - -void CPDF_FormField::NotifyListOrComboBoxAfterChange() { - switch (GetType()) { - case ListBox: - NotifyAfterSelectionChange(); - break; - case ComboBox: - NotifyAfterValueChange(); - break; - default: - break; - } -} diff --git a/core/fpdfdoc/doc_utils.cpp b/core/fpdfdoc/doc_utils.cpp deleted file mode 100644 index aaaaddf0c6..0000000000 --- a/core/fpdfdoc/doc_utils.cpp +++ /dev/null @@ -1,770 +0,0 @@ -// 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 -#include - -#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/fpdfapi/fpdf_parser/include/fpdf_parser_decode.h" -#include "core/fpdfdoc/doc_utils.h" -#include "core/fpdfdoc/include/cpdf_defaultappearance.h" -#include "core/fpdfdoc/include/cpdf_formcontrol.h" -#include "core/fpdfdoc/include/cpdf_interform.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 nullptr; - } - CPDF_Array* pNumbers = pNode->GetArrayBy("Nums"); - if (pNumbers) { - for (size_t i = 0; i < pNumbers->GetCount() / 2; i++) { - int index = pNumbers->GetIntegerAt(i * 2); - if (num == index) { - return pNumbers->GetDirectObjectAt(i * 2 + 1); - } - if (index > num) { - break; - } - } - return nullptr; - } - CPDF_Array* pKids = pNode->GetArrayBy("Kids"); - if (!pKids) { - return nullptr; - } - for (size_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 nullptr; -} - -} // 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.AsStringC()); - return syntax.FindTagParamFromStart("Tf", 2); -} -CFX_ByteString CPDF_DefaultAppearance::GetFontString() { - CFX_ByteString csFont; - if (m_csDA.IsEmpty()) { - return csFont; - } - CPDF_SimpleParser syntax(m_csDA.AsStringC()); - if (syntax.FindTagParamFromStart("Tf", 2)) { - csFont += syntax.GetWord(); - csFont += " "; - csFont += syntax.GetWord(); - csFont += " "; - csFont += 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.AsStringC()); - 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(PaintOperation nOperation) { - if (m_csDA.IsEmpty()) { - return FALSE; - } - CPDF_SimpleParser syntax(m_csDA.AsStringC()); - if (syntax.FindTagParamFromStart( - (nOperation == PaintOperation::STROKE ? "G" : "g"), 1)) { - return TRUE; - } - if (syntax.FindTagParamFromStart( - (nOperation == PaintOperation::STROKE ? "RG" : "rg"), 3)) { - return TRUE; - } - return syntax.FindTagParamFromStart( - (nOperation == PaintOperation::STROKE ? "K" : "k"), 4); -} -CFX_ByteString CPDF_DefaultAppearance::GetColorString( - PaintOperation nOperation) { - CFX_ByteString csColor; - if (m_csDA.IsEmpty()) { - return csColor; - } - CPDF_SimpleParser syntax(m_csDA.AsStringC()); - if (syntax.FindTagParamFromStart( - (nOperation == PaintOperation::STROKE ? "G" : "g"), 1)) { - csColor += syntax.GetWord(); - csColor += " "; - csColor += syntax.GetWord(); - return csColor; - } - if (syntax.FindTagParamFromStart( - (nOperation == PaintOperation::STROKE ? "RG" : "rg"), 3)) { - csColor += syntax.GetWord(); - csColor += " "; - csColor += syntax.GetWord(); - csColor += " "; - csColor += syntax.GetWord(); - csColor += " "; - csColor += syntax.GetWord(); - return csColor; - } - if (syntax.FindTagParamFromStart( - (nOperation == PaintOperation::STROKE ? "K" : "k"), 4)) { - csColor += syntax.GetWord(); - csColor += " "; - csColor += syntax.GetWord(); - csColor += " "; - csColor += syntax.GetWord(); - csColor += " "; - csColor += syntax.GetWord(); - csColor += " "; - csColor += syntax.GetWord(); - } - return csColor; -} -void CPDF_DefaultAppearance::GetColor(int& iColorType, - FX_FLOAT fc[4], - PaintOperation nOperation) { - iColorType = COLORTYPE_TRANSPARENT; - for (int c = 0; c < 4; c++) { - fc[c] = 0; - } - if (m_csDA.IsEmpty()) { - return; - } - CPDF_SimpleParser syntax(m_csDA.AsStringC()); - if (syntax.FindTagParamFromStart( - (nOperation == PaintOperation::STROKE ? "G" : "g"), 1)) { - iColorType = COLORTYPE_GRAY; - fc[0] = FX_atof(syntax.GetWord()); - return; - } - if (syntax.FindTagParamFromStart( - (nOperation == PaintOperation::STROKE ? "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( - (nOperation == PaintOperation::STROKE ? "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, - PaintOperation nOperation) { - color = 0; - iColorType = COLORTYPE_TRANSPARENT; - if (m_csDA.IsEmpty()) { - return; - } - CPDF_SimpleParser syntax(m_csDA.AsStringC()); - if (syntax.FindTagParamFromStart( - (nOperation == PaintOperation::STROKE ? "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( - (nOperation == PaintOperation::STROKE ? "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( - (nOperation == PaintOperation::STROKE ? "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.AsStringC()); - return syntax.FindTagParamFromStart("Tm", 6); -} -CFX_ByteString CPDF_DefaultAppearance::GetTextMatrixString() { - CFX_ByteString csTM; - if (m_csDA.IsEmpty()) { - return csTM; - } - CPDF_SimpleParser syntax(m_csDA.AsStringC()); - if (syntax.FindTagParamFromStart("Tm", 6)) { - for (int i = 0; i < 6; i++) { - csTM += syntax.GetWord(); - csTM += " "; - } - csTM += syntax.GetWord(); - } - return csTM; -} -CFX_Matrix CPDF_DefaultAppearance::GetTextMatrix() { - CFX_Matrix tm; - if (m_csDA.IsEmpty()) { - return tm; - } - CPDF_SimpleParser syntax(m_csDA.AsStringC()); - 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")) { - CFX_ByteString csBaseName; - CFX_ByteString csDefault; - uint8_t charSet = CPDF_InterForm::GetNativeCharSet(); - CPDF_Font* pFont = CPDF_InterForm::AddStandardFont(pDocument, "Helvetica"); - if (pFont) { - AddInterFormFont(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 = ""; - 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 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* GetInterFormFont(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* GetInterFormFont(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* GetNativeInterFormFont(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* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, - CPDF_Document* pDocument, - CFX_ByteString& csNameTag) { - csNameTag.clear(); - uint8_t charSet = CPDF_InterForm::GetNativeCharSet(); - CPDF_Font* pFont = GetDefaultInterFormFont(pFormDict, pDocument); - if (pFont) { - CFX_SubstFont* pSubst = 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.c_str()); - pFonts->SetAtReference(csNameTag, 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() && - 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); -} - -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); -} - -CPDF_Font* GetDefaultInterFormFont(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 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); - } - } -} - -bool CPDF_IconFit::GetFittingBounds() { - return m_pDict ? m_pDict->GetBooleanBy("FB") : false; -} - -std::vector SaveCheckedFieldStatus(CPDF_FormField* pField) { - std::vector 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 nullptr; - } - if (!pFieldDict) { - return nullptr; - } - CPDF_Object* pAttr = pFieldDict->GetDirectObjectBy(name); - if (pAttr) { - return pAttr; - } - CPDF_Dictionary* pParent = pFieldDict->GetDictBy("Parent"); - if (!pParent) { - return nullptr; - } - return FPDF_GetFieldAttr(pParent, name, nLevel + 1); -} diff --git a/core/fpdfdoc/doc_utils.h b/core/fpdfdoc/doc_utils.h deleted file mode 100644 index 35b7d2d598..0000000000 --- a/core/fpdfdoc/doc_utils.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2015 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 - -#ifndef CORE_FPDFDOC_DOC_UTILS_H_ -#define CORE_FPDFDOC_DOC_UTILS_H_ - -#include - -#include "core/fpdfapi/fpdf_parser/include/cpdf_parser.h" - -class CPDF_Dictionary; -class CPDF_FormField; - -class CPDF_NumberTree { - public: - CPDF_NumberTree(CPDF_Dictionary* pRoot) : m_pRoot(pRoot) {} - CPDF_Object* LookupValue(int num) const; - - protected: - CPDF_Dictionary* const m_pRoot; -}; - -CFX_WideString GetFullName(CPDF_Dictionary* pFieldDict); -void InitInterFormDict(CPDF_Dictionary*& pFormDict, CPDF_Document* pDocument); -uint32_t CountInterFormFonts(CPDF_Dictionary* pFormDict); -CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, - CPDF_Document* pDocument, - uint32_t index, - CFX_ByteString& csNameTag); -CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, - CPDF_Document* pDocument, - CFX_ByteString csNameTag); -CPDF_Font* GetInterFormFont(CPDF_Dictionary* pFormDict, - CPDF_Document* pDocument, - CFX_ByteString csFontName, - CFX_ByteString& csNameTag); -CPDF_Font* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, - CPDF_Document* pDocument, - uint8_t charSet, - CFX_ByteString& csNameTag); -CPDF_Font* GetNativeInterFormFont(CPDF_Dictionary* pFormDict, - CPDF_Document* pDocument, - CFX_ByteString& csNameTag); -FX_BOOL FindInterFormFont(CPDF_Dictionary* pFormDict, - const CPDF_Font* pFont, - CFX_ByteString& csNameTag); -FX_BOOL FindInterFormFont(CPDF_Dictionary* pFormDict, - CPDF_Document* pDocument, - CFX_ByteString csFontName, - CPDF_Font*& pFont, - CFX_ByteString& csNameTag); -void AddInterFormFont(CPDF_Dictionary*& pFormDict, - CPDF_Document* pDocument, - const CPDF_Font* pFont, - CFX_ByteString& csNameTag); -CPDF_Font* AddNativeInterFormFont(CPDF_Dictionary*& pFormDict, - CPDF_Document* pDocument, - uint8_t charSet, - CFX_ByteString& csNameTag); -CPDF_Font* AddNativeInterFormFont(CPDF_Dictionary*& pFormDict, - CPDF_Document* pDocument, - CFX_ByteString& csNameTag); -void RemoveInterFormFont(CPDF_Dictionary* pFormDict, const CPDF_Font* pFont); -void RemoveInterFormFont(CPDF_Dictionary* pFormDict, CFX_ByteString csNameTag); -CPDF_Font* GetDefaultInterFormFont(CPDF_Dictionary* pFormDict, - CPDF_Document* pDocument); -void SetDefaultInterFormFont(CPDF_Dictionary*& pFormDict, - CPDF_Document* pDocument, - const CPDF_Font* pFont); -std::vector SaveCheckedFieldStatus(CPDF_FormField* pField); -FX_BOOL NeedPDFEncodeForFieldFullName(const CFX_WideString& csFieldName); -FX_BOOL NeedPDFEncodeForFieldTree(CPDF_Dictionary* pFieldDict, int nLevel = 0); -void EncodeFieldName(const CFX_WideString& csName, CFX_ByteString& csT); -void UpdateEncodeFieldName(CPDF_Dictionary* pFieldDict, int nLevel = 0); - -#endif // CORE_FPDFDOC_DOC_UTILS_H_ diff --git a/core/fpdfdoc/include/cpdf_formfield.h b/core/fpdfdoc/include/cpdf_formfield.h index 3d9d88fb6b..d39c6da4d4 100644 --- a/core/fpdfdoc/include/cpdf_formfield.h +++ b/core/fpdfdoc/include/cpdf_formfield.h @@ -31,6 +31,7 @@ class CPDF_String; CPDF_Object* FPDF_GetFieldAttr(CPDF_Dictionary* pFieldDict, const FX_CHAR* name, int nLevel = 0); +CFX_WideString FPDF_GetFullName(CPDF_Dictionary* pFieldDict); class CPDF_FormField { public: diff --git a/core/fpdfdoc/include/cpdf_interform.h b/core/fpdfdoc/include/cpdf_interform.h index f07172c42b..6d9d616c89 100644 --- a/core/fpdfdoc/include/cpdf_interform.h +++ b/core/fpdfdoc/include/cpdf_interform.h @@ -27,6 +27,10 @@ class CPDF_Object; class CPDF_Page; class IPDF_FormNotify; +CPDF_Font* AddNativeInterFormFont(CPDF_Dictionary*& pFormDict, + CPDF_Document* pDocument, + CFX_ByteString& csNameTag); + class CPDF_InterForm { public: explicit CPDF_InterForm(CPDF_Document* pDocument); -- cgit v1.2.3