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 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