Remove default argument from CPDF_Dictionary::SetAt().
[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     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 }
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 }
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 }
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 == NULL) {
127     return FALSE;
128   }
129   CFX_ByteString csDV = pDV->GetString();
130   CFX_ByteString csOn = GetOnStateName();
131   return (csDV == csOn);
132 }
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);
150 void CPDF_FormControl::DrawControl(CFX_RenderDevice* pDevice,
151                                    CFX_AffineMatrix* 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 == NULL) {
160     return;
161   }
162   CFX_FloatRect form_bbox = pStream->GetDict()->GetRect("BBox");
163   CFX_AffineMatrix form_matrix = pStream->GetDict()->GetMatrix("Matrix");
164   form_matrix.TransformRect(form_bbox);
165   CFX_FloatRect arect = m_pWidgetDict->GetRect("Rect");
166   CFX_AffineMatrix 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;
173   context.Create(pPage);
174   context.DrawObjectList(pDevice, &form, &matrix, pOptions);
175 }
176 const FX_CHAR* g_sHighlightingMode[] = {"N", "I", "O", "P", "T", ""};
177 CPDF_FormControl::HighlightingMode CPDF_FormControl::GetHighlightingMode() {
178   if (m_pWidgetDict == NULL) {
179     return Invert;
180   }
181   CFX_ByteString csH = m_pWidgetDict->GetString("H", "I");
182   int i = 0;
183   while (g_sHighlightingMode[i][0] != '\0') {
184     if (csH.Equal(g_sHighlightingMode[i])) {
185       return (HighlightingMode)i;
186     }
187     i++;
188   }
189   return Invert;
190 }
191 CPDF_ApSettings CPDF_FormControl::GetMK(FX_BOOL bCreate) {
192   if (!m_pWidgetDict) {
193     return NULL;
194   }
195   CPDF_ApSettings mk = m_pWidgetDict->GetDict(FX_BSTRC("MK"));
196   if (!mk && bCreate) {
197     mk = CPDF_Dictionary::Create();
198     if (mk == NULL) {
199       return NULL;
200     }
201     m_pWidgetDict->SetAt(FX_BSTRC("MK"), mk);
202   }
203   return mk;
204 }
205 FX_BOOL CPDF_FormControl::HasMKEntry(CFX_ByteString csEntry) {
206   CPDF_ApSettings mk = GetMK(FALSE);
207   return mk.HasMKEntry(csEntry);
208 }
209 int CPDF_FormControl::GetRotation() {
210   CPDF_ApSettings mk = GetMK(FALSE);
211   return mk.GetRotation();
212 }
213 FX_ARGB CPDF_FormControl::GetColor(int& iColorType, CFX_ByteString csEntry) {
214   CPDF_ApSettings mk = GetMK(FALSE);
215   return mk.GetColor(iColorType, csEntry);
216 }
217 FX_FLOAT CPDF_FormControl::GetOriginalColor(int index, CFX_ByteString csEntry) {
218   CPDF_ApSettings mk = GetMK(FALSE);
219   return mk.GetOriginalColor(index, csEntry);
220 }
221 void CPDF_FormControl::GetOriginalColor(int& iColorType,
222                                         FX_FLOAT fc[4],
223                                         CFX_ByteString csEntry) {
224   CPDF_ApSettings mk = GetMK(FALSE);
225   mk.GetOriginalColor(iColorType, fc, csEntry);
226 }
227 CFX_WideString CPDF_FormControl::GetCaption(CFX_ByteString csEntry) {
228   CPDF_ApSettings mk = GetMK(FALSE);
229   return mk.GetCaption(csEntry);
230 }
231 CPDF_Stream* CPDF_FormControl::GetIcon(CFX_ByteString csEntry) {
232   CPDF_ApSettings mk = GetMK(FALSE);
233   return mk.GetIcon(csEntry);
234 }
235 CPDF_IconFit CPDF_FormControl::GetIconFit() {
236   CPDF_ApSettings mk = GetMK(FALSE);
237   return mk.GetIconFit();
238 }
239 int CPDF_FormControl::GetTextPosition() {
240   CPDF_ApSettings mk = GetMK(FALSE);
241   return mk.GetTextPosition();
242 }
243 CPDF_Action CPDF_FormControl::GetAction() {
244   if (!m_pWidgetDict) {
245     return CPDF_Action();
246   }
247   if (m_pWidgetDict->KeyExist("A")) {
248     return CPDF_Action(m_pWidgetDict->GetDict("A"));
249   }
250   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "A");
251   if (!pObj) {
252     return CPDF_Action();
253   }
254   return CPDF_Action(pObj->GetDict());
255 }
256 CPDF_AAction CPDF_FormControl::GetAdditionalAction() {
257   if (!m_pWidgetDict) {
258     return nullptr;
259   }
260   if (m_pWidgetDict->KeyExist("AA")) {
261     return m_pWidgetDict->GetDict("AA");
262   }
263   return m_pField->GetAdditionalAction();
264 }
265 CPDF_DefaultAppearance CPDF_FormControl::GetDefaultAppearance() {
266   if (!m_pWidgetDict) {
267     return CFX_ByteString();
268   }
269   if (m_pWidgetDict->KeyExist("DA")) {
270     return m_pWidgetDict->GetString("DA");
271   }
272   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "DA");
273   if (!pObj) {
274     return m_pField->m_pForm->GetDefaultAppearance();
275   }
276   return pObj->GetString();
277 }
278
279 CPDF_Font* CPDF_FormControl::GetDefaultControlFont() {
280   CPDF_DefaultAppearance cDA = GetDefaultAppearance();
281   CFX_ByteString csFontNameTag;
282   FX_FLOAT fFontSize;
283   cDA.GetFont(csFontNameTag, fFontSize);
284   if (csFontNameTag.IsEmpty())
285     return nullptr;
286
287   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pWidgetDict, "DR");
288   if (CPDF_Dictionary* pDict = ToDictionary(pObj)) {
289     CPDF_Dictionary* pFonts = pDict->GetDict("Font");
290     if (pFonts) {
291       CPDF_Dictionary* pElement = pFonts->GetDict(csFontNameTag);
292       if (pElement) {
293         CPDF_Font* pFont = m_pField->m_pForm->m_pDocument->LoadFont(pElement);
294         if (pFont) {
295           return pFont;
296         }
297       }
298     }
299   }
300   if (CPDF_Font* pFormFont = m_pField->m_pForm->GetFormFont(csFontNameTag))
301     return pFormFont;
302
303   CPDF_Dictionary* pPageDict = m_pWidgetDict->GetDict("P");
304   pObj = FPDF_GetFieldAttr(pPageDict, "Resources");
305   if (CPDF_Dictionary* pDict = ToDictionary(pObj)) {
306     CPDF_Dictionary* pFonts = pDict->GetDict("Font");
307     if (pFonts) {
308       CPDF_Dictionary* pElement = pFonts->GetDict(csFontNameTag);
309       if (pElement) {
310         CPDF_Font* pFont = m_pField->m_pForm->m_pDocument->LoadFont(pElement);
311         if (pFont) {
312           return pFont;
313         }
314       }
315     }
316   }
317   return nullptr;
318 }
319
320 int CPDF_FormControl::GetControlAlignment() {
321   if (!m_pWidgetDict) {
322     return 0;
323   }
324   if (m_pWidgetDict->KeyExist("Q")) {
325     return m_pWidgetDict->GetInteger("Q", 0);
326   }
327   CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->m_pDict, "Q");
328   if (pObj == NULL) {
329     return m_pField->m_pForm->GetFormAlignment();
330   }
331   return pObj->GetInteger();
332 }
333 FX_BOOL CPDF_ApSettings::HasMKEntry(const CFX_ByteStringC& csEntry) {
334   if (m_pDict == NULL) {
335     return FALSE;
336   }
337   return m_pDict->KeyExist(csEntry);
338 }
339 int CPDF_ApSettings::GetRotation() {
340   if (m_pDict == NULL) {
341     return 0;
342   }
343   return m_pDict->GetInteger(FX_BSTRC("R"));
344 }
345 FX_ARGB CPDF_ApSettings::GetColor(int& iColorType,
346                                   const CFX_ByteStringC& csEntry) {
347   iColorType = COLORTYPE_TRANSPARENT;
348   if (m_pDict == NULL) {
349     return 0;
350   }
351   FX_ARGB color = 0;
352   CPDF_Array* pEntry = m_pDict->GetArray(csEntry);
353   if (pEntry == NULL) {
354     return color;
355   }
356   FX_DWORD dwCount = pEntry->GetCount();
357   if (dwCount == 1) {
358     iColorType = COLORTYPE_GRAY;
359     FX_FLOAT g = pEntry->GetNumber(0) * 255;
360     color = ArgbEncode(255, (int)g, (int)g, (int)g);
361   } else if (dwCount == 3) {
362     iColorType = COLORTYPE_RGB;
363     FX_FLOAT r = pEntry->GetNumber(0) * 255;
364     FX_FLOAT g = pEntry->GetNumber(1) * 255;
365     FX_FLOAT b = pEntry->GetNumber(2) * 255;
366     color = ArgbEncode(255, (int)r, (int)g, (int)b);
367   } else if (dwCount == 4) {
368     iColorType = COLORTYPE_CMYK;
369     FX_FLOAT c = pEntry->GetNumber(0);
370     FX_FLOAT m = pEntry->GetNumber(1);
371     FX_FLOAT y = pEntry->GetNumber(2);
372     FX_FLOAT k = pEntry->GetNumber(3);
373     FX_FLOAT r = 1.0f - FX_MIN(1.0f, c + k);
374     FX_FLOAT g = 1.0f - FX_MIN(1.0f, m + k);
375     FX_FLOAT b = 1.0f - FX_MIN(1.0f, y + k);
376     color = ArgbEncode(255, (int)(r * 255), (int)(g * 255), (int)(b * 255));
377   }
378   return color;
379 }
380 FX_FLOAT CPDF_ApSettings::GetOriginalColor(int index,
381                                            const CFX_ByteStringC& csEntry) {
382   if (m_pDict == NULL) {
383     return 0;
384   }
385   CPDF_Array* pEntry = m_pDict->GetArray(csEntry);
386   if (pEntry != NULL) {
387     return pEntry->GetNumber(index);
388   }
389   return 0;
390 }
391 void CPDF_ApSettings::GetOriginalColor(int& iColorType,
392                                        FX_FLOAT fc[4],
393                                        const CFX_ByteStringC& csEntry) {
394   iColorType = COLORTYPE_TRANSPARENT;
395   for (int i = 0; i < 4; i++) {
396     fc[i] = 0;
397   }
398   if (m_pDict == NULL) {
399     return;
400   }
401   CPDF_Array* pEntry = m_pDict->GetArray(csEntry);
402   if (pEntry == NULL) {
403     return;
404   }
405   FX_DWORD dwCount = pEntry->GetCount();
406   if (dwCount == 1) {
407     iColorType = COLORTYPE_GRAY;
408     fc[0] = pEntry->GetNumber(0);
409   } else if (dwCount == 3) {
410     iColorType = COLORTYPE_RGB;
411     fc[0] = pEntry->GetNumber(0);
412     fc[1] = pEntry->GetNumber(1);
413     fc[2] = pEntry->GetNumber(2);
414   } else if (dwCount == 4) {
415     iColorType = COLORTYPE_CMYK;
416     fc[0] = pEntry->GetNumber(0);
417     fc[1] = pEntry->GetNumber(1);
418     fc[2] = pEntry->GetNumber(2);
419     fc[3] = pEntry->GetNumber(3);
420   }
421 }
422 CFX_WideString CPDF_ApSettings::GetCaption(const CFX_ByteStringC& csEntry) {
423   CFX_WideString csCaption;
424   if (m_pDict == NULL) {
425     return csCaption;
426   }
427   return m_pDict->GetUnicodeText(csEntry);
428 }
429 CPDF_Stream* CPDF_ApSettings::GetIcon(const CFX_ByteStringC& csEntry) {
430   if (m_pDict == NULL) {
431     return NULL;
432   }
433   return m_pDict->GetStream(csEntry);
434 }
435 CPDF_IconFit CPDF_ApSettings::GetIconFit() {
436   if (m_pDict == NULL) {
437     return NULL;
438   }
439   return m_pDict->GetDict(FX_BSTRC("IF"));
440 }
441 int CPDF_ApSettings::GetTextPosition() {
442   if (m_pDict == NULL) {
443     return TEXTPOS_CAPTION;
444   }
445   return m_pDict->GetInteger(FX_BSTRC("TP"), TEXTPOS_CAPTION);
446 }