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/page/cpdf_form.h" 12 #include "core/fpdfapi/parser/cpdf_array.h" 13 #include "core/fpdfapi/parser/cpdf_document.h" 14 #include "core/fpdfapi/parser/cpdf_name.h" 15 #include "core/fpdfapi/parser/cpdf_stream.h" 16 #include "core/fpdfapi/parser/fpdf_parser_decode.h" 17 #include "core/fpdfapi/render/cpdf_rendercontext.h" 18 #include "core/fpdfdoc/cpdf_interform.h" 19 #include "core/fxge/cfx_renderdevice.h" 20 21 namespace { 22 23 const char* const g_sHighlightingMode[] = { 24 // Must match order of HighlightingMode enum. 25 "N", "I", "O", "P", "T"}; 26 27 } // namespace 28 29 CPDF_FormControl::CPDF_FormControl(CPDF_FormField* pField, 30 CPDF_Dictionary* pWidgetDict) 31 : m_pField(pField), 32 m_pWidgetDict(pWidgetDict), 33 m_pForm(m_pField->GetForm()) {} 34 35 CPDF_FormControl::~CPDF_FormControl() {} 36 37 ByteString CPDF_FormControl::GetOnStateName() const { 38 ASSERT(GetType() == CPDF_FormField::CheckBox || 39 GetType() == CPDF_FormField::RadioButton); 40 ByteString csOn; 41 CPDF_Dictionary* pAP = m_pWidgetDict->GetDictFor("AP"); 42 if (!pAP) 43 return csOn; 44 45 CPDF_Dictionary* pN = pAP->GetDictFor("N"); 46 if (!pN) 47 return csOn; 48 49 for (const auto& it : *pN) { 50 if (it.first != "Off") 51 return it.first; 52 } 53 return ByteString(); 54 } 55 56 void CPDF_FormControl::SetOnStateName(const ByteString& csOn) { 57 ASSERT(GetType() == CPDF_FormField::CheckBox || 58 GetType() == CPDF_FormField::RadioButton); 59 ByteString csValue = csOn; 60 if (csValue.IsEmpty()) 61 csValue = "Yes"; 62 else if (csValue == "Off") 63 csValue = "Yes"; 64 65 ByteString csAS = m_pWidgetDict->GetStringFor("AS", "Off"); 66 if (csAS != "Off") 67 m_pWidgetDict->SetNewFor<CPDF_Name>("AS", csValue); 68 69 CPDF_Dictionary* pAP = m_pWidgetDict->GetDictFor("AP"); 70 if (!pAP) 71 return; 72 73 for (const auto& it : *pAP) { 74 CPDF_Object* pObj1 = it.second.get(); 75 if (!pObj1) 76 continue; 77 78 CPDF_Object* pObjDirect1 = pObj1->GetDirect(); 79 CPDF_Dictionary* pSubDict = pObjDirect1->AsDictionary(); 80 if (!pSubDict) 81 continue; 82 83 auto subdict_it = pSubDict->begin(); 84 while (subdict_it != pSubDict->end()) { 85 const ByteString& csKey2 = subdict_it->first; 86 CPDF_Object* pObj2 = subdict_it->second.get(); 87 ++subdict_it; 88 if (!pObj2) 89 continue; 90 if (csKey2 != "Off") { 91 pSubDict->ReplaceKey(csKey2, csValue); 92 break; 93 } 94 } 95 } 96 } 97 98 ByteString CPDF_FormControl::GetCheckedAPState() { 99 ASSERT(GetType() == CPDF_FormField::CheckBox || 100 GetType() == CPDF_FormField::RadioButton); 101 ByteString csOn = GetOnStateName(); 102 if (GetType() == CPDF_FormField::RadioButton || 103 GetType() == CPDF_FormField::CheckBox) { 104 if (ToArray(FPDF_GetFieldAttr(m_pField->GetDict(), "Opt"))) 105 csOn = ByteString::Format("%d", m_pField->GetControlIndex(this)); 106 } 107 if (csOn.IsEmpty()) 108 csOn = "Yes"; 109 return csOn; 110 } 111 112 WideString CPDF_FormControl::GetExportValue() const { 113 ASSERT(GetType() == CPDF_FormField::CheckBox || 114 GetType() == CPDF_FormField::RadioButton); 115 ByteString csOn = GetOnStateName(); 116 if (GetType() == CPDF_FormField::RadioButton || 117 GetType() == CPDF_FormField::CheckBox) { 118 if (CPDF_Array* pArray = 119 ToArray(FPDF_GetFieldAttr(m_pField->GetDict(), "Opt"))) { 120 int iIndex = m_pField->GetControlIndex(this); 121 csOn = pArray->GetStringAt(iIndex); 122 } 123 } 124 if (csOn.IsEmpty()) 125 csOn = "Yes"; 126 return PDF_DecodeText(csOn); 127 } 128 129 bool CPDF_FormControl::IsChecked() const { 130 ASSERT(GetType() == CPDF_FormField::CheckBox || 131 GetType() == CPDF_FormField::RadioButton); 132 ByteString csOn = GetOnStateName(); 133 ByteString csAS = m_pWidgetDict->GetStringFor("AS"); 134 return csAS == csOn; 135 } 136 137 bool CPDF_FormControl::IsDefaultChecked() const { 138 ASSERT(GetType() == CPDF_FormField::CheckBox || 139 GetType() == CPDF_FormField::RadioButton); 140 CPDF_Object* pDV = FPDF_GetFieldAttr(m_pField->GetDict(), "DV"); 141 if (!pDV) 142 return false; 143 144 ByteString csDV = pDV->GetString(); 145 ByteString csOn = GetOnStateName(); 146 return (csDV == csOn); 147 } 148 149 void CPDF_FormControl::CheckControl(bool bChecked) { 150 ASSERT(GetType() == CPDF_FormField::CheckBox || 151 GetType() == CPDF_FormField::RadioButton); 152 ByteString csOn = GetOnStateName(); 153 ByteString csOldAS = m_pWidgetDict->GetStringFor("AS", "Off"); 154 ByteString csAS = "Off"; 155 if (bChecked) 156 csAS = csOn; 157 if (csOldAS == csAS) 158 return; 159 m_pWidgetDict->SetNewFor<CPDF_Name>("AS", csAS); 160 } 161 162 void CPDF_FormControl::DrawControl(CFX_RenderDevice* pDevice, 163 CFX_Matrix* pMatrix, 164 CPDF_Page* pPage, 165 CPDF_Annot::AppearanceMode mode, 166 const CPDF_RenderOptions* pOptions) { 167 if (m_pWidgetDict->GetIntegerFor("F") & ANNOTFLAG_HIDDEN) 168 return; 169 170 CPDF_Stream* pStream = FPDFDOC_GetAnnotAP(m_pWidgetDict.Get(), mode); 171 if (!pStream) 172 return; 173 174 CFX_Matrix form_matrix = pStream->GetDict()->GetMatrixFor("Matrix"); 175 CFX_FloatRect form_bbox = 176 form_matrix.TransformRect(pStream->GetDict()->GetRectFor("BBox")); 177 CFX_FloatRect arect = m_pWidgetDict->GetRectFor("Rect"); 178 CFX_Matrix matrix; 179 matrix.MatchRect(arect, form_bbox); 180 matrix.Concat(*pMatrix); 181 CPDF_Form form(m_pField->GetForm()->GetDocument(), 182 m_pField->GetForm()->GetFormDict()->GetDictFor("DR"), pStream); 183 form.ParseContent(); 184 CPDF_RenderContext context(pPage); 185 context.AppendLayer(&form, &matrix); 186 context.Render(pDevice, pOptions, nullptr); 187 } 188 189 CPDF_FormControl::HighlightingMode CPDF_FormControl::GetHighlightingMode() { 190 if (!m_pWidgetDict) 191 return Invert; 192 193 ByteString csH = m_pWidgetDict->GetStringFor("H", "I"); 194 for (size_t i = 0; i < FX_ArraySize(g_sHighlightingMode); ++i) { 195 if (csH == g_sHighlightingMode[i]) 196 return static_cast<HighlightingMode>(i); 197 } 198 return Invert; 199 } 200 201 CPDF_ApSettings CPDF_FormControl::GetMK() const { 202 return CPDF_ApSettings(m_pWidgetDict ? m_pWidgetDict->GetDictFor("MK") 203 : nullptr); 204 } 205 206 bool CPDF_FormControl::HasMKEntry(const ByteString& csEntry) const { 207 return GetMK().HasMKEntry(csEntry); 208 } 209 210 int CPDF_FormControl::GetRotation() { 211 return GetMK().GetRotation(); 212 } 213 214 FX_ARGB CPDF_FormControl::GetColor(int& iColorType, const ByteString& csEntry) { 215 return GetMK().GetColor(iColorType, csEntry); 216 } 217 218 float CPDF_FormControl::GetOriginalColor(int index, const ByteString& csEntry) { 219 return GetMK().GetOriginalColor(index, csEntry); 220 } 221 222 void CPDF_FormControl::GetOriginalColor(int& iColorType, 223 float fc[4], 224 const ByteString& csEntry) { 225 GetMK().GetOriginalColor(iColorType, fc, csEntry); 226 } 227 228 WideString CPDF_FormControl::GetCaption(const ByteString& csEntry) { 229 return GetMK().GetCaption(csEntry); 230 } 231 232 CPDF_Stream* CPDF_FormControl::GetIcon(const ByteString& csEntry) { 233 return GetMK().GetIcon(csEntry); 234 } 235 236 CPDF_IconFit CPDF_FormControl::GetIconFit() { 237 return GetMK().GetIconFit(); 238 } 239 240 int CPDF_FormControl::GetTextPosition() { 241 return GetMK().GetTextPosition(); 242 } 243 244 CPDF_Action CPDF_FormControl::GetAction() { 245 if (!m_pWidgetDict) 246 return CPDF_Action(nullptr); 247 248 if (m_pWidgetDict->KeyExist("A")) 249 return CPDF_Action(m_pWidgetDict->GetDictFor("A")); 250 251 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->GetDict(), "A"); 252 return CPDF_Action(pObj ? pObj->GetDict() : nullptr); 253 } 254 255 CPDF_AAction CPDF_FormControl::GetAdditionalAction() { 256 if (!m_pWidgetDict) 257 return CPDF_AAction(nullptr); 258 259 if (m_pWidgetDict->KeyExist("AA")) 260 return CPDF_AAction(m_pWidgetDict->GetDictFor("AA")); 261 return m_pField->GetAdditionalAction(); 262 } 263 264 CPDF_DefaultAppearance CPDF_FormControl::GetDefaultAppearance() { 265 if (!m_pWidgetDict) 266 return CPDF_DefaultAppearance(); 267 268 if (m_pWidgetDict->KeyExist("DA")) 269 return CPDF_DefaultAppearance(m_pWidgetDict->GetStringFor("DA")); 270 271 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->GetDict(), "DA"); 272 if (pObj) 273 return CPDF_DefaultAppearance(pObj->GetString()); 274 return m_pField->GetForm()->GetDefaultAppearance(); 275 } 276 277 CPDF_Font* CPDF_FormControl::GetDefaultControlFont() { 278 float fFontSize; 279 CPDF_DefaultAppearance cDA = GetDefaultAppearance(); 280 ByteString csFontNameTag = cDA.GetFont(&fFontSize); 281 if (csFontNameTag.IsEmpty()) 282 return nullptr; 283 284 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pWidgetDict.Get(), "DR"); 285 if (CPDF_Dictionary* pDict = ToDictionary(pObj)) { 286 CPDF_Dictionary* pFonts = pDict->GetDictFor("Font"); 287 if (pFonts) { 288 CPDF_Dictionary* pElement = pFonts->GetDictFor(csFontNameTag); 289 if (pElement) { 290 CPDF_Font* pFont = 291 m_pField->GetForm()->GetDocument()->LoadFont(pElement); 292 if (pFont) 293 return pFont; 294 } 295 } 296 } 297 if (CPDF_Font* pFormFont = m_pField->GetForm()->GetFormFont(csFontNameTag)) 298 return pFormFont; 299 300 CPDF_Dictionary* pPageDict = m_pWidgetDict->GetDictFor("P"); 301 pObj = FPDF_GetFieldAttr(pPageDict, "Resources"); 302 if (CPDF_Dictionary* pDict = ToDictionary(pObj)) { 303 CPDF_Dictionary* pFonts = pDict->GetDictFor("Font"); 304 if (pFonts) { 305 CPDF_Dictionary* pElement = pFonts->GetDictFor(csFontNameTag); 306 if (pElement) { 307 CPDF_Font* pFont = 308 m_pField->GetForm()->GetDocument()->LoadFont(pElement); 309 if (pFont) 310 return pFont; 311 } 312 } 313 } 314 return nullptr; 315 } 316 317 int CPDF_FormControl::GetControlAlignment() { 318 if (!m_pWidgetDict) 319 return 0; 320 if (m_pWidgetDict->KeyExist("Q")) 321 return m_pWidgetDict->GetIntegerFor("Q", 0); 322 323 CPDF_Object* pObj = FPDF_GetFieldAttr(m_pField->GetDict(), "Q"); 324 if (pObj) 325 return pObj->GetInteger(); 326 return m_pField->GetForm()->GetFormAlignment(); 327 } 328