Home | History | Annotate | Download | only in app
      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 "xfa/fxfa/app/xfa_ffnotify.h"
      8 
      9 #include "fxjs/cfxjse_value.h"
     10 #include "xfa/fxfa/app/cxfa_textlayout.h"
     11 #include "xfa/fxfa/app/xfa_ffbarcode.h"
     12 #include "xfa/fxfa/app/xfa_ffcheckbutton.h"
     13 #include "xfa/fxfa/app/xfa_ffchoicelist.h"
     14 #include "xfa/fxfa/app/xfa_ffdraw.h"
     15 #include "xfa/fxfa/app/xfa_ffexclgroup.h"
     16 #include "xfa/fxfa/app/xfa_fffield.h"
     17 #include "xfa/fxfa/app/xfa_ffimage.h"
     18 #include "xfa/fxfa/app/xfa_ffimageedit.h"
     19 #include "xfa/fxfa/app/xfa_ffpath.h"
     20 #include "xfa/fxfa/app/xfa_ffpushbutton.h"
     21 #include "xfa/fxfa/app/xfa_ffsignature.h"
     22 #include "xfa/fxfa/app/xfa_ffsubform.h"
     23 #include "xfa/fxfa/app/xfa_fftext.h"
     24 #include "xfa/fxfa/app/xfa_fftextedit.h"
     25 #include "xfa/fxfa/app/xfa_ffwidgetacc.h"
     26 #include "xfa/fxfa/app/xfa_fwladapter.h"
     27 #include "xfa/fxfa/xfa_ffapp.h"
     28 #include "xfa/fxfa/xfa_ffdoc.h"
     29 #include "xfa/fxfa/xfa_ffdocview.h"
     30 #include "xfa/fxfa/xfa_ffpageview.h"
     31 #include "xfa/fxfa/xfa_ffwidget.h"
     32 #include "xfa/fxfa/xfa_ffwidgethandler.h"
     33 
     34 static void XFA_FFDeleteWidgetAcc(void* pData) {
     35   delete static_cast<CXFA_WidgetAcc*>(pData);
     36 }
     37 
     38 static XFA_MAPDATABLOCKCALLBACKINFO gs_XFADeleteWidgetAcc = {
     39     XFA_FFDeleteWidgetAcc, nullptr};
     40 
     41 CXFA_FFNotify::CXFA_FFNotify(CXFA_FFDoc* pDoc) : m_pDoc(pDoc) {}
     42 CXFA_FFNotify::~CXFA_FFNotify() {}
     43 
     44 void CXFA_FFNotify::OnPageEvent(CXFA_ContainerLayoutItem* pSender,
     45                                 uint32_t dwEvent) {
     46   CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pSender->GetLayout());
     47   if (pDocView)
     48     pDocView->OnPageEvent(pSender, dwEvent);
     49 }
     50 
     51 void CXFA_FFNotify::OnWidgetListItemAdded(CXFA_WidgetData* pSender,
     52                                           const FX_WCHAR* pLabel,
     53                                           const FX_WCHAR* pValue,
     54                                           int32_t iIndex) {
     55   CXFA_WidgetAcc* pWidgetAcc = static_cast<CXFA_WidgetAcc*>(pSender);
     56   if (pWidgetAcc->GetUIType() != XFA_Element::ChoiceList)
     57     return;
     58 
     59   CXFA_FFWidget* pWidget = nullptr;
     60   while ((pWidget = pWidgetAcc->GetNextWidget(pWidget)) != nullptr) {
     61     if (pWidget->IsLoaded()) {
     62       if (pWidgetAcc->IsListBox()) {
     63         static_cast<CXFA_FFListBox*>(pWidget)->InsertItem(pLabel, iIndex);
     64       } else {
     65         static_cast<CXFA_FFComboBox*>(pWidget)->InsertItem(pLabel, iIndex);
     66       }
     67     }
     68   }
     69 }
     70 
     71 void CXFA_FFNotify::OnWidgetListItemRemoved(CXFA_WidgetData* pSender,
     72                                             int32_t iIndex) {
     73   CXFA_WidgetAcc* pWidgetAcc = static_cast<CXFA_WidgetAcc*>(pSender);
     74   if (pWidgetAcc->GetUIType() != XFA_Element::ChoiceList)
     75     return;
     76 
     77   CXFA_FFWidget* pWidget = nullptr;
     78   while ((pWidget = pWidgetAcc->GetNextWidget(pWidget)) != nullptr) {
     79     if (pWidget->IsLoaded()) {
     80       if (pWidgetAcc->IsListBox()) {
     81         static_cast<CXFA_FFListBox*>(pWidget)->DeleteItem(iIndex);
     82       } else {
     83         static_cast<CXFA_FFComboBox*>(pWidget)->DeleteItem(iIndex);
     84       }
     85     }
     86   }
     87 }
     88 
     89 CXFA_LayoutItem* CXFA_FFNotify::OnCreateLayoutItem(CXFA_Node* pNode) {
     90   CXFA_LayoutProcessor* pLayout = m_pDoc->GetXFADoc()->GetDocLayout();
     91   CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pLayout);
     92   XFA_Element eType = pNode->GetElementType();
     93   if (eType == XFA_Element::PageArea)
     94     return new CXFA_FFPageView(pDocView, pNode);
     95   if (eType == XFA_Element::ContentArea)
     96     return new CXFA_ContainerLayoutItem(pNode);
     97 
     98   CXFA_WidgetAcc* pAcc = static_cast<CXFA_WidgetAcc*>(pNode->GetWidgetData());
     99   if (!pAcc)
    100     return new CXFA_ContentLayoutItem(pNode);
    101 
    102   CXFA_FFWidget* pWidget;
    103   switch (pAcc->GetUIType()) {
    104     case XFA_Element::Barcode:
    105       pWidget = new CXFA_FFBarcode(pAcc);
    106       break;
    107     case XFA_Element::Button:
    108       pWidget = new CXFA_FFPushButton(pAcc);
    109       break;
    110     case XFA_Element::CheckButton:
    111       pWidget = new CXFA_FFCheckButton(pAcc);
    112       break;
    113     case XFA_Element::ChoiceList: {
    114       if (pAcc->IsListBox()) {
    115         pWidget = new CXFA_FFListBox(pAcc);
    116       } else {
    117         pWidget = new CXFA_FFComboBox(pAcc);
    118       }
    119     } break;
    120     case XFA_Element::DateTimeEdit:
    121       pWidget = new CXFA_FFDateTimeEdit(pAcc);
    122       break;
    123     case XFA_Element::ImageEdit:
    124       pWidget = new CXFA_FFImageEdit(pAcc);
    125       break;
    126     case XFA_Element::NumericEdit:
    127       pWidget = new CXFA_FFNumericEdit(pAcc);
    128       break;
    129     case XFA_Element::PasswordEdit:
    130       pWidget = new CXFA_FFPasswordEdit(pAcc);
    131       break;
    132     case XFA_Element::Signature:
    133       pWidget = new CXFA_FFSignature(pAcc);
    134       break;
    135     case XFA_Element::TextEdit:
    136       pWidget = new CXFA_FFTextEdit(pAcc);
    137       break;
    138     case XFA_Element::Arc:
    139       pWidget = new CXFA_FFArc(pAcc);
    140       break;
    141     case XFA_Element::Line:
    142       pWidget = new CXFA_FFLine(pAcc);
    143       break;
    144     case XFA_Element::Rectangle:
    145       pWidget = new CXFA_FFRectangle(pAcc);
    146       break;
    147     case XFA_Element::Text:
    148       pWidget = new CXFA_FFText(pAcc);
    149       break;
    150     case XFA_Element::Image:
    151       pWidget = new CXFA_FFImage(pAcc);
    152       break;
    153     case XFA_Element::Draw:
    154       pWidget = new CXFA_FFDraw(pAcc);
    155       break;
    156     case XFA_Element::Subform:
    157       pWidget = new CXFA_FFSubForm(pAcc);
    158       break;
    159     case XFA_Element::ExclGroup:
    160       pWidget = new CXFA_FFExclGroup(pAcc);
    161       break;
    162     case XFA_Element::DefaultUi:
    163     default:
    164       pWidget = nullptr;
    165       break;
    166   }
    167 
    168   if (pWidget)
    169     pWidget->SetDocView(pDocView);
    170   return pWidget;
    171 }
    172 
    173 void CXFA_FFNotify::StartFieldDrawLayout(CXFA_Node* pItem,
    174                                          FX_FLOAT& fCalcWidth,
    175                                          FX_FLOAT& fCalcHeight) {
    176   CXFA_WidgetAcc* pAcc = static_cast<CXFA_WidgetAcc*>(pItem->GetWidgetData());
    177   if (!pAcc)
    178     return;
    179 
    180   pAcc->StartWidgetLayout(fCalcWidth, fCalcHeight);
    181 }
    182 
    183 bool CXFA_FFNotify::FindSplitPos(CXFA_Node* pItem,
    184                                  int32_t iBlockIndex,
    185                                  FX_FLOAT& fCalcHeightPos) {
    186   CXFA_WidgetAcc* pAcc = static_cast<CXFA_WidgetAcc*>(pItem->GetWidgetData());
    187   return pAcc && pAcc->FindSplitPos(iBlockIndex, fCalcHeightPos);
    188 }
    189 
    190 bool CXFA_FFNotify::RunScript(CXFA_Node* pScript, CXFA_Node* pFormItem) {
    191   bool bRet = false;
    192   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    193   if (!pDocView) {
    194     return bRet;
    195   }
    196   CXFA_WidgetAcc* pWidgetAcc =
    197       static_cast<CXFA_WidgetAcc*>(pFormItem->GetWidgetData());
    198   if (!pWidgetAcc) {
    199     return bRet;
    200   }
    201   CXFA_EventParam EventParam;
    202   EventParam.m_eType = XFA_EVENT_Unknown;
    203   CFXJSE_Value* pRetValue = nullptr;
    204   int32_t iRet =
    205       pWidgetAcc->ExecuteScript(CXFA_Script(pScript), &EventParam, &pRetValue);
    206   if (iRet == XFA_EVENTERROR_Success && pRetValue) {
    207     bRet = pRetValue->ToBoolean();
    208     delete pRetValue;
    209   }
    210   return bRet;
    211 }
    212 int32_t CXFA_FFNotify::ExecEventByDeepFirst(CXFA_Node* pFormNode,
    213                                             XFA_EVENTTYPE eEventType,
    214                                             bool bIsFormReady,
    215                                             bool bRecursive,
    216                                             CXFA_WidgetAcc* pExclude) {
    217   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    218   if (!pDocView) {
    219     return XFA_EVENTERROR_NotExist;
    220   }
    221   return pDocView->ExecEventActivityByDeepFirst(
    222       pFormNode, eEventType, bIsFormReady, bRecursive,
    223       pExclude ? pExclude->GetNode() : nullptr);
    224 }
    225 void CXFA_FFNotify::AddCalcValidate(CXFA_Node* pNode) {
    226   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    227   if (!pDocView) {
    228     return;
    229   }
    230   CXFA_WidgetAcc* pWidgetAcc =
    231       static_cast<CXFA_WidgetAcc*>(pNode->GetWidgetData());
    232   if (!pWidgetAcc) {
    233     return;
    234   }
    235   pDocView->AddCalculateWidgetAcc(pWidgetAcc);
    236   pDocView->AddValidateWidget(pWidgetAcc);
    237 }
    238 CXFA_FFDoc* CXFA_FFNotify::GetHDOC() {
    239   return m_pDoc;
    240 }
    241 IXFA_DocEnvironment* CXFA_FFNotify::GetDocEnvironment() const {
    242   return m_pDoc->GetDocEnvironment();
    243 }
    244 IXFA_AppProvider* CXFA_FFNotify::GetAppProvider() {
    245   return m_pDoc->GetApp()->GetAppProvider();
    246 }
    247 CXFA_FFWidgetHandler* CXFA_FFNotify::GetWidgetHandler() {
    248   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    249   return pDocView ? pDocView->GetWidgetHandler() : nullptr;
    250 }
    251 CXFA_FFWidget* CXFA_FFNotify::GetHWidget(CXFA_LayoutItem* pLayoutItem) {
    252   return XFA_GetWidgetFromLayoutItem(pLayoutItem);
    253 }
    254 void CXFA_FFNotify::OpenDropDownList(CXFA_FFWidget* hWidget) {
    255   if (hWidget->GetDataAcc()->GetUIType() != XFA_Element::ChoiceList) {
    256     return;
    257   }
    258   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    259   pDocView->LockUpdate();
    260   static_cast<CXFA_FFComboBox*>(hWidget)->OpenDropDownList();
    261   pDocView->UnlockUpdate();
    262   pDocView->UpdateDocView();
    263 }
    264 CFX_WideString CXFA_FFNotify::GetCurrentDateTime() {
    265   CFX_Unitime dataTime;
    266   dataTime.Now();
    267   CFX_WideString wsDateTime;
    268   wsDateTime.Format(L"%d%02d%02dT%02d%02d%02d", dataTime.GetYear(),
    269                     dataTime.GetMonth(), dataTime.GetDay(), dataTime.GetHour(),
    270                     dataTime.GetMinute(), dataTime.GetSecond());
    271   return wsDateTime;
    272 }
    273 void CXFA_FFNotify::ResetData(CXFA_WidgetData* pWidgetData) {
    274   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    275   if (!pDocView) {
    276     return;
    277   }
    278   pDocView->ResetWidgetData(static_cast<CXFA_WidgetAcc*>(pWidgetData));
    279 }
    280 int32_t CXFA_FFNotify::GetLayoutStatus() {
    281   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    282   return pDocView ? pDocView->GetLayoutStatus() : 0;
    283 }
    284 void CXFA_FFNotify::RunNodeInitialize(CXFA_Node* pNode) {
    285   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    286   if (!pDocView) {
    287     return;
    288   }
    289   pDocView->AddNewFormNode(pNode);
    290 }
    291 void CXFA_FFNotify::RunSubformIndexChange(CXFA_Node* pSubformNode) {
    292   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    293   if (!pDocView) {
    294     return;
    295   }
    296   pDocView->AddIndexChangedSubform(pSubformNode);
    297 }
    298 CXFA_Node* CXFA_FFNotify::GetFocusWidgetNode() {
    299   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    300   if (!pDocView) {
    301     return nullptr;
    302   }
    303   CXFA_WidgetAcc* pAcc = pDocView->GetFocusWidgetAcc();
    304   return pAcc ? pAcc->GetNode() : nullptr;
    305 }
    306 void CXFA_FFNotify::SetFocusWidgetNode(CXFA_Node* pNode) {
    307   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    308   if (!pDocView) {
    309     return;
    310   }
    311   CXFA_WidgetAcc* pAcc =
    312       pNode ? static_cast<CXFA_WidgetAcc*>(pNode->GetWidgetData()) : nullptr;
    313   pDocView->SetFocusWidgetAcc(pAcc);
    314 }
    315 
    316 void CXFA_FFNotify::OnNodeReady(CXFA_Node* pNode) {
    317   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    318   if (!pDocView)
    319     return;
    320 
    321   XFA_Element eType = pNode->GetElementType();
    322   if (XFA_IsCreateWidget(eType)) {
    323     CXFA_WidgetAcc* pAcc = new CXFA_WidgetAcc(pDocView, pNode);
    324     pNode->SetObject(XFA_ATTRIBUTE_WidgetData, pAcc, &gs_XFADeleteWidgetAcc);
    325     return;
    326   }
    327   switch (eType) {
    328     case XFA_Element::BindItems:
    329       pDocView->m_BindItems.push_back(pNode);
    330       break;
    331     case XFA_Element::Validate: {
    332       pNode->SetFlag(XFA_NodeFlag_NeedsInitApp, false);
    333     } break;
    334     default:
    335       break;
    336   }
    337 }
    338 
    339 void CXFA_FFNotify::OnValueChanging(CXFA_Node* pSender, XFA_ATTRIBUTE eAttr) {
    340   if (eAttr != XFA_ATTRIBUTE_Presence)
    341     return;
    342 
    343   if (pSender->GetPacketID() & XFA_XDPPACKET_Datasets)
    344     return;
    345 
    346   if (!pSender->IsFormContainer())
    347     return;
    348 
    349   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    350   if (!pDocView)
    351     return;
    352 
    353   if (pDocView->GetLayoutStatus() < XFA_DOCVIEW_LAYOUTSTATUS_End)
    354     return;
    355 
    356   CXFA_WidgetAcc* pWidgetAcc =
    357       static_cast<CXFA_WidgetAcc*>(pSender->GetWidgetData());
    358   if (!pWidgetAcc)
    359     return;
    360 
    361   CXFA_FFWidget* pWidget = nullptr;
    362   while ((pWidget = pWidgetAcc->GetNextWidget(pWidget)) != nullptr) {
    363     if (pWidget->IsLoaded())
    364       pWidget->AddInvalidateRect();
    365   }
    366 }
    367 
    368 void CXFA_FFNotify::OnValueChanged(CXFA_Node* pSender,
    369                                    XFA_ATTRIBUTE eAttr,
    370                                    CXFA_Node* pParentNode,
    371                                    CXFA_Node* pWidgetNode) {
    372   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    373   if (!pDocView)
    374     return;
    375 
    376   if (!(pSender->GetPacketID() & XFA_XDPPACKET_Form)) {
    377     if (eAttr == XFA_ATTRIBUTE_Value)
    378       pDocView->AddCalculateNodeNotify(pSender);
    379     return;
    380   }
    381 
    382   XFA_Element eType = pParentNode->GetElementType();
    383   bool bIsContainerNode = pParentNode->IsContainerNode();
    384   CXFA_WidgetAcc* pWidgetAcc =
    385       static_cast<CXFA_WidgetAcc*>(pWidgetNode->GetWidgetData());
    386   if (!pWidgetAcc)
    387     return;
    388 
    389   bool bUpdateProperty = false;
    390   pDocView->SetChangeMark();
    391   switch (eType) {
    392     case XFA_Element::Caption: {
    393       CXFA_TextLayout* pCapOut = pWidgetAcc->GetCaptionTextLayout();
    394       if (!pCapOut)
    395         return;
    396 
    397       pCapOut->Unload();
    398     } break;
    399     case XFA_Element::Ui:
    400     case XFA_Element::Para:
    401       bUpdateProperty = true;
    402       break;
    403     default:
    404       break;
    405   }
    406   if (bIsContainerNode && eAttr == XFA_ATTRIBUTE_Access)
    407     bUpdateProperty = true;
    408 
    409   if (eAttr == XFA_ATTRIBUTE_Value) {
    410     pDocView->AddCalculateNodeNotify(pSender);
    411     if (eType == XFA_Element::Value || bIsContainerNode) {
    412       if (bIsContainerNode) {
    413         pWidgetAcc->UpdateUIDisplay();
    414         pDocView->AddCalculateWidgetAcc(pWidgetAcc);
    415         pDocView->AddValidateWidget(pWidgetAcc);
    416       } else if (pWidgetNode->GetNodeItem(XFA_NODEITEM_Parent)
    417                      ->GetElementType() == XFA_Element::ExclGroup) {
    418         pWidgetAcc->UpdateUIDisplay();
    419       }
    420       return;
    421     }
    422   }
    423   CXFA_FFWidget* pWidget = nullptr;
    424   while ((pWidget = pWidgetAcc->GetNextWidget(pWidget)) != nullptr) {
    425     if (!pWidget->IsLoaded())
    426       continue;
    427 
    428     if (bUpdateProperty)
    429       pWidget->UpdateWidgetProperty();
    430     pWidget->PerformLayout();
    431     pWidget->AddInvalidateRect();
    432   }
    433 }
    434 
    435 void CXFA_FFNotify::OnChildAdded(CXFA_Node* pSender) {
    436   if (!pSender->IsFormContainer()) {
    437     return;
    438   }
    439   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    440   if (!pDocView) {
    441     return;
    442   }
    443   bool bLayoutReady =
    444       !(pDocView->m_bInLayoutStatus) &&
    445       (pDocView->GetLayoutStatus() == XFA_DOCVIEW_LAYOUTSTATUS_End);
    446   if (bLayoutReady)
    447     m_pDoc->GetDocEnvironment()->SetChangeMark(m_pDoc);
    448 }
    449 
    450 void CXFA_FFNotify::OnChildRemoved() {
    451   CXFA_FFDocView* pDocView = m_pDoc->GetDocView();
    452   if (!pDocView)
    453     return;
    454 
    455   bool bLayoutReady =
    456       !(pDocView->m_bInLayoutStatus) &&
    457       (pDocView->GetLayoutStatus() == XFA_DOCVIEW_LAYOUTSTATUS_End);
    458   if (bLayoutReady)
    459     m_pDoc->GetDocEnvironment()->SetChangeMark(m_pDoc);
    460 }
    461 
    462 void CXFA_FFNotify::OnLayoutItemAdded(CXFA_LayoutProcessor* pLayout,
    463                                       CXFA_LayoutItem* pSender,
    464                                       int32_t iPageIdx,
    465                                       uint32_t dwStatus) {
    466   CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pLayout);
    467   if (!pDocView)
    468     return;
    469 
    470   CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pSender);
    471   if (!pWidget)
    472     return;
    473 
    474   CXFA_FFPageView* pNewPageView = pDocView->GetPageView(iPageIdx);
    475   uint32_t dwFilter = XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable |
    476                       XFA_WidgetStatus_Printable;
    477   pWidget->ModifyStatus(dwStatus, dwFilter);
    478   CXFA_FFPageView* pPrePageView = pWidget->GetPageView();
    479   if (pPrePageView != pNewPageView ||
    480       (dwStatus & (XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable)) ==
    481           (XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable)) {
    482     pWidget->SetPageView(pNewPageView);
    483     m_pDoc->GetDocEnvironment()->WidgetPostAdd(pWidget, pWidget->GetDataAcc());
    484   }
    485   if (pDocView->GetLayoutStatus() != XFA_DOCVIEW_LAYOUTSTATUS_End ||
    486       !(dwStatus & XFA_WidgetStatus_Visible)) {
    487     return;
    488   }
    489   if (pWidget->IsLoaded()) {
    490     if (pWidget->GetWidgetRect() != pWidget->RecacheWidgetRect())
    491       pWidget->PerformLayout();
    492   } else {
    493     pWidget->LoadWidget();
    494   }
    495   pWidget->AddInvalidateRect(nullptr);
    496 }
    497 
    498 void CXFA_FFNotify::OnLayoutItemRemoving(CXFA_LayoutProcessor* pLayout,
    499                                          CXFA_LayoutItem* pSender) {
    500   CXFA_FFDocView* pDocView = m_pDoc->GetDocView(pLayout);
    501   if (!pDocView)
    502     return;
    503 
    504   CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pSender);
    505   if (!pWidget)
    506     return;
    507 
    508   pDocView->DeleteLayoutItem(pWidget);
    509   m_pDoc->GetDocEnvironment()->WidgetPreRemove(pWidget, pWidget->GetDataAcc());
    510   pWidget->AddInvalidateRect(nullptr);
    511 }
    512