1 // Copyright 2014 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 <algorithm>
8
9 #include "core/include/fpdfdoc/fpdf_doc.h"
10
CPDF_FormControl(CPDF_FormField * pField,CPDF_Dictionary * pWidgetDict)11 CPDF_FormControl::CPDF_FormControl(CPDF_FormField* pField,
12 CPDF_Dictionary* pWidgetDict) {
13 m_pField = pField;
14 m_pWidgetDict = pWidgetDict;
15 m_pForm = m_pField->m_pForm;
16 }
GetRect() const17 CFX_FloatRect CPDF_FormControl::GetRect() const {
18 return m_pWidgetDict->GetRect("Rect");
19 }
GetOnStateName()20 CFX_ByteString CPDF_FormControl::GetOnStateName() {
21 ASSERT(GetType() == CPDF_FormField::CheckBox ||
22 GetType() == CPDF_FormField::RadioButton);
23 CFX_ByteString csOn;
24 CPDF_Dictionary* pAP = m_pWidgetDict->GetDict("AP");
25 if (!pAP) {
26 return csOn;
27 }
28 CPDF_Dictionary* pN = pAP->GetDict("N");
29 if (!pN) {
30 return csOn;
31 }
32 for (const auto& it : *pN) {
33 if (it.first != "Off") {
34 return it.first;
35 }
36 }
37 return CFX_ByteString();
38 }
SetOnStateName(const CFX_ByteString & csOn)39 void CPDF_FormControl::SetOnStateName(const CFX_ByteString& csOn) {
40 ASSERT(GetType() == CPDF_FormField::CheckBox ||
41 GetType() == CPDF_FormField::RadioButton);
42 CFX_ByteString csValue = csOn;
43 if (csValue.IsEmpty()) {
44 csValue = "Yes";
45 }
46 if (csValue == "Off") {
47 csValue = "Yes";
48 }
49 CFX_ByteString csAS = m_pWidgetDict->GetString("AS", "Off");
50 if (csAS != "Off") {
51 m_pWidgetDict->SetAtName("AS", csValue);
52 }
53 CPDF_Dictionary* pAP = m_pWidgetDict->GetDict("AP");
54 if (!pAP) {
55 return;
56 }
57 for (const auto& it : *pAP) {
58 CPDF_Object* pObj1 = it.second;
59 if (!pObj1) {
60 continue;
61 }
62 CPDF_Object* pObjDirect1 = pObj1->GetDirect();
63 CPDF_Dictionary* pSubDict = pObjDirect1->AsDictionary();
64 if (!pSubDict)
65 continue;
66
67 auto subdict_it = pSubDict->begin();
68 while (subdict_it != pSubDict->end()) {
69 const CFX_ByteString& csKey2 = subdict_it->first;
70 CPDF_Object* pObj2 = subdict_it->second;
71 ++subdict_it;
72 if (!pObj2) {
73 continue;
74 }
75 if (csKey2 != "Off") {
76 pSubDict->ReplaceKey(csKey2, csValue);
77 break;
78 }
79 }
80 }
81 }
GetCheckedAPState()82 CFX_ByteString CPDF_FormControl::GetCheckedAPState() {
83 ASSERT(GetType() == CPDF_FormField::CheckBox ||
84 GetType() == CPDF_FormField::RadioButton);
85 CFX_ByteString csOn = GetOnStateName();
86 if (GetType() == CPDF_FormField::RadioButton ||
87 GetType() == CPDF_FormField::CheckBox) {
88 if (ToArray(FPDF_GetFieldAttr(m_pField->m_pDict, "Opt"))) {
89 int iIndex = m_pField->GetControlIndex(this);
90 csOn.Format("%d", iIndex);
91 }
92 }
93 if (csOn.IsEmpty())
94 csOn = "Yes";
95 return csOn;
96 }
GetExportValue()97 CFX_WideString CPDF_FormControl::GetExportValue() {
98 ASSERT(GetType() == CPDF_FormField::CheckBox ||
99 GetType() == CPDF_FormField::RadioButton);
100 CFX_ByteString csOn = GetOnStateName();
101 if (GetType() == CPDF_FormField::RadioButton ||
102 GetType() == CPDF_FormField::CheckBox) {
103 if (CPDF_Array* pArray =
104 ToArray(FPDF_GetFieldAttr(m_pField->m_pDict, "Opt"))) {
105 int iIndex = m_pField->GetControlIndex(this);
106 csOn = pArray->GetString(iIndex);
107 }
108 }
109 if (csOn.IsEmpty()) {
110 csOn = "Yes";
111 }
112 CFX_WideString csWOn = PDF_DecodeText(csOn);
113 return csWOn;
114 }
IsChecked()115 FX_BOOL CPDF_FormControl::IsChecked() {
116 ASSERT(GetType() == CPDF_FormField::CheckBox ||
117 GetType() == CPDF_FormField::RadioButton);
118 CFX_ByteString csOn = GetOnStateName();
119 CFX_ByteString csAS = m_pWidgetDict->GetString("AS");
120 return csAS == csOn;
121 }
IsDefaultChecked()122 FX_BOOL CPDF_FormControl::IsDefaultChecked() {
123 ASSERT(GetType() == CPDF_FormField::CheckBox ||
124 GetType() == CPDF_FormField::RadioButton);
125 CPDF_Object* pDV = FPDF_GetFieldAttr(m_pField->m_pDict, "DV");
126 if (!pDV) {
127 return FALSE;
128 }
129 CFX_ByteString csDV = pDV->GetString();
130 CFX_ByteString csOn = GetOnStateName();
131 return (csDV == csOn);
132 }
CheckControl(FX_BOOL bChecked)133 void CPDF_FormControl::CheckControl(FX_BOOL bChecked) {
134 ASSERT(GetType() == CPDF_FormField::CheckBox ||
135 GetType() == CPDF_FormField::RadioButton);
136 CFX_ByteString csOn = GetOnStateName();
137 CFX_ByteString csOldAS = m_pWidgetDict->GetString("AS", "Off");
138 CFX_ByteString csAS = "Off";
139 if (bChecked) {
140 csAS = csOn;
141 }
142 if (csOldAS == csAS) {
143 return;
144 }
145 m_pWidgetDict->SetAtName("AS", csAS);
146 m_pForm->m_bUpdated = TRUE;
147 }
148 CPDF_Stream* FPDFDOC_GetAnnotAP(CPDF_Dictionary* pAnnotDict,
149 CPDF_Annot::AppearanceMode mode);
DrawControl(CFX_RenderDevice * pDevice,CFX_Matrix * pMatrix,CPDF_Page * pPage,CPDF_Annot::AppearanceMode mode,const CPDF_RenderOptions * pOptions)150 void CPDF_FormControl::DrawControl(CFX_RenderDevice* pDevice,
151 CFX_Matrix* pMatrix,
152 CPDF_Page* pPage,
153 CPDF_Annot::AppearanceMode mode,
154 const CPDF_RenderOptions* pOptions) {
155 if (m_pWidgetDict->GetInteger("F") & ANNOTFLAG_HIDDEN) {
156 return;
157 }
158 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(m_pWidgetDict, mode);
159 if (!pStream) {
160 return;
161 }
162 CFX_FloatRect form_bbox = pStream->GetDict()->GetRect("BBox");
163 CFX_Matrix form_matrix = pStream->GetDict()->GetMatrix("Matrix");
164 form_matrix.TransformRect(form_bbox);
165 CFX_FloatRect arect = m_pWidgetDict->GetRect("Rect");
166 CFX_Matrix matrix;
167 matrix.MatchRect(arect, form_bbox);
168 matrix.Concat(*pMatrix);
169 CPDF_Form form(m_pField->m_pForm->m_pDocument,
170 m_pField->m_pForm->m_pFormDict->GetDict("DR"), pStream);
171 form.ParseContent(NULL, NULL, NULL, NULL);
172 CPDF_RenderContext context(pPage);
173 context.DrawObjectList(pDevice, &form, &matrix, pOptions);
174 }
175 static const FX_CHAR* const g_sHighlightingMode[] = {
176 // Must match order of HiglightingMode enum.
177 "N", "I", "O", "P", "T", nullptr};
GetHighlightingMode()178 CPDF_FormControl::HighlightingMode CPDF_FormControl::GetHighlightingMode() {
179 if (!m_pWidgetDict) {
180 return Invert;
181 }
182 CFX_ByteString csH = m_pWidgetDict->GetString("H", "I");
183 for (int i = 0; g_sHighlightingMode[i]; ++i) {
184 if (csH.Equal(g_sHighlightingMode[i]))
185 return static_cast<HighlightingMode>(i);
186 }
187 return Invert;
188 }
189
GetMK() const190 CPDF_ApSettings CPDF_FormControl::GetMK() const {
191 return CPDF_ApSettings(m_pWidgetDict ? m_pWidgetDict->GetDict("MK")
192 : nullptr);
193 }
194
HasMKEntry(CFX_ByteString csEntry) const195 bool CPDF_FormControl::HasMKEntry(CFX_ByteString csEntry) const {
196 return GetMK().HasMKEntry(csEntry);
197 }
198
GetRotation()199 int CPDF_FormControl::GetRotation() {
200 return GetMK().GetRotation();
201 }
202
GetColor(int & iColorType,CFX_ByteString csEntry)203 FX_ARGB CPDF_FormControl::GetColor(int& iColorType, CFX_ByteString csEntry) {
204 return GetMK().GetColor(iColorType, csEntry);
205 }
206
GetOriginalColor(int index,CFX_ByteString csEntry)207 FX_FLOAT CPDF_FormControl::GetOriginalColor(int index, CFX_ByteString csEntry) {
208 return GetMK().GetOriginalColor(index, csEntry);
209 }
210
GetOriginalColor(int & iColorType,FX_FLOAT fc[4],CFX_ByteString csEntry)211 void CPDF_FormControl::GetOriginalColor(int& iColorType,
212 FX_FLOAT fc[4],
213 CFX_ByteString csEntry) {
214 GetMK().GetOriginalColor(iColorType, fc, csEntry);
215 }
GetCaption(CFX_ByteString csEntry)216 CFX_WideString CPDF_FormControl::GetCaption(CFX_ByteString csEntry) {
217 return GetMK().GetCaption(csEntry);
218 }
219
GetIcon(CFX_ByteString csEntry)220 CPDF_Stream* CPDF_FormControl::GetIcon(CFX_ByteString csEntry) {
221 return GetMK().GetIcon(csEntry);
222 }
223
GetIconFit()224 CPDF_IconFit CPDF_FormControl::GetIconFit() {
225 return GetMK().GetIconFit();
226 }
227
GetTextPosition()228 int CPDF_FormControl::GetTextPosition() {
229 return GetMK().GetTextPosition();
230 }
231
GetAction()232 CPDF_Action CPDF_FormControl::GetAction() {
233 if (!m_pWidgetDict) {
234 return CPDF_Action();
235 }
236 if (m_pWidgetDict->KeyExist("A")) {
237 return CPDF_Action(m_pWidgetDict->GetDict("A"));
238 }
239 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "A");
240 if (!pObj) {
241 return CPDF_Action();
242 }
243 return CPDF_Action(pObj->GetDict());
244 }
GetAdditionalAction()245 CPDF_AAction CPDF_FormControl::GetAdditionalAction() {
246 if (!m_pWidgetDict) {
247 return nullptr;
248 }
249 if (m_pWidgetDict->KeyExist("AA")) {
250 return m_pWidgetDict->GetDict("AA");
251 }
252 return m_pField->GetAdditionalAction();
253 }
GetDefaultAppearance()254 CPDF_DefaultAppearance CPDF_FormControl::GetDefaultAppearance() {
255 if (!m_pWidgetDict) {
256 return CFX_ByteString();
257 }
258 if (m_pWidgetDict->KeyExist("DA")) {
259 return m_pWidgetDict->GetString("DA");
260 }
261 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "DA");
262 if (!pObj) {
263 return m_pField->m_pForm->GetDefaultAppearance();
264 }
265 return pObj->GetString();
266 }
267
GetDefaultControlFont()268 CPDF_Font* CPDF_FormControl::GetDefaultControlFont() {
269 CPDF_DefaultAppearance cDA = GetDefaultAppearance();
270 CFX_ByteString csFontNameTag;
271 FX_FLOAT fFontSize;
272 cDA.GetFont(csFontNameTag, fFontSize);
273 if (csFontNameTag.IsEmpty())
274 return nullptr;
275
276 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pWidgetDict, "DR");
277 if (CPDF_Dictionary* pDict = ToDictionary(pObj)) {
278 CPDF_Dictionary* pFonts = pDict->GetDict("Font");
279 if (pFonts) {
280 CPDF_Dictionary* pElement = pFonts->GetDict(csFontNameTag);
281 if (pElement) {
282 CPDF_Font* pFont = m_pField->m_pForm->m_pDocument->LoadFont(pElement);
283 if (pFont) {
284 return pFont;
285 }
286 }
287 }
288 }
289 if (CPDF_Font* pFormFont = m_pField->m_pForm->GetFormFont(csFontNameTag))
290 return pFormFont;
291
292 CPDF_Dictionary* pPageDict = m_pWidgetDict->GetDict("P");
293 pObj = FPDF_GetFieldAttr(pPageDict, "Resources");
294 if (CPDF_Dictionary* pDict = ToDictionary(pObj)) {
295 CPDF_Dictionary* pFonts = pDict->GetDict("Font");
296 if (pFonts) {
297 CPDF_Dictionary* pElement = pFonts->GetDict(csFontNameTag);
298 if (pElement) {
299 CPDF_Font* pFont = m_pField->m_pForm->m_pDocument->LoadFont(pElement);
300 if (pFont) {
301 return pFont;
302 }
303 }
304 }
305 }
306 return nullptr;
307 }
308
GetControlAlignment()309 int CPDF_FormControl::GetControlAlignment() {
310 if (!m_pWidgetDict) {
311 return 0;
312 }
313 if (m_pWidgetDict->KeyExist("Q")) {
314 return m_pWidgetDict->GetInteger("Q", 0);
315 }
316 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "Q");
317 if (pObj)
318 return pObj->GetInteger();
319 return m_pField->m_pForm->GetFormAlignment();
320 }
321
CPDF_ApSettings(CPDF_Dictionary * pDict)322 CPDF_ApSettings::CPDF_ApSettings(CPDF_Dictionary* pDict) : m_pDict(pDict) {}
323
HasMKEntry(const CFX_ByteStringC & csEntry) const324 bool CPDF_ApSettings::HasMKEntry(const CFX_ByteStringC& csEntry) const {
325 return m_pDict && m_pDict->KeyExist(csEntry);
326 }
327
GetRotation() const328 int CPDF_ApSettings::GetRotation() const {
329 return m_pDict ? m_pDict->GetInteger("R") : 0;
330 }
331
GetColor(int & iColorType,const CFX_ByteStringC & csEntry) const332 FX_ARGB CPDF_ApSettings::GetColor(int& iColorType,
333 const CFX_ByteStringC& csEntry) const {
334 iColorType = COLORTYPE_TRANSPARENT;
335 if (!m_pDict)
336 return 0;
337
338 CPDF_Array* pEntry = m_pDict->GetArray(csEntry);
339 if (!pEntry)
340 return 0;
341
342 FX_ARGB color = 0;
343 FX_DWORD dwCount = pEntry->GetCount();
344 if (dwCount == 1) {
345 iColorType = COLORTYPE_GRAY;
346 FX_FLOAT g = pEntry->GetNumber(0) * 255;
347 color = ArgbEncode(255, (int)g, (int)g, (int)g);
348 } else if (dwCount == 3) {
349 iColorType = COLORTYPE_RGB;
350 FX_FLOAT r = pEntry->GetNumber(0) * 255;
351 FX_FLOAT g = pEntry->GetNumber(1) * 255;
352 FX_FLOAT b = pEntry->GetNumber(2) * 255;
353 color = ArgbEncode(255, (int)r, (int)g, (int)b);
354 } else if (dwCount == 4) {
355 iColorType = COLORTYPE_CMYK;
356 FX_FLOAT c = pEntry->GetNumber(0);
357 FX_FLOAT m = pEntry->GetNumber(1);
358 FX_FLOAT y = pEntry->GetNumber(2);
359 FX_FLOAT k = pEntry->GetNumber(3);
360 FX_FLOAT r = 1.0f - std::min(1.0f, c + k);
361 FX_FLOAT g = 1.0f - std::min(1.0f, m + k);
362 FX_FLOAT b = 1.0f - std::min(1.0f, y + k);
363 color = ArgbEncode(255, (int)(r * 255), (int)(g * 255), (int)(b * 255));
364 }
365 return color;
366 }
367
GetOriginalColor(int index,const CFX_ByteStringC & csEntry) const368 FX_FLOAT CPDF_ApSettings::GetOriginalColor(
369 int index,
370 const CFX_ByteStringC& csEntry) const {
371 if (!m_pDict)
372 return 0;
373
374 CPDF_Array* pEntry = m_pDict->GetArray(csEntry);
375 return pEntry ? pEntry->GetNumber(index) : 0;
376 }
377
GetOriginalColor(int & iColorType,FX_FLOAT fc[4],const CFX_ByteStringC & csEntry) const378 void CPDF_ApSettings::GetOriginalColor(int& iColorType,
379 FX_FLOAT fc[4],
380 const CFX_ByteStringC& csEntry) const {
381 iColorType = COLORTYPE_TRANSPARENT;
382 for (int i = 0; i < 4; i++) {
383 fc[i] = 0;
384 }
385 if (!m_pDict) {
386 return;
387 }
388 CPDF_Array* pEntry = m_pDict->GetArray(csEntry);
389 if (!pEntry) {
390 return;
391 }
392 FX_DWORD dwCount = pEntry->GetCount();
393 if (dwCount == 1) {
394 iColorType = COLORTYPE_GRAY;
395 fc[0] = pEntry->GetNumber(0);
396 } else if (dwCount == 3) {
397 iColorType = COLORTYPE_RGB;
398 fc[0] = pEntry->GetNumber(0);
399 fc[1] = pEntry->GetNumber(1);
400 fc[2] = pEntry->GetNumber(2);
401 } else if (dwCount == 4) {
402 iColorType = COLORTYPE_CMYK;
403 fc[0] = pEntry->GetNumber(0);
404 fc[1] = pEntry->GetNumber(1);
405 fc[2] = pEntry->GetNumber(2);
406 fc[3] = pEntry->GetNumber(3);
407 }
408 }
409
GetCaption(const CFX_ByteStringC & csEntry) const410 CFX_WideString CPDF_ApSettings::GetCaption(
411 const CFX_ByteStringC& csEntry) const {
412 return m_pDict ? m_pDict->GetUnicodeText(csEntry) : CFX_WideString();
413 }
414
GetIcon(const CFX_ByteStringC & csEntry) const415 CPDF_Stream* CPDF_ApSettings::GetIcon(const CFX_ByteStringC& csEntry) const {
416 return m_pDict ? m_pDict->GetStream(csEntry) : nullptr;
417 }
418
GetIconFit() const419 CPDF_IconFit CPDF_ApSettings::GetIconFit() const {
420 return m_pDict ? m_pDict->GetDict("IF") : nullptr;
421 }
422
GetTextPosition() const423 int CPDF_ApSettings::GetTextPosition() const {
424 return m_pDict ? m_pDict->GetInteger("TP", TEXTPOS_CAPTION) : TEXTPOS_CAPTION;
425 }
426