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