Home | History | Annotate | Download | only in fpdfdoc
      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 FX_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->m_pForm) {}
     34 
     35 CFX_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 
     54 void 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 
     96 CFX_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 
    112 CFX_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 
    129 bool 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 
    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->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 
    149 void 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 
    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, 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 
    189 CPDF_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 
    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 CFX_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,
    215                                    const CFX_ByteString& csEntry) {
    216   return GetMK().GetColor(iColorType, csEntry);
    217 }
    218 
    219 FX_FLOAT CPDF_FormControl::GetOriginalColor(int index,
    220                                             const CFX_ByteString& csEntry) {
    221   return GetMK().GetOriginalColor(index, csEntry);
    222 }
    223 
    224 void CPDF_FormControl::GetOriginalColor(int& iColorType,
    225                                         FX_FLOAT fc[4],
    226                                         const CFX_ByteString& csEntry) {
    227   GetMK().GetOriginalColor(iColorType, fc, csEntry);
    228 }
    229 
    230 CFX_WideString CPDF_FormControl::GetCaption(const CFX_ByteString& csEntry) {
    231   return GetMK().GetCaption(csEntry);
    232 }
    233 
    234 CPDF_Stream* CPDF_FormControl::GetIcon(const CFX_ByteString& csEntry) {
    235   return GetMK().GetIcon(csEntry);
    236 }
    237 
    238 CPDF_IconFit CPDF_FormControl::GetIconFit() {
    239   return GetMK().GetIconFit();
    240 }
    241 
    242 int CPDF_FormControl::GetTextPosition() {
    243   return GetMK().GetTextPosition();
    244 }
    245 
    246 CPDF_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 
    260 CPDF_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 
    269 CPDF_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 
    282 CPDF_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 
    321 int 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