1 // Copyright 2016 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fpdfdoc/cpdf_formcontrol.h"
8
9 #include <algorithm>
10
11 #include "core/fpdfapi/font/cpdf_font.h"
12 #include "core/fpdfapi/page/cpdf_docpagedata.h"
13 #include "core/fpdfapi/parser/cpdf_array.h"
14 #include "core/fpdfapi/parser/cpdf_dictionary.h"
15 #include "core/fpdfapi/parser/cpdf_document.h"
16 #include "core/fpdfapi/parser/cpdf_name.h"
17 #include "core/fpdfapi/parser/cpdf_stream.h"
18 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
19 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
20 #include "core/fpdfdoc/cpdf_interactiveform.h"
21
22 namespace {
23
24 const char* const g_sHighlightingMode[] = {
25 // Must match order of HighlightingMode enum.
26 "N", "I", "O", "P", "T"};
27
28 } // namespace
29
CPDF_FormControl(CPDF_FormField * pField,CPDF_Dictionary * pWidgetDict)30 CPDF_FormControl::CPDF_FormControl(CPDF_FormField* pField,
31 CPDF_Dictionary* pWidgetDict)
32 : m_pField(pField),
33 m_pWidgetDict(pWidgetDict),
34 m_pForm(m_pField->GetForm()) {}
35
36 CPDF_FormControl::~CPDF_FormControl() = default;
37
GetRect() const38 CFX_FloatRect CPDF_FormControl::GetRect() const {
39 return m_pWidgetDict->GetRectFor("Rect");
40 }
41
GetOnStateName() const42 ByteString CPDF_FormControl::GetOnStateName() const {
43 ASSERT(GetType() == CPDF_FormField::kCheckBox ||
44 GetType() == CPDF_FormField::kRadioButton);
45 ByteString csOn;
46 CPDF_Dictionary* pAP = m_pWidgetDict->GetDictFor("AP");
47 if (!pAP)
48 return csOn;
49
50 CPDF_Dictionary* pN = pAP->GetDictFor("N");
51 if (!pN)
52 return csOn;
53
54 CPDF_DictionaryLocker locker(pN);
55 for (const auto& it : locker) {
56 if (it.first != "Off")
57 return it.first;
58 }
59 return ByteString();
60 }
61
GetCheckedAPState() const62 ByteString CPDF_FormControl::GetCheckedAPState() const {
63 ASSERT(GetType() == CPDF_FormField::kCheckBox ||
64 GetType() == CPDF_FormField::kRadioButton);
65 ByteString csOn = GetOnStateName();
66 if (ToArray(CPDF_FormField::GetFieldAttr(m_pField->GetDict(), "Opt")))
67 csOn = ByteString::Format("%d", m_pField->GetControlIndex(this));
68 if (csOn.IsEmpty())
69 csOn = "Yes";
70 return csOn;
71 }
72
GetExportValue() const73 WideString CPDF_FormControl::GetExportValue() const {
74 ASSERT(GetType() == CPDF_FormField::kCheckBox ||
75 GetType() == CPDF_FormField::kRadioButton);
76 ByteString csOn = GetOnStateName();
77 CPDF_Array* pArray =
78 ToArray(CPDF_FormField::GetFieldAttr(m_pField->GetDict(), "Opt"));
79 if (pArray)
80 csOn = pArray->GetStringAt(m_pField->GetControlIndex(this));
81 if (csOn.IsEmpty())
82 csOn = "Yes";
83 return PDF_DecodeText(csOn.raw_span());
84 }
85
IsChecked() const86 bool CPDF_FormControl::IsChecked() const {
87 ASSERT(GetType() == CPDF_FormField::kCheckBox ||
88 GetType() == CPDF_FormField::kRadioButton);
89 ByteString csOn = GetOnStateName();
90 ByteString csAS = m_pWidgetDict->GetStringFor("AS");
91 return csAS == csOn;
92 }
93
IsDefaultChecked() const94 bool CPDF_FormControl::IsDefaultChecked() const {
95 ASSERT(GetType() == CPDF_FormField::kCheckBox ||
96 GetType() == CPDF_FormField::kRadioButton);
97 CPDF_Object* pDV = CPDF_FormField::GetFieldAttr(m_pField->GetDict(), "DV");
98 if (!pDV)
99 return false;
100
101 ByteString csDV = pDV->GetString();
102 ByteString csOn = GetOnStateName();
103 return (csDV == csOn);
104 }
105
CheckControl(bool bChecked)106 void CPDF_FormControl::CheckControl(bool bChecked) {
107 ASSERT(GetType() == CPDF_FormField::kCheckBox ||
108 GetType() == CPDF_FormField::kRadioButton);
109 ByteString csOldAS = m_pWidgetDict->GetStringFor("AS", "Off");
110 ByteString csAS = "Off";
111 if (bChecked)
112 csAS = GetOnStateName();
113 if (csOldAS == csAS)
114 return;
115 m_pWidgetDict->SetNewFor<CPDF_Name>("AS", csAS);
116 }
117
GetHighlightingMode() const118 CPDF_FormControl::HighlightingMode CPDF_FormControl::GetHighlightingMode()
119 const {
120 if (!m_pWidgetDict)
121 return Invert;
122
123 ByteString csH = m_pWidgetDict->GetStringFor("H", "I");
124 for (size_t i = 0; i < FX_ArraySize(g_sHighlightingMode); ++i) {
125 if (csH == g_sHighlightingMode[i])
126 return static_cast<HighlightingMode>(i);
127 }
128 return Invert;
129 }
130
GetMK() const131 CPDF_ApSettings CPDF_FormControl::GetMK() const {
132 return CPDF_ApSettings(m_pWidgetDict ? m_pWidgetDict->GetDictFor("MK")
133 : nullptr);
134 }
135
HasMKEntry(const ByteString & csEntry) const136 bool CPDF_FormControl::HasMKEntry(const ByteString& csEntry) const {
137 return GetMK().HasMKEntry(csEntry);
138 }
139
GetRotation() const140 int CPDF_FormControl::GetRotation() const {
141 return GetMK().GetRotation();
142 }
143
GetColor(int & iColorType,const ByteString & csEntry)144 FX_ARGB CPDF_FormControl::GetColor(int& iColorType, const ByteString& csEntry) {
145 return GetMK().GetColor(iColorType, csEntry);
146 }
147
GetOriginalColor(int index,const ByteString & csEntry)148 float CPDF_FormControl::GetOriginalColor(int index, const ByteString& csEntry) {
149 return GetMK().GetOriginalColor(index, csEntry);
150 }
151
GetOriginalColor(int & iColorType,float fc[4],const ByteString & csEntry)152 void CPDF_FormControl::GetOriginalColor(int& iColorType,
153 float fc[4],
154 const ByteString& csEntry) {
155 GetMK().GetOriginalColor(iColorType, fc, csEntry);
156 }
157
GetCaption(const ByteString & csEntry) const158 WideString CPDF_FormControl::GetCaption(const ByteString& csEntry) const {
159 return GetMK().GetCaption(csEntry);
160 }
161
GetIcon(const ByteString & csEntry)162 CPDF_Stream* CPDF_FormControl::GetIcon(const ByteString& csEntry) {
163 return GetMK().GetIcon(csEntry);
164 }
165
GetIconFit() const166 CPDF_IconFit CPDF_FormControl::GetIconFit() const {
167 return GetMK().GetIconFit();
168 }
169
GetTextPosition() const170 int CPDF_FormControl::GetTextPosition() const {
171 return GetMK().GetTextPosition();
172 }
173
GetAction() const174 CPDF_Action CPDF_FormControl::GetAction() const {
175 if (!m_pWidgetDict)
176 return CPDF_Action(nullptr);
177
178 if (m_pWidgetDict->KeyExist("A"))
179 return CPDF_Action(m_pWidgetDict->GetDictFor("A"));
180
181 CPDF_Object* pObj = CPDF_FormField::GetFieldAttr(m_pField->GetDict(), "A");
182 return CPDF_Action(pObj ? pObj->GetDict() : nullptr);
183 }
184
GetAdditionalAction() const185 CPDF_AAction CPDF_FormControl::GetAdditionalAction() const {
186 if (!m_pWidgetDict)
187 return CPDF_AAction(nullptr);
188
189 if (m_pWidgetDict->KeyExist("AA"))
190 return CPDF_AAction(m_pWidgetDict->GetDictFor("AA"));
191 return m_pField->GetAdditionalAction();
192 }
193
GetDefaultAppearance() const194 CPDF_DefaultAppearance CPDF_FormControl::GetDefaultAppearance() const {
195 if (!m_pWidgetDict)
196 return CPDF_DefaultAppearance();
197
198 if (m_pWidgetDict->KeyExist("DA"))
199 return CPDF_DefaultAppearance(m_pWidgetDict->GetStringFor("DA"));
200
201 CPDF_Object* pObj = CPDF_FormField::GetFieldAttr(m_pField->GetDict(), "DA");
202 if (!pObj)
203 return m_pForm->GetDefaultAppearance();
204 return CPDF_DefaultAppearance(pObj->GetString());
205 }
206
GetDefaultControlFontName() const207 Optional<WideString> CPDF_FormControl::GetDefaultControlFontName() const {
208 RetainPtr<CPDF_Font> pFont = GetDefaultControlFont();
209 if (!pFont)
210 return {};
211
212 return WideString::FromDefANSI(pFont->GetBaseFontName().AsStringView());
213 }
214
GetDefaultControlFont() const215 RetainPtr<CPDF_Font> CPDF_FormControl::GetDefaultControlFont() const {
216 float fFontSize;
217 CPDF_DefaultAppearance cDA = GetDefaultAppearance();
218 Optional<ByteString> csFontNameTag = cDA.GetFont(&fFontSize);
219 if (!csFontNameTag || csFontNameTag->IsEmpty())
220 return nullptr;
221
222 CPDF_Object* pObj = CPDF_FormField::GetFieldAttr(m_pWidgetDict.Get(), "DR");
223 if (CPDF_Dictionary* pDict = ToDictionary(pObj)) {
224 CPDF_Dictionary* pFonts = pDict->GetDictFor("Font");
225 if (ValidateFontResourceDict(pFonts)) {
226 CPDF_Dictionary* pElement = pFonts->GetDictFor(*csFontNameTag);
227 if (pElement) {
228 auto* pData = CPDF_DocPageData::FromDocument(m_pForm->GetDocument());
229 RetainPtr<CPDF_Font> pFont = pData->GetFont(pElement);
230 if (pFont)
231 return pFont;
232 }
233 }
234 }
235 RetainPtr<CPDF_Font> pFormFont = m_pForm->GetFormFont(*csFontNameTag);
236 if (pFormFont)
237 return pFormFont;
238
239 CPDF_Dictionary* pPageDict = m_pWidgetDict->GetDictFor("P");
240 CPDF_Dictionary* pDict =
241 ToDictionary(CPDF_FormField::GetFieldAttr(pPageDict, "Resources"));
242 if (!pDict)
243 return nullptr;
244
245 CPDF_Dictionary* pFonts = pDict->GetDictFor("Font");
246 if (!ValidateFontResourceDict(pFonts))
247 return nullptr;
248
249 CPDF_Dictionary* pElement = pFonts->GetDictFor(*csFontNameTag);
250 if (!pElement)
251 return nullptr;
252
253 auto* pDocPageData = CPDF_DocPageData::FromDocument(m_pForm->GetDocument());
254 return pDocPageData->GetFont(pElement);
255 }
256
GetControlAlignment() const257 int CPDF_FormControl::GetControlAlignment() const {
258 if (!m_pWidgetDict)
259 return 0;
260 if (m_pWidgetDict->KeyExist("Q"))
261 return m_pWidgetDict->GetIntegerFor("Q", 0);
262
263 CPDF_Object* pObj = CPDF_FormField::GetFieldAttr(m_pField->GetDict(), "Q");
264 if (pObj)
265 return pObj->GetInteger();
266 return m_pForm->GetFormAlignment();
267 }
268