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 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 } 17 CFX_FloatRect CPDF_FormControl::GetRect() const { 18 return m_pWidgetDict->GetRect("Rect"); 19 } 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 } 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 } 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) { 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_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}; 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 190 CPDF_ApSettings CPDF_FormControl::GetMK() const { 191 return CPDF_ApSettings(m_pWidgetDict ? m_pWidgetDict->GetDict("MK") 192 : nullptr); 193 } 194 195 bool CPDF_FormControl::HasMKEntry(CFX_ByteString csEntry) const { 196 return GetMK().HasMKEntry(csEntry); 197 } 198 199 int CPDF_FormControl::GetRotation() { 200 return GetMK().GetRotation(); 201 } 202 203 FX_ARGB CPDF_FormControl::GetColor(int& iColorType, CFX_ByteString csEntry) { 204 return GetMK().GetColor(iColorType, csEntry); 205 } 206 207 FX_FLOAT CPDF_FormControl::GetOriginalColor(int index, CFX_ByteString csEntry) { 208 return GetMK().GetOriginalColor(index, csEntry); 209 } 210 211 void CPDF_FormControl::GetOriginalColor(int& iColorType, 212 FX_FLOAT fc[4], 213 CFX_ByteString csEntry) { 214 GetMK().GetOriginalColor(iColorType, fc, csEntry); 215 } 216 CFX_WideString CPDF_FormControl::GetCaption(CFX_ByteString csEntry) { 217 return GetMK().GetCaption(csEntry); 218 } 219 220 CPDF_Stream* CPDF_FormControl::GetIcon(CFX_ByteString csEntry) { 221 return GetMK().GetIcon(csEntry); 222 } 223 224 CPDF_IconFit CPDF_FormControl::GetIconFit() { 225 return GetMK().GetIconFit(); 226 } 227 228 int CPDF_FormControl::GetTextPosition() { 229 return GetMK().GetTextPosition(); 230 } 231 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 } 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 } 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 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 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 322 CPDF_ApSettings::CPDF_ApSettings(CPDF_Dictionary* pDict) : m_pDict(pDict) {} 323 324 bool CPDF_ApSettings::HasMKEntry(const CFX_ByteStringC& csEntry) const { 325 return m_pDict && m_pDict->KeyExist(csEntry); 326 } 327 328 int CPDF_ApSettings::GetRotation() const { 329 return m_pDict ? m_pDict->GetInteger("R") : 0; 330 } 331 332 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 368 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 378 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 410 CFX_WideString CPDF_ApSettings::GetCaption( 411 const CFX_ByteStringC& csEntry) const { 412 return m_pDict ? m_pDict->GetUnicodeText(csEntry) : CFX_WideString(); 413 } 414 415 CPDF_Stream* CPDF_ApSettings::GetIcon(const CFX_ByteStringC& csEntry) const { 416 return m_pDict ? m_pDict->GetStream(csEntry) : nullptr; 417 } 418 419 CPDF_IconFit CPDF_ApSettings::GetIconFit() const { 420 return m_pDict ? m_pDict->GetDict("IF") : nullptr; 421 } 422 423 int CPDF_ApSettings::GetTextPosition() const { 424 return m_pDict ? m_pDict->GetInteger("TP", TEXTPOS_CAPTION) : TEXTPOS_CAPTION; 425 } 426