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