Home | History | Annotate | Download | only in fpdfdoc
      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