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