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