Home | History | Annotate | Download | only in formfiller
      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 "fpdfsdk/formfiller/cffl_interactiveformfiller.h"
      8 
      9 #include "core/fpdfapi/page/cpdf_page.h"
     10 #include "core/fpdfapi/parser/cpdf_document.h"
     11 #include "core/fxcrt/autorestorer.h"
     12 #include "core/fxge/cfx_graphstatedata.h"
     13 #include "core/fxge/cfx_pathdata.h"
     14 #include "core/fxge/cfx_renderdevice.h"
     15 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
     16 #include "fpdfsdk/cpdfsdk_interform.h"
     17 #include "fpdfsdk/cpdfsdk_pageview.h"
     18 #include "fpdfsdk/cpdfsdk_widget.h"
     19 #include "fpdfsdk/formfiller/cffl_checkbox.h"
     20 #include "fpdfsdk/formfiller/cffl_combobox.h"
     21 #include "fpdfsdk/formfiller/cffl_formfiller.h"
     22 #include "fpdfsdk/formfiller/cffl_listbox.h"
     23 #include "fpdfsdk/formfiller/cffl_pushbutton.h"
     24 #include "fpdfsdk/formfiller/cffl_radiobutton.h"
     25 #include "fpdfsdk/formfiller/cffl_textfield.h"
     26 #include "third_party/base/stl_util.h"
     27 
     28 CFFL_InteractiveFormFiller::CFFL_InteractiveFormFiller(
     29     CPDFSDK_FormFillEnvironment* pFormFillEnv)
     30     : m_pFormFillEnv(pFormFillEnv), m_bNotifying(false) {}
     31 
     32 CFFL_InteractiveFormFiller::~CFFL_InteractiveFormFiller() {}
     33 
     34 bool CFFL_InteractiveFormFiller::Annot_HitTest(CPDFSDK_PageView* pPageView,
     35                                                CPDFSDK_Annot* pAnnot,
     36                                                const CFX_PointF& point) {
     37   return pAnnot->GetRect().Contains(point);
     38 }
     39 
     40 FX_RECT CFFL_InteractiveFormFiller::GetViewBBox(CPDFSDK_PageView* pPageView,
     41                                                 CPDFSDK_Annot* pAnnot) {
     42   if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false))
     43     return pFormFiller->GetViewBBox(pPageView, pAnnot);
     44 
     45   ASSERT(pPageView);
     46 
     47   CPDF_Annot* pPDFAnnot = pAnnot->GetPDFAnnot();
     48   CFX_FloatRect rcWin = pPDFAnnot->GetRect();
     49   if (!rcWin.IsEmpty()) {
     50     rcWin.Inflate(1, 1);
     51     rcWin.Normalize();
     52   }
     53   return rcWin.GetOuterRect();
     54 }
     55 
     56 void CFFL_InteractiveFormFiller::OnDraw(CPDFSDK_PageView* pPageView,
     57                                         CPDFSDK_Annot* pAnnot,
     58                                         CFX_RenderDevice* pDevice,
     59                                         CFX_Matrix* pUser2Device) {
     60   ASSERT(pPageView);
     61   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot);
     62   if (!IsVisible(pWidget))
     63     return;
     64 
     65   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false);
     66   if (pFormFiller && pFormFiller->IsValid()) {
     67     pFormFiller->OnDraw(pPageView, pAnnot, pDevice, *pUser2Device);
     68     pAnnot->GetPDFPage();
     69 
     70     if (m_pFormFillEnv->GetFocusAnnot() != pAnnot)
     71       return;
     72 
     73     CFX_FloatRect rcFocus = pFormFiller->GetFocusBox(pPageView);
     74     if (rcFocus.IsEmpty())
     75       return;
     76 
     77     CFX_PathData path;
     78     path.AppendPoint(CFX_PointF(rcFocus.left, rcFocus.top), FXPT_TYPE::MoveTo,
     79                      false);
     80     path.AppendPoint(CFX_PointF(rcFocus.left, rcFocus.bottom),
     81                      FXPT_TYPE::LineTo, false);
     82     path.AppendPoint(CFX_PointF(rcFocus.right, rcFocus.bottom),
     83                      FXPT_TYPE::LineTo, false);
     84     path.AppendPoint(CFX_PointF(rcFocus.right, rcFocus.top), FXPT_TYPE::LineTo,
     85                      false);
     86     path.AppendPoint(CFX_PointF(rcFocus.left, rcFocus.top), FXPT_TYPE::LineTo,
     87                      false);
     88 
     89     CFX_GraphStateData gsd;
     90     gsd.SetDashCount(1);
     91     gsd.m_DashArray[0] = 1.0f;
     92     gsd.m_DashPhase = 0;
     93     gsd.m_LineWidth = 1.0f;
     94     pDevice->DrawPath(&path, pUser2Device, &gsd, 0, ArgbEncode(255, 0, 0, 0),
     95                       FXFILL_ALTERNATE);
     96     return;
     97   }
     98 
     99   pFormFiller = GetFormFiller(pAnnot, false);
    100   if (pFormFiller) {
    101     pFormFiller->OnDrawDeactive(pPageView, pAnnot, pDevice, *pUser2Device);
    102   } else {
    103     pWidget->DrawAppearance(pDevice, *pUser2Device, CPDF_Annot::Normal,
    104                             nullptr);
    105   }
    106 
    107   if (!IsReadOnly(pWidget) && IsFillingAllowed(pWidget))
    108     pWidget->DrawShadow(pDevice, pPageView);
    109 }
    110 
    111 void CFFL_InteractiveFormFiller::OnDelete(CPDFSDK_Annot* pAnnot) {
    112   UnRegisterFormFiller(pAnnot);
    113 }
    114 
    115 void CFFL_InteractiveFormFiller::OnMouseEnter(
    116     CPDFSDK_PageView* pPageView,
    117     CPDFSDK_Annot::ObservedPtr* pAnnot,
    118     uint32_t nFlag) {
    119   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    120   if (!m_bNotifying) {
    121     CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    122     if (pWidget->GetAAction(CPDF_AAction::CursorEnter).GetDict()) {
    123       m_bNotifying = true;
    124 
    125       uint32_t nValueAge = pWidget->GetValueAge();
    126       pWidget->ClearAppModified();
    127       ASSERT(pPageView);
    128 
    129       PDFSDK_FieldAction fa;
    130       fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
    131       fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
    132       pWidget->OnAAction(CPDF_AAction::CursorEnter, fa, pPageView);
    133       m_bNotifying = false;
    134       if (!(*pAnnot))
    135         return;
    136 
    137       if (pWidget->IsAppModified()) {
    138         if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false)) {
    139           pFormFiller->ResetPDFWindow(pPageView,
    140                                       pWidget->GetValueAge() == nValueAge);
    141         }
    142       }
    143     }
    144   }
    145   if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), true))
    146     pFormFiller->OnMouseEnter(pPageView, pAnnot->Get());
    147 }
    148 
    149 void CFFL_InteractiveFormFiller::OnMouseExit(CPDFSDK_PageView* pPageView,
    150                                              CPDFSDK_Annot::ObservedPtr* pAnnot,
    151                                              uint32_t nFlag) {
    152   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    153   if (!m_bNotifying) {
    154     CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    155     if (pWidget->GetAAction(CPDF_AAction::CursorExit).GetDict()) {
    156       m_bNotifying = true;
    157 
    158       uint32_t nValueAge = pWidget->GetValueAge();
    159       pWidget->ClearAppModified();
    160       ASSERT(pPageView);
    161 
    162       PDFSDK_FieldAction fa;
    163       fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
    164       fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
    165       pWidget->OnAAction(CPDF_AAction::CursorExit, fa, pPageView);
    166       m_bNotifying = false;
    167       if (!(*pAnnot))
    168         return;
    169 
    170       if (pWidget->IsAppModified()) {
    171         if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false)) {
    172           pFormFiller->ResetPDFWindow(pPageView,
    173                                       nValueAge == pWidget->GetValueAge());
    174         }
    175       }
    176     }
    177   }
    178   if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false))
    179     pFormFiller->OnMouseExit(pPageView, pAnnot->Get());
    180 }
    181 
    182 bool CFFL_InteractiveFormFiller::OnLButtonDown(
    183     CPDFSDK_PageView* pPageView,
    184     CPDFSDK_Annot::ObservedPtr* pAnnot,
    185     uint32_t nFlags,
    186     const CFX_PointF& point) {
    187   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    188   if (!m_bNotifying) {
    189     CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    190     if (Annot_HitTest(pPageView, pAnnot->Get(), point) &&
    191         pWidget->GetAAction(CPDF_AAction::ButtonDown).GetDict()) {
    192       m_bNotifying = true;
    193 
    194       uint32_t nValueAge = pWidget->GetValueAge();
    195       pWidget->ClearAppModified();
    196       ASSERT(pPageView);
    197 
    198       PDFSDK_FieldAction fa;
    199       fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlags);
    200       fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlags);
    201       pWidget->OnAAction(CPDF_AAction::ButtonDown, fa, pPageView);
    202       m_bNotifying = false;
    203       if (!(*pAnnot))
    204         return true;
    205 
    206       if (!IsValidAnnot(pPageView, pAnnot->Get()))
    207         return true;
    208 
    209       if (pWidget->IsAppModified()) {
    210         if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false)) {
    211           pFormFiller->ResetPDFWindow(pPageView,
    212                                       nValueAge == pWidget->GetValueAge());
    213         }
    214       }
    215     }
    216   }
    217   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false);
    218   return pFormFiller &&
    219          pFormFiller->OnLButtonDown(pPageView, pAnnot->Get(), nFlags, point);
    220 }
    221 
    222 bool CFFL_InteractiveFormFiller::OnLButtonUp(CPDFSDK_PageView* pPageView,
    223                                              CPDFSDK_Annot::ObservedPtr* pAnnot,
    224                                              uint32_t nFlags,
    225                                              const CFX_PointF& point) {
    226   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    227   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    228 
    229   bool bSetFocus;
    230   switch (pWidget->GetFieldType()) {
    231     case FormFieldType::kPushButton:
    232     case FormFieldType::kCheckBox:
    233     case FormFieldType::kRadioButton: {
    234       FX_RECT bbox = GetViewBBox(pPageView, pAnnot->Get());
    235       bSetFocus =
    236           bbox.Contains(static_cast<int>(point.x), static_cast<int>(point.y));
    237       break;
    238     }
    239     default:
    240       bSetFocus = true;
    241       break;
    242   }
    243   if (bSetFocus)
    244     m_pFormFillEnv->SetFocusAnnot(pAnnot);
    245 
    246   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false);
    247   bool bRet = pFormFiller &&
    248               pFormFiller->OnLButtonUp(pPageView, pAnnot->Get(), nFlags, point);
    249   if (m_pFormFillEnv->GetFocusAnnot() != pAnnot->Get())
    250     return bRet;
    251   if (OnButtonUp(pAnnot, pPageView, nFlags) || !pAnnot)
    252     return true;
    253 #ifdef PDF_ENABLE_XFA
    254   if (OnClick(pAnnot, pPageView, nFlags) || !pAnnot)
    255     return true;
    256 #endif  // PDF_ENABLE_XFA
    257   return bRet;
    258 }
    259 
    260 bool CFFL_InteractiveFormFiller::OnButtonUp(CPDFSDK_Annot::ObservedPtr* pAnnot,
    261                                             CPDFSDK_PageView* pPageView,
    262                                             uint32_t nFlag) {
    263   if (m_bNotifying)
    264     return false;
    265 
    266   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    267   if (!pWidget->GetAAction(CPDF_AAction::ButtonUp).GetDict())
    268     return false;
    269 
    270   m_bNotifying = true;
    271 
    272   uint32_t nAge = pWidget->GetAppearanceAge();
    273   uint32_t nValueAge = pWidget->GetValueAge();
    274   ASSERT(pPageView);
    275 
    276   PDFSDK_FieldAction fa;
    277   fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
    278   fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
    279   pWidget->OnAAction(CPDF_AAction::ButtonUp, fa, pPageView);
    280   m_bNotifying = false;
    281   if (!(*pAnnot) || !IsValidAnnot(pPageView, pWidget))
    282     return true;
    283   if (nAge == pWidget->GetAppearanceAge())
    284     return false;
    285 
    286   CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false);
    287   if (pFormFiller)
    288     pFormFiller->ResetPDFWindow(pPageView, nValueAge == pWidget->GetValueAge());
    289   return true;
    290 }
    291 
    292 bool CFFL_InteractiveFormFiller::OnLButtonDblClk(
    293     CPDFSDK_PageView* pPageView,
    294     CPDFSDK_Annot::ObservedPtr* pAnnot,
    295     uint32_t nFlags,
    296     const CFX_PointF& point) {
    297   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    298   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false);
    299   return pFormFiller &&
    300          pFormFiller->OnLButtonDblClk(pPageView, pAnnot->Get(), nFlags, point);
    301 }
    302 
    303 bool CFFL_InteractiveFormFiller::OnMouseMove(CPDFSDK_PageView* pPageView,
    304                                              CPDFSDK_Annot::ObservedPtr* pAnnot,
    305                                              uint32_t nFlags,
    306                                              const CFX_PointF& point) {
    307   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    308   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), true);
    309   return pFormFiller &&
    310          pFormFiller->OnMouseMove(pPageView, pAnnot->Get(), nFlags, point);
    311 }
    312 
    313 bool CFFL_InteractiveFormFiller::OnMouseWheel(
    314     CPDFSDK_PageView* pPageView,
    315     CPDFSDK_Annot::ObservedPtr* pAnnot,
    316     uint32_t nFlags,
    317     short zDelta,
    318     const CFX_PointF& point) {
    319   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    320   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false);
    321   return pFormFiller &&
    322          pFormFiller->OnMouseWheel(pPageView, pAnnot->Get(), nFlags, zDelta,
    323                                    point);
    324 }
    325 
    326 bool CFFL_InteractiveFormFiller::OnRButtonDown(
    327     CPDFSDK_PageView* pPageView,
    328     CPDFSDK_Annot::ObservedPtr* pAnnot,
    329     uint32_t nFlags,
    330     const CFX_PointF& point) {
    331   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    332   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false);
    333   return pFormFiller &&
    334          pFormFiller->OnRButtonDown(pPageView, pAnnot->Get(), nFlags, point);
    335 }
    336 
    337 bool CFFL_InteractiveFormFiller::OnRButtonUp(CPDFSDK_PageView* pPageView,
    338                                              CPDFSDK_Annot::ObservedPtr* pAnnot,
    339                                              uint32_t nFlags,
    340                                              const CFX_PointF& point) {
    341   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    342   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false);
    343   return pFormFiller &&
    344          pFormFiller->OnRButtonUp(pPageView, pAnnot->Get(), nFlags, point);
    345 }
    346 
    347 bool CFFL_InteractiveFormFiller::OnKeyDown(CPDFSDK_Annot* pAnnot,
    348                                            uint32_t nKeyCode,
    349                                            uint32_t nFlags) {
    350   ASSERT(pAnnot->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    351 
    352   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false);
    353   return pFormFiller && pFormFiller->OnKeyDown(pAnnot, nKeyCode, nFlags);
    354 }
    355 
    356 bool CFFL_InteractiveFormFiller::OnChar(CPDFSDK_Annot* pAnnot,
    357                                         uint32_t nChar,
    358                                         uint32_t nFlags) {
    359   ASSERT(pAnnot->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    360   if (nChar == FWL_VKEY_Tab)
    361     return true;
    362 
    363   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false);
    364   return pFormFiller && pFormFiller->OnChar(pAnnot, nChar, nFlags);
    365 }
    366 
    367 bool CFFL_InteractiveFormFiller::OnSetFocus(CPDFSDK_Annot::ObservedPtr* pAnnot,
    368                                             uint32_t nFlag) {
    369   if (!(*pAnnot))
    370     return false;
    371 
    372   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    373   if (!m_bNotifying) {
    374     CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    375     if (pWidget->GetAAction(CPDF_AAction::GetFocus).GetDict()) {
    376       m_bNotifying = true;
    377 
    378       uint32_t nValueAge = pWidget->GetValueAge();
    379       pWidget->ClearAppModified();
    380 
    381       CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, true);
    382       if (!pFormFiller)
    383         return false;
    384 
    385       CPDFSDK_PageView* pPageView = (*pAnnot)->GetPageView();
    386       ASSERT(pPageView);
    387 
    388       PDFSDK_FieldAction fa;
    389       fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
    390       fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
    391       pFormFiller->GetActionData(pPageView, CPDF_AAction::GetFocus, fa);
    392       pWidget->OnAAction(CPDF_AAction::GetFocus, fa, pPageView);
    393       m_bNotifying = false;
    394       if (!(*pAnnot))
    395         return false;
    396 
    397       if (pWidget->IsAppModified()) {
    398         if (CFFL_FormFiller* pFiller = GetFormFiller(pWidget, false)) {
    399           pFiller->ResetPDFWindow(pPageView,
    400                                   nValueAge == pWidget->GetValueAge());
    401         }
    402       }
    403     }
    404   }
    405 
    406   if (CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), true))
    407     pFormFiller->SetFocusForAnnot(pAnnot->Get(), nFlag);
    408 
    409   return true;
    410 }
    411 
    412 bool CFFL_InteractiveFormFiller::OnKillFocus(CPDFSDK_Annot::ObservedPtr* pAnnot,
    413                                              uint32_t nFlag) {
    414   if (!(*pAnnot))
    415     return false;
    416 
    417   ASSERT((*pAnnot)->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    418   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot->Get(), false);
    419   if (!pFormFiller)
    420     return true;
    421 
    422   pFormFiller->KillFocusForAnnot(pAnnot->Get(), nFlag);
    423   if (!(*pAnnot))
    424     return false;
    425 
    426   if (m_bNotifying)
    427     return true;
    428 
    429   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    430   if (!pWidget->GetAAction(CPDF_AAction::LoseFocus).GetDict())
    431     return true;
    432 
    433   m_bNotifying = true;
    434   pWidget->ClearAppModified();
    435 
    436   CPDFSDK_PageView* pPageView = pWidget->GetPageView();
    437   ASSERT(pPageView);
    438 
    439   PDFSDK_FieldAction fa;
    440   fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
    441   fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
    442   pFormFiller->GetActionData(pPageView, CPDF_AAction::LoseFocus, fa);
    443   pWidget->OnAAction(CPDF_AAction::LoseFocus, fa, pPageView);
    444   m_bNotifying = false;
    445   return !!(*pAnnot);
    446 }
    447 
    448 bool CFFL_InteractiveFormFiller::IsVisible(CPDFSDK_Widget* pWidget) {
    449   return pWidget->IsVisible();
    450 }
    451 
    452 bool CFFL_InteractiveFormFiller::IsReadOnly(CPDFSDK_Widget* pWidget) {
    453   int nFieldFlags = pWidget->GetFieldFlags();
    454   return (nFieldFlags & FIELDFLAG_READONLY) == FIELDFLAG_READONLY;
    455 }
    456 
    457 bool CFFL_InteractiveFormFiller::IsFillingAllowed(CPDFSDK_Widget* pWidget) {
    458   if (pWidget->GetFieldType() == FormFieldType::kPushButton)
    459     return false;
    460 
    461   CPDF_Page* pPage = pWidget->GetPDFPage();
    462   uint32_t dwPermissions = pPage->m_pDocument->GetUserPermissions();
    463   return (dwPermissions & FPDFPERM_FILL_FORM) ||
    464          (dwPermissions & FPDFPERM_ANNOT_FORM) ||
    465          (dwPermissions & FPDFPERM_MODIFY);
    466 }
    467 
    468 CFFL_FormFiller* CFFL_InteractiveFormFiller::GetFormFiller(
    469     CPDFSDK_Annot* pAnnot,
    470     bool bRegister) {
    471   auto it = m_Maps.find(pAnnot);
    472   if (it != m_Maps.end())
    473     return it->second.get();
    474 
    475   if (!bRegister)
    476     return nullptr;
    477 
    478   // TODO(thestig): How do we know |pAnnot| is a CPDFSDK_Widget?
    479   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot);
    480   FormFieldType fieldType = pWidget->GetFieldType();
    481   CFFL_FormFiller* pFormFiller;
    482   switch (fieldType) {
    483     case FormFieldType::kPushButton:
    484       pFormFiller = new CFFL_PushButton(m_pFormFillEnv.Get(), pWidget);
    485       break;
    486     case FormFieldType::kCheckBox:
    487       pFormFiller = new CFFL_CheckBox(m_pFormFillEnv.Get(), pWidget);
    488       break;
    489     case FormFieldType::kRadioButton:
    490       pFormFiller = new CFFL_RadioButton(m_pFormFillEnv.Get(), pWidget);
    491       break;
    492     case FormFieldType::kTextField:
    493       pFormFiller = new CFFL_TextField(m_pFormFillEnv.Get(), pWidget);
    494       break;
    495     case FormFieldType::kListBox:
    496       pFormFiller = new CFFL_ListBox(m_pFormFillEnv.Get(), pWidget);
    497       break;
    498     case FormFieldType::kComboBox:
    499       pFormFiller = new CFFL_ComboBox(m_pFormFillEnv.Get(), pWidget);
    500       break;
    501     case FormFieldType::kUnknown:
    502     default:
    503       pFormFiller = nullptr;
    504       break;
    505   }
    506 
    507   if (!pFormFiller)
    508     return nullptr;
    509 
    510   m_Maps[pAnnot].reset(pFormFiller);
    511   return pFormFiller;
    512 }
    513 
    514 WideString CFFL_InteractiveFormFiller::GetSelectedText(CPDFSDK_Annot* pAnnot) {
    515   ASSERT(pAnnot->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    516   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false);
    517   return pFormFiller ? pFormFiller->GetSelectedText(pAnnot) : WideString();
    518 }
    519 
    520 void CFFL_InteractiveFormFiller::ReplaceSelection(CPDFSDK_Annot* pAnnot,
    521                                                   const WideString& text) {
    522   ASSERT(pAnnot->GetPDFAnnot()->GetSubtype() == CPDF_Annot::Subtype::WIDGET);
    523   CFFL_FormFiller* pFormFiller = GetFormFiller(pAnnot, false);
    524   if (!pFormFiller)
    525     return;
    526 
    527   pFormFiller->ReplaceSelection(pAnnot, text);
    528 }
    529 
    530 void CFFL_InteractiveFormFiller::UnRegisterFormFiller(CPDFSDK_Annot* pAnnot) {
    531   auto it = m_Maps.find(pAnnot);
    532   if (it == m_Maps.end())
    533     return;
    534 
    535   m_Maps.erase(it);
    536 }
    537 
    538 void CFFL_InteractiveFormFiller::QueryWherePopup(
    539     CPWL_Wnd::PrivateData* pAttached,
    540     float fPopupMin,
    541     float fPopupMax,
    542     bool* bBottom,
    543     float* fPopupRet) {
    544   auto* pData = static_cast<CFFL_PrivateData*>(pAttached);
    545   CPDFSDK_Widget* pWidget = pData->pWidget;
    546   CPDF_Page* pPage = pWidget->GetPDFPage();
    547 
    548   CFX_FloatRect rcPageView(0, pPage->GetPageHeight(), pPage->GetPageWidth(), 0);
    549   rcPageView.Normalize();
    550 
    551   CFX_FloatRect rcAnnot = pWidget->GetRect();
    552   float fTop = 0.0f;
    553   float fBottom = 0.0f;
    554   switch (pWidget->GetRotate() / 90) {
    555     default:
    556     case 0:
    557       fTop = rcPageView.top - rcAnnot.top;
    558       fBottom = rcAnnot.bottom - rcPageView.bottom;
    559       break;
    560     case 1:
    561       fTop = rcAnnot.left - rcPageView.left;
    562       fBottom = rcPageView.right - rcAnnot.right;
    563       break;
    564     case 2:
    565       fTop = rcAnnot.bottom - rcPageView.bottom;
    566       fBottom = rcPageView.top - rcAnnot.top;
    567       break;
    568     case 3:
    569       fTop = rcPageView.right - rcAnnot.right;
    570       fBottom = rcAnnot.left - rcPageView.left;
    571       break;
    572   }
    573 
    574   constexpr float kMaxListBoxHeight = 140;
    575   const float fMaxListBoxHeight =
    576       pdfium::clamp(kMaxListBoxHeight, fPopupMin, fPopupMax);
    577 
    578   if (fBottom > fMaxListBoxHeight) {
    579     *fPopupRet = fMaxListBoxHeight;
    580     *bBottom = true;
    581     return;
    582   }
    583 
    584   if (fTop > fMaxListBoxHeight) {
    585     *fPopupRet = fMaxListBoxHeight;
    586     *bBottom = false;
    587     return;
    588   }
    589 
    590   if (fTop > fBottom) {
    591     *fPopupRet = fTop;
    592     *bBottom = false;
    593   } else {
    594     *fPopupRet = fBottom;
    595     *bBottom = true;
    596   }
    597 }
    598 
    599 bool CFFL_InteractiveFormFiller::OnKeyStrokeCommit(
    600     CPDFSDK_Annot::ObservedPtr* pAnnot,
    601     CPDFSDK_PageView* pPageView,
    602     uint32_t nFlag) {
    603   if (m_bNotifying)
    604     return true;
    605 
    606   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    607   if (!pWidget->GetAAction(CPDF_AAction::KeyStroke).GetDict())
    608     return true;
    609 
    610   ASSERT(pPageView);
    611   m_bNotifying = true;
    612   pWidget->ClearAppModified();
    613 
    614   PDFSDK_FieldAction fa;
    615   fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
    616   fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
    617   fa.bWillCommit = true;
    618   fa.bKeyDown = true;
    619   fa.bRC = true;
    620 
    621   CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false);
    622   pFormFiller->GetActionData(pPageView, CPDF_AAction::KeyStroke, fa);
    623   pFormFiller->SaveState(pPageView);
    624   pWidget->OnAAction(CPDF_AAction::KeyStroke, fa, pPageView);
    625   if (!(*pAnnot))
    626     return true;
    627 
    628   m_bNotifying = false;
    629   return fa.bRC;
    630 }
    631 
    632 bool CFFL_InteractiveFormFiller::OnValidate(CPDFSDK_Annot::ObservedPtr* pAnnot,
    633                                             CPDFSDK_PageView* pPageView,
    634                                             uint32_t nFlag) {
    635   if (m_bNotifying)
    636     return true;
    637 
    638   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    639   if (!pWidget->GetAAction(CPDF_AAction::Validate).GetDict())
    640     return true;
    641 
    642   ASSERT(pPageView);
    643   m_bNotifying = true;
    644   pWidget->ClearAppModified();
    645 
    646   PDFSDK_FieldAction fa;
    647   fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
    648   fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
    649   fa.bKeyDown = true;
    650   fa.bRC = true;
    651 
    652   CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false);
    653   pFormFiller->GetActionData(pPageView, CPDF_AAction::Validate, fa);
    654   pFormFiller->SaveState(pPageView);
    655   pWidget->OnAAction(CPDF_AAction::Validate, fa, pPageView);
    656   if (!(*pAnnot))
    657     return true;
    658 
    659   m_bNotifying = false;
    660   return fa.bRC;
    661 }
    662 
    663 void CFFL_InteractiveFormFiller::OnCalculate(CPDFSDK_Annot::ObservedPtr* pAnnot,
    664                                              CPDFSDK_PageView* pPageView,
    665                                              uint32_t nFlag) {
    666   if (m_bNotifying)
    667     return;
    668 
    669   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    670   if (pWidget) {
    671     CPDFSDK_InterForm* pInterForm = pPageView->GetFormFillEnv()->GetInterForm();
    672     pInterForm->OnCalculate(pWidget->GetFormField());
    673   }
    674   m_bNotifying = false;
    675 }
    676 
    677 void CFFL_InteractiveFormFiller::OnFormat(CPDFSDK_Annot::ObservedPtr* pAnnot,
    678                                           CPDFSDK_PageView* pPageView,
    679                                           uint32_t nFlag) {
    680   if (m_bNotifying)
    681     return;
    682 
    683   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    684   ASSERT(pWidget);
    685   CPDFSDK_InterForm* pInterForm = pPageView->GetFormFillEnv()->GetInterForm();
    686 
    687   bool bFormatted = false;
    688   WideString sValue = pInterForm->OnFormat(pWidget->GetFormField(), bFormatted);
    689   if (!(*pAnnot))
    690     return;
    691 
    692   if (bFormatted) {
    693     pInterForm->ResetFieldAppearance(pWidget->GetFormField(), &sValue, true);
    694     pInterForm->UpdateField(pWidget->GetFormField());
    695   }
    696 
    697   m_bNotifying = false;
    698 }
    699 
    700 #ifdef PDF_ENABLE_XFA
    701 bool CFFL_InteractiveFormFiller::OnClick(CPDFSDK_Annot::ObservedPtr* pAnnot,
    702                                          CPDFSDK_PageView* pPageView,
    703                                          uint32_t nFlag) {
    704   if (m_bNotifying)
    705     return false;
    706 
    707   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    708   if (!pWidget->HasXFAAAction(PDFSDK_XFA_Click))
    709     return false;
    710 
    711   m_bNotifying = true;
    712   uint32_t nAge = pWidget->GetAppearanceAge();
    713   uint32_t nValueAge = pWidget->GetValueAge();
    714 
    715   PDFSDK_FieldAction fa;
    716   fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
    717   fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
    718 
    719   pWidget->OnXFAAAction(PDFSDK_XFA_Click, fa, pPageView);
    720   m_bNotifying = false;
    721   if (!(*pAnnot) || !IsValidAnnot(pPageView, pWidget))
    722     return true;
    723   if (nAge == pWidget->GetAppearanceAge())
    724     return false;
    725 
    726   if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false))
    727     pFormFiller->ResetPDFWindow(pPageView, nValueAge == pWidget->GetValueAge());
    728   return false;
    729 }
    730 
    731 bool CFFL_InteractiveFormFiller::OnFull(CPDFSDK_Annot::ObservedPtr* pAnnot,
    732                                         CPDFSDK_PageView* pPageView,
    733                                         uint32_t nFlag) {
    734   if (m_bNotifying)
    735     return false;
    736 
    737   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    738   if (!pWidget->HasXFAAAction(PDFSDK_XFA_Full))
    739     return false;
    740 
    741   m_bNotifying = true;
    742   uint32_t nAge = pWidget->GetAppearanceAge();
    743   uint32_t nValueAge = pWidget->GetValueAge();
    744 
    745   PDFSDK_FieldAction fa;
    746   fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
    747   fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
    748 
    749   pWidget->OnXFAAAction(PDFSDK_XFA_Full, fa, pPageView);
    750   m_bNotifying = false;
    751   if (!(*pAnnot) || !IsValidAnnot(pPageView, pWidget))
    752     return true;
    753   if (nAge == pWidget->GetAppearanceAge())
    754     return false;
    755 
    756   if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false))
    757     pFormFiller->ResetPDFWindow(pPageView, nValueAge == pWidget->GetValueAge());
    758 
    759   return true;
    760 }
    761 
    762 bool CFFL_InteractiveFormFiller::OnPopupPreOpen(
    763     CPWL_Wnd::PrivateData* pAttached,
    764     uint32_t nFlag) {
    765   auto* pData = static_cast<CFFL_PrivateData*>(pAttached);
    766   ASSERT(pData);
    767   ASSERT(pData->pWidget);
    768 
    769   CPDFSDK_Annot::ObservedPtr pObserved(pData->pWidget);
    770   return OnPreOpen(&pObserved, pData->pPageView, nFlag) || !pObserved;
    771 }
    772 
    773 bool CFFL_InteractiveFormFiller::OnPopupPostOpen(
    774     CPWL_Wnd::PrivateData* pAttached,
    775     uint32_t nFlag) {
    776   auto* pData = static_cast<CFFL_PrivateData*>(pAttached);
    777   ASSERT(pData);
    778   ASSERT(pData->pWidget);
    779 
    780   CPDFSDK_Annot::ObservedPtr pObserved(pData->pWidget);
    781   return OnPostOpen(&pObserved, pData->pPageView, nFlag) || !pObserved;
    782 }
    783 
    784 bool CFFL_InteractiveFormFiller::OnPreOpen(CPDFSDK_Annot::ObservedPtr* pAnnot,
    785                                            CPDFSDK_PageView* pPageView,
    786                                            uint32_t nFlag) {
    787   if (m_bNotifying)
    788     return false;
    789 
    790   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    791   if (!pWidget->HasXFAAAction(PDFSDK_XFA_PreOpen))
    792     return false;
    793 
    794   m_bNotifying = true;
    795   uint32_t nAge = pWidget->GetAppearanceAge();
    796   uint32_t nValueAge = pWidget->GetValueAge();
    797 
    798   PDFSDK_FieldAction fa;
    799   fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
    800   fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
    801 
    802   pWidget->OnXFAAAction(PDFSDK_XFA_PreOpen, fa, pPageView);
    803   m_bNotifying = false;
    804   if (!(*pAnnot) || !IsValidAnnot(pPageView, pWidget))
    805     return true;
    806   if (nAge == pWidget->GetAppearanceAge())
    807     return false;
    808 
    809   if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false))
    810     pFormFiller->ResetPDFWindow(pPageView, nValueAge == pWidget->GetValueAge());
    811 
    812   return true;
    813 }
    814 
    815 bool CFFL_InteractiveFormFiller::OnPostOpen(CPDFSDK_Annot::ObservedPtr* pAnnot,
    816                                             CPDFSDK_PageView* pPageView,
    817                                             uint32_t nFlag) {
    818   if (m_bNotifying)
    819     return false;
    820 
    821   CPDFSDK_Widget* pWidget = static_cast<CPDFSDK_Widget*>(pAnnot->Get());
    822   if (!pWidget->HasXFAAAction(PDFSDK_XFA_PostOpen))
    823     return false;
    824 
    825   m_bNotifying = true;
    826   uint32_t nAge = pWidget->GetAppearanceAge();
    827   uint32_t nValueAge = pWidget->GetValueAge();
    828 
    829   PDFSDK_FieldAction fa;
    830   fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
    831   fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
    832 
    833   pWidget->OnXFAAAction(PDFSDK_XFA_PostOpen, fa, pPageView);
    834   m_bNotifying = false;
    835   if (!(*pAnnot) || !IsValidAnnot(pPageView, pWidget))
    836     return true;
    837   if (nAge == pWidget->GetAppearanceAge())
    838     return false;
    839 
    840   if (CFFL_FormFiller* pFormFiller = GetFormFiller(pWidget, false))
    841     pFormFiller->ResetPDFWindow(pPageView, nValueAge == pWidget->GetValueAge());
    842 
    843   return true;
    844 }
    845 #endif  // PDF_ENABLE_XFA
    846 
    847 bool CFFL_InteractiveFormFiller::IsValidAnnot(CPDFSDK_PageView* pPageView,
    848                                               CPDFSDK_Annot* pAnnot) {
    849   return pPageView && pPageView->IsValidAnnot(pAnnot->GetPDFAnnot());
    850 }
    851 
    852 std::pair<bool, bool> CFFL_InteractiveFormFiller::OnBeforeKeyStroke(
    853     CPWL_Wnd::PrivateData* pAttached,
    854     WideString& strChange,
    855     const WideString& strChangeEx,
    856     int nSelStart,
    857     int nSelEnd,
    858     bool bKeyDown,
    859     uint32_t nFlag) {
    860   // Copy the private data since the window owning it may not survive.
    861   CFFL_PrivateData privateData = *static_cast<CFFL_PrivateData*>(pAttached);
    862   ASSERT(privateData.pWidget);
    863 
    864   CFFL_FormFiller* pFormFiller = GetFormFiller(privateData.pWidget, false);
    865 
    866 #ifdef PDF_ENABLE_XFA
    867   if (pFormFiller->IsFieldFull(privateData.pPageView)) {
    868     CPDFSDK_Annot::ObservedPtr pObserved(privateData.pWidget);
    869     if (OnFull(&pObserved, privateData.pPageView, nFlag) || !pObserved)
    870       return {true, true};
    871   }
    872 #endif  // PDF_ENABLE_XFA
    873 
    874   if (m_bNotifying ||
    875       !privateData.pWidget->GetAAction(CPDF_AAction::KeyStroke).GetDict()) {
    876     return {true, false};
    877   }
    878 
    879   AutoRestorer<bool> restorer(&m_bNotifying);
    880   m_bNotifying = true;
    881 
    882   uint32_t nAge = privateData.pWidget->GetAppearanceAge();
    883   uint32_t nValueAge = privateData.pWidget->GetValueAge();
    884   CPDFSDK_FormFillEnvironment* pFormFillEnv =
    885       privateData.pPageView->GetFormFillEnv();
    886 
    887   PDFSDK_FieldAction fa;
    888   fa.bModifier = CPDFSDK_FormFillEnvironment::IsCTRLKeyDown(nFlag);
    889   fa.bShift = CPDFSDK_FormFillEnvironment::IsSHIFTKeyDown(nFlag);
    890   fa.sChange = strChange;
    891   fa.sChangeEx = strChangeEx;
    892   fa.bKeyDown = bKeyDown;
    893   fa.bWillCommit = false;
    894   fa.bRC = true;
    895   fa.nSelStart = nSelStart;
    896   fa.nSelEnd = nSelEnd;
    897   pFormFiller->GetActionData(privateData.pPageView, CPDF_AAction::KeyStroke,
    898                              fa);
    899   pFormFiller->SaveState(privateData.pPageView);
    900 
    901   CPDFSDK_Annot::ObservedPtr pObserved(privateData.pWidget);
    902   bool action_status = privateData.pWidget->OnAAction(
    903       CPDF_AAction::KeyStroke, fa, privateData.pPageView);
    904 
    905   if (!pObserved || !IsValidAnnot(privateData.pPageView, privateData.pWidget))
    906     return {true, true};
    907 
    908   if (!action_status)
    909     return {true, false};
    910 
    911   bool bExit = false;
    912   if (nAge != privateData.pWidget->GetAppearanceAge()) {
    913     CPWL_Wnd* pWnd = pFormFiller->ResetPDFWindow(
    914         privateData.pPageView, nValueAge == privateData.pWidget->GetValueAge());
    915     if (!pWnd)
    916       return {true, true};
    917     privateData = *static_cast<CFFL_PrivateData*>(pWnd->GetAttachedData());
    918     bExit = true;
    919   }
    920   if (fa.bRC) {
    921     pFormFiller->SetActionData(privateData.pPageView, CPDF_AAction::KeyStroke,
    922                                fa);
    923   } else {
    924     pFormFiller->RestoreState(privateData.pPageView);
    925   }
    926   if (pFormFillEnv->GetFocusAnnot() == privateData.pWidget)
    927     return {false, bExit};
    928 
    929   pFormFiller->CommitData(privateData.pPageView, nFlag);
    930   return {false, true};
    931 }
    932