• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The PDFium Authors
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 <array>
10 #include <iterator>
11 #include <utility>
12 
13 #include "constants/form_fields.h"
14 #include "core/fpdfapi/font/cpdf_font.h"
15 #include "core/fpdfapi/page/cpdf_docpagedata.h"
16 #include "core/fpdfapi/parser/cpdf_array.h"
17 #include "core/fpdfapi/parser/cpdf_dictionary.h"
18 #include "core/fpdfapi/parser/cpdf_name.h"
19 #include "core/fpdfapi/parser/cpdf_stream.h"
20 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
21 #include "core/fpdfapi/parser/fpdf_parser_utility.h"
22 #include "core/fpdfdoc/cpdf_interactiveform.h"
23 #include "core/fxcrt/check.h"
24 
25 namespace {
26 
27 constexpr std::array<char, 5> kHighlightModes = {{'N', 'I', 'O', 'P', 'T'}};
28 
29 // Order of |kHighlightModes| must match order of HighlightingMode enum.
30 static_assert(kHighlightModes[CPDF_FormControl::kNone] == 'N',
31               "HighlightingMode mismatch");
32 static_assert(kHighlightModes[CPDF_FormControl::kInvert] == 'I',
33               "HighlightingMode mismatch");
34 static_assert(kHighlightModes[CPDF_FormControl::kOutline] == 'O',
35               "HighlightingMode mismatch");
36 static_assert(kHighlightModes[CPDF_FormControl::kPush] == 'P',
37               "HighlightingMode mismatch");
38 static_assert(kHighlightModes[CPDF_FormControl::kToggle] == 'T',
39               "HighlightingMode mismatch");
40 
41 }  // namespace
42 
CPDF_FormControl(CPDF_FormField * pField,RetainPtr<CPDF_Dictionary> pWidgetDict,CPDF_InteractiveForm * pForm)43 CPDF_FormControl::CPDF_FormControl(CPDF_FormField* pField,
44                                    RetainPtr<CPDF_Dictionary> pWidgetDict,
45                                    CPDF_InteractiveForm* pForm)
46     : m_pField(pField), m_pWidgetDict(std::move(pWidgetDict)), m_pForm(pForm) {
47   DCHECK(m_pWidgetDict);
48 }
49 
50 CPDF_FormControl::~CPDF_FormControl() = default;
51 
GetRect() const52 CFX_FloatRect CPDF_FormControl::GetRect() const {
53   return m_pWidgetDict->GetRectFor("Rect");
54 }
55 
GetOnStateName() const56 ByteString CPDF_FormControl::GetOnStateName() const {
57   DCHECK(GetType() == CPDF_FormField::kCheckBox ||
58          GetType() == CPDF_FormField::kRadioButton);
59   RetainPtr<const CPDF_Dictionary> pAP = m_pWidgetDict->GetDictFor("AP");
60   if (!pAP)
61     return ByteString();
62 
63   RetainPtr<const CPDF_Dictionary> pN = pAP->GetDictFor("N");
64   if (!pN)
65     return ByteString();
66 
67   CPDF_DictionaryLocker locker(pN);
68   for (const auto& it : locker) {
69     if (it.first != "Off")
70       return it.first;
71   }
72   return ByteString();
73 }
74 
GetCheckedAPState() const75 ByteString CPDF_FormControl::GetCheckedAPState() const {
76   DCHECK(GetType() == CPDF_FormField::kCheckBox ||
77          GetType() == CPDF_FormField::kRadioButton);
78   ByteString csOn = GetOnStateName();
79   if (ToArray(m_pField->GetFieldAttr("Opt")))
80     csOn = ByteString::FormatInteger(m_pField->GetControlIndex(this));
81   if (csOn.IsEmpty())
82     csOn = "Yes";
83   return csOn;
84 }
85 
GetExportValue() const86 WideString CPDF_FormControl::GetExportValue() const {
87   DCHECK(GetType() == CPDF_FormField::kCheckBox ||
88          GetType() == CPDF_FormField::kRadioButton);
89   ByteString csOn = GetOnStateName();
90   RetainPtr<const CPDF_Array> pArray = ToArray(m_pField->GetFieldAttr("Opt"));
91   if (pArray)
92     csOn = pArray->GetByteStringAt(m_pField->GetControlIndex(this));
93   if (csOn.IsEmpty())
94     csOn = "Yes";
95   return PDF_DecodeText(csOn.unsigned_span());
96 }
97 
IsChecked() const98 bool CPDF_FormControl::IsChecked() const {
99   DCHECK(GetType() == CPDF_FormField::kCheckBox ||
100          GetType() == CPDF_FormField::kRadioButton);
101   ByteString csOn = GetOnStateName();
102   ByteString csAS = m_pWidgetDict->GetByteStringFor("AS");
103   return csAS == csOn;
104 }
105 
IsDefaultChecked() const106 bool CPDF_FormControl::IsDefaultChecked() const {
107   DCHECK(GetType() == CPDF_FormField::kCheckBox ||
108          GetType() == CPDF_FormField::kRadioButton);
109   RetainPtr<const CPDF_Object> pDV = m_pField->GetFieldAttr("DV");
110   if (!pDV)
111     return false;
112 
113   ByteString csDV = pDV->GetString();
114   ByteString csOn = GetOnStateName();
115   return (csDV == csOn);
116 }
117 
CheckControl(bool bChecked)118 void CPDF_FormControl::CheckControl(bool bChecked) {
119   DCHECK(GetType() == CPDF_FormField::kCheckBox ||
120          GetType() == CPDF_FormField::kRadioButton);
121   ByteString csOldAS = m_pWidgetDict->GetByteStringFor("AS", "Off");
122   ByteString csAS = "Off";
123   if (bChecked)
124     csAS = GetOnStateName();
125   if (csOldAS == csAS)
126     return;
127   m_pWidgetDict->SetNewFor<CPDF_Name>("AS", csAS);
128 }
129 
GetHighlightingMode() const130 CPDF_FormControl::HighlightingMode CPDF_FormControl::GetHighlightingMode()
131     const {
132   ByteString csH = m_pWidgetDict->GetByteStringFor("H", "I");
133   for (size_t i = 0; i < std::size(kHighlightModes); ++i) {
134     // TODO(tsepez): disambiguate string ctors.
135       if (csH == ByteStringView(kHighlightModes[i])) {
136         return static_cast<HighlightingMode>(i);
137       }
138   }
139   return kInvert;
140 }
141 
GetMK() const142 CPDF_ApSettings CPDF_FormControl::GetMK() const {
143   return CPDF_ApSettings(m_pWidgetDict->GetMutableDictFor("MK"));
144 }
145 
HasMKEntry(const ByteString & csEntry) const146 bool CPDF_FormControl::HasMKEntry(const ByteString& csEntry) const {
147   return GetMK().HasMKEntry(csEntry);
148 }
149 
GetRotation() const150 int CPDF_FormControl::GetRotation() const {
151   return GetMK().GetRotation();
152 }
153 
GetColorARGB(const ByteString & csEntry)154 CFX_Color::TypeAndARGB CPDF_FormControl::GetColorARGB(
155     const ByteString& csEntry) {
156   return GetMK().GetColorARGB(csEntry);
157 }
158 
GetOriginalColorComponent(int index,const ByteString & csEntry)159 float CPDF_FormControl::GetOriginalColorComponent(int index,
160                                                   const ByteString& csEntry) {
161   return GetMK().GetOriginalColorComponent(index, csEntry);
162 }
163 
GetOriginalColor(const ByteString & csEntry)164 CFX_Color CPDF_FormControl::GetOriginalColor(const ByteString& csEntry) {
165   return GetMK().GetOriginalColor(csEntry);
166 }
167 
GetCaption(const ByteString & csEntry) const168 WideString CPDF_FormControl::GetCaption(const ByteString& csEntry) const {
169   return GetMK().GetCaption(csEntry);
170 }
171 
GetIcon(const ByteString & csEntry)172 RetainPtr<CPDF_Stream> CPDF_FormControl::GetIcon(const ByteString& csEntry) {
173   return GetMK().GetIcon(csEntry);
174 }
175 
GetIconFit() const176 CPDF_IconFit CPDF_FormControl::GetIconFit() const {
177   return GetMK().GetIconFit();
178 }
179 
GetTextPosition() const180 int CPDF_FormControl::GetTextPosition() const {
181   return GetMK().GetTextPosition();
182 }
183 
GetDefaultAppearance() const184 CPDF_DefaultAppearance CPDF_FormControl::GetDefaultAppearance() const {
185   if (m_pWidgetDict->KeyExist(pdfium::form_fields::kDA)) {
186     return CPDF_DefaultAppearance(
187         m_pWidgetDict->GetByteStringFor(pdfium::form_fields::kDA));
188   }
189   RetainPtr<const CPDF_Object> pObj =
190       m_pField->GetFieldAttr(pdfium::form_fields::kDA);
191   if (pObj)
192     return CPDF_DefaultAppearance(pObj->GetString());
193 
194   return m_pForm->GetDefaultAppearance();
195 }
196 
GetDefaultControlFontName() const197 std::optional<WideString> CPDF_FormControl::GetDefaultControlFontName() const {
198   RetainPtr<CPDF_Font> pFont = GetDefaultControlFont();
199   if (!pFont)
200     return std::nullopt;
201 
202   return WideString::FromDefANSI(pFont->GetBaseFontName().AsStringView());
203 }
204 
GetDefaultControlFont() const205 RetainPtr<CPDF_Font> CPDF_FormControl::GetDefaultControlFont() const {
206   float fFontSize;
207   CPDF_DefaultAppearance cDA = GetDefaultAppearance();
208   std::optional<ByteString> csFontNameTag = cDA.GetFont(&fFontSize);
209   if (!csFontNameTag.has_value() || csFontNameTag->IsEmpty())
210     return nullptr;
211 
212   RetainPtr<CPDF_Dictionary> pDRDict = ToDictionary(
213       CPDF_FormField::GetMutableFieldAttrForDict(m_pWidgetDict.Get(), "DR"));
214   if (pDRDict) {
215     RetainPtr<CPDF_Dictionary> pFonts = pDRDict->GetMutableDictFor("Font");
216     if (ValidateFontResourceDict(pFonts.Get())) {
217       RetainPtr<CPDF_Dictionary> pElement =
218           pFonts->GetMutableDictFor(csFontNameTag.value());
219       if (pElement) {
220         RetainPtr<CPDF_Font> pFont =
221             m_pForm->GetFontForElement(std::move(pElement));
222         if (pFont)
223           return pFont;
224       }
225     }
226   }
227   RetainPtr<CPDF_Font> pFormFont = m_pForm->GetFormFont(csFontNameTag.value());
228   if (pFormFont)
229     return pFormFont;
230 
231   RetainPtr<CPDF_Dictionary> pPageDict = m_pWidgetDict->GetMutableDictFor("P");
232   RetainPtr<CPDF_Dictionary> pDict = ToDictionary(
233       CPDF_FormField::GetMutableFieldAttrForDict(pPageDict.Get(), "Resources"));
234   if (!pDict)
235     return nullptr;
236 
237   RetainPtr<CPDF_Dictionary> pFonts = pDict->GetMutableDictFor("Font");
238   if (!ValidateFontResourceDict(pFonts.Get()))
239     return nullptr;
240 
241   RetainPtr<CPDF_Dictionary> pElement =
242       pFonts->GetMutableDictFor(csFontNameTag.value());
243   if (!pElement)
244     return nullptr;
245 
246   return m_pForm->GetFontForElement(std::move(pElement));
247 }
248 
GetControlAlignment() const249 int CPDF_FormControl::GetControlAlignment() const {
250   if (m_pWidgetDict->KeyExist(pdfium::form_fields::kQ))
251     return m_pWidgetDict->GetIntegerFor(pdfium::form_fields::kQ, 0);
252 
253   RetainPtr<const CPDF_Object> pObj =
254       m_pField->GetFieldAttr(pdfium::form_fields::kQ);
255   if (pObj)
256     return pObj->GetInteger();
257 
258   return m_pForm->GetFormAlignment();
259 }
260