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