• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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