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