706 lines
22 KiB
C++
706 lines
22 KiB
C++
// Copyright 2014 PDFium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
|
|
|
|
#include "xfa/fxfa/cxfa_ffdocview.h"
|
|
|
|
#include <set>
|
|
#include <utility>
|
|
|
|
#include "core/fxcrt/fx_extension.h"
|
|
#include "fxjs/xfa/cfxjse_engine.h"
|
|
#include "fxjs/xfa/cjx_object.h"
|
|
#include "third_party/base/ptr_util.h"
|
|
#include "third_party/base/stl_util.h"
|
|
#include "xfa/fxfa/cxfa_ffapp.h"
|
|
#include "xfa/fxfa/cxfa_ffbarcode.h"
|
|
#include "xfa/fxfa/cxfa_ffcheckbutton.h"
|
|
#include "xfa/fxfa/cxfa_ffdoc.h"
|
|
#include "xfa/fxfa/cxfa_ffexclgroup.h"
|
|
#include "xfa/fxfa/cxfa_fffield.h"
|
|
#include "xfa/fxfa/cxfa_ffimage.h"
|
|
#include "xfa/fxfa/cxfa_ffimageedit.h"
|
|
#include "xfa/fxfa/cxfa_ffpageview.h"
|
|
#include "xfa/fxfa/cxfa_ffpushbutton.h"
|
|
#include "xfa/fxfa/cxfa_ffsignature.h"
|
|
#include "xfa/fxfa/cxfa_fftext.h"
|
|
#include "xfa/fxfa/cxfa_ffwidget.h"
|
|
#include "xfa/fxfa/cxfa_ffwidgethandler.h"
|
|
#include "xfa/fxfa/cxfa_fwladapterwidgetmgr.h"
|
|
#include "xfa/fxfa/cxfa_readynodeiterator.h"
|
|
#include "xfa/fxfa/cxfa_textprovider.h"
|
|
#include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
|
|
#include "xfa/fxfa/parser/cxfa_acrobat.h"
|
|
#include "xfa/fxfa/parser/cxfa_binditems.h"
|
|
#include "xfa/fxfa/parser/cxfa_calculate.h"
|
|
#include "xfa/fxfa/parser/cxfa_pageset.h"
|
|
#include "xfa/fxfa/parser/cxfa_present.h"
|
|
#include "xfa/fxfa/parser/cxfa_subform.h"
|
|
#include "xfa/fxfa/parser/cxfa_validate.h"
|
|
#include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
|
|
#include "xfa/fxfa/parser/xfa_utils.h"
|
|
|
|
const XFA_AttributeValue gs_EventActivity[] = {
|
|
XFA_AttributeValue::Click, XFA_AttributeValue::Change,
|
|
XFA_AttributeValue::DocClose, XFA_AttributeValue::DocReady,
|
|
XFA_AttributeValue::Enter, XFA_AttributeValue::Exit,
|
|
XFA_AttributeValue::Full, XFA_AttributeValue::IndexChange,
|
|
XFA_AttributeValue::Initialize, XFA_AttributeValue::MouseDown,
|
|
XFA_AttributeValue::MouseEnter, XFA_AttributeValue::MouseExit,
|
|
XFA_AttributeValue::MouseUp, XFA_AttributeValue::PostExecute,
|
|
XFA_AttributeValue::PostOpen, XFA_AttributeValue::PostPrint,
|
|
XFA_AttributeValue::PostSave, XFA_AttributeValue::PostSign,
|
|
XFA_AttributeValue::PostSubmit, XFA_AttributeValue::PreExecute,
|
|
XFA_AttributeValue::PreOpen, XFA_AttributeValue::PrePrint,
|
|
XFA_AttributeValue::PreSave, XFA_AttributeValue::PreSign,
|
|
XFA_AttributeValue::PreSubmit, XFA_AttributeValue::Ready,
|
|
XFA_AttributeValue::Unknown,
|
|
};
|
|
|
|
CXFA_FFDocView::CXFA_FFDocView(CXFA_FFDoc* pDoc) : m_pDoc(pDoc) {}
|
|
|
|
CXFA_FFDocView::~CXFA_FFDocView() = default;
|
|
|
|
void CXFA_FFDocView::InitLayout(CXFA_Node* pNode) {
|
|
RunBindItems();
|
|
ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Initialize, false, true);
|
|
ExecEventActivityByDeepFirst(pNode, XFA_EVENT_IndexChange, false, true);
|
|
}
|
|
|
|
int32_t CXFA_FFDocView::StartLayout() {
|
|
m_iStatus = XFA_DOCVIEW_LAYOUTSTATUS_Start;
|
|
m_pDoc->GetXFADoc()->DoProtoMerge();
|
|
m_pDoc->GetXFADoc()->DoDataMerge();
|
|
m_pXFADocLayout = GetXFALayout();
|
|
|
|
int32_t iStatus = m_pXFADocLayout->StartLayout(false);
|
|
if (iStatus < 0)
|
|
return iStatus;
|
|
|
|
CXFA_Node* pRootItem =
|
|
ToNode(m_pDoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form));
|
|
if (!pRootItem)
|
|
return iStatus;
|
|
|
|
InitLayout(pRootItem);
|
|
InitCalculate(pRootItem);
|
|
InitValidate(pRootItem);
|
|
|
|
ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, true, true);
|
|
m_iStatus = XFA_DOCVIEW_LAYOUTSTATUS_Start;
|
|
return iStatus;
|
|
}
|
|
|
|
int32_t CXFA_FFDocView::DoLayout() {
|
|
int32_t iStatus = m_pXFADocLayout->DoLayout();
|
|
if (iStatus != 100)
|
|
return iStatus;
|
|
|
|
m_iStatus = XFA_DOCVIEW_LAYOUTSTATUS_Doing;
|
|
return iStatus;
|
|
}
|
|
|
|
void CXFA_FFDocView::StopLayout() {
|
|
CXFA_Node* pRootItem =
|
|
ToNode(m_pDoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form));
|
|
if (!pRootItem)
|
|
return;
|
|
|
|
CXFA_Subform* pSubformNode =
|
|
pRootItem->GetChild<CXFA_Subform>(0, XFA_Element::Subform, false);
|
|
if (!pSubformNode)
|
|
return;
|
|
|
|
CXFA_PageSet* pPageSetNode =
|
|
pSubformNode->GetFirstChildByClass<CXFA_PageSet>(XFA_Element::PageSet);
|
|
if (!pPageSetNode)
|
|
return;
|
|
|
|
RunCalculateWidgets();
|
|
RunValidate();
|
|
|
|
InitLayout(pPageSetNode);
|
|
InitCalculate(pPageSetNode);
|
|
InitValidate(pPageSetNode);
|
|
|
|
ExecEventActivityByDeepFirst(pPageSetNode, XFA_EVENT_Ready, true, true);
|
|
ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, false, true);
|
|
ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_DocReady, false, true);
|
|
|
|
RunCalculateWidgets();
|
|
RunValidate();
|
|
|
|
if (RunLayout())
|
|
ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, false, true);
|
|
|
|
m_CalculateNodes.clear();
|
|
if (m_pFocusNode && !m_pFocusWidget)
|
|
SetFocusNode(m_pFocusNode.Get());
|
|
|
|
m_iStatus = XFA_DOCVIEW_LAYOUTSTATUS_End;
|
|
}
|
|
|
|
void CXFA_FFDocView::ShowNullTestMsg() {
|
|
int32_t iCount = pdfium::CollectionSize<int32_t>(m_arrNullTestMsg);
|
|
CXFA_FFApp* pApp = m_pDoc->GetApp();
|
|
IXFA_AppProvider* pAppProvider = pApp->GetAppProvider();
|
|
if (pAppProvider && iCount) {
|
|
int32_t iRemain = iCount > 7 ? iCount - 7 : 0;
|
|
iCount -= iRemain;
|
|
WideString wsMsg;
|
|
for (int32_t i = 0; i < iCount; i++)
|
|
wsMsg += m_arrNullTestMsg[i] + L"\n";
|
|
|
|
if (iRemain > 0) {
|
|
wsMsg += L"\n" + WideString::Format(
|
|
L"Message limit exceeded. Remaining %d "
|
|
L"validation errors not reported.",
|
|
iRemain);
|
|
}
|
|
pAppProvider->MsgBox(wsMsg, pAppProvider->GetAppTitle(),
|
|
static_cast<uint32_t>(AlertIcon::kStatus),
|
|
static_cast<uint32_t>(AlertButton::kOK));
|
|
}
|
|
m_arrNullTestMsg.clear();
|
|
}
|
|
|
|
void CXFA_FFDocView::UpdateDocView() {
|
|
if (IsUpdateLocked())
|
|
return;
|
|
|
|
LockUpdate();
|
|
while (!m_NewAddedNodes.empty()) {
|
|
CXFA_Node* pNode = m_NewAddedNodes.front();
|
|
m_NewAddedNodes.pop_front();
|
|
InitCalculate(pNode);
|
|
InitValidate(pNode);
|
|
ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Ready, true, true);
|
|
}
|
|
|
|
RunSubformIndexChange();
|
|
RunCalculateWidgets();
|
|
RunValidate();
|
|
|
|
ShowNullTestMsg();
|
|
|
|
if (RunLayout() && m_bLayoutEvent)
|
|
RunEventLayoutReady();
|
|
|
|
m_bLayoutEvent = false;
|
|
m_CalculateNodes.clear();
|
|
UnlockUpdate();
|
|
}
|
|
|
|
void CXFA_FFDocView::UpdateUIDisplay(CXFA_Node* pNode, CXFA_FFWidget* pExcept) {
|
|
CXFA_FFWidget* pWidget = GetWidgetForNode(pNode);
|
|
CXFA_FFWidget* pNext = nullptr;
|
|
for (; pWidget; pWidget = pNext) {
|
|
pNext = pWidget->GetNextFFWidget();
|
|
if (pWidget == pExcept || !pWidget->IsLoaded() ||
|
|
(pNode->GetFFWidgetType() != XFA_FFWidgetType::kCheckButton &&
|
|
pWidget->IsFocused())) {
|
|
continue;
|
|
}
|
|
ObservedPtr<CXFA_FFWidget> pWatched(pWidget);
|
|
ObservedPtr<CXFA_FFWidget> pWatchedNext(pNext);
|
|
pWatched->UpdateFWLData();
|
|
if (pWatched)
|
|
pWatched->InvalidateRect();
|
|
if (!pWatchedNext)
|
|
break;
|
|
}
|
|
}
|
|
|
|
int32_t CXFA_FFDocView::CountPageViews() const {
|
|
return m_pXFADocLayout ? m_pXFADocLayout->CountPages() : 0;
|
|
}
|
|
|
|
CXFA_FFPageView* CXFA_FFDocView::GetPageView(int32_t nIndex) const {
|
|
if (!m_pXFADocLayout)
|
|
return nullptr;
|
|
auto* pPage = m_pXFADocLayout->GetPage(nIndex);
|
|
return pPage ? pPage->GetPageView() : nullptr;
|
|
}
|
|
|
|
CXFA_LayoutProcessor* CXFA_FFDocView::GetXFALayout() const {
|
|
return CXFA_LayoutProcessor::FromDocument(m_pDoc->GetXFADoc());
|
|
}
|
|
|
|
bool CXFA_FFDocView::ResetSingleNodeData(CXFA_Node* pNode) {
|
|
XFA_Element eType = pNode->GetElementType();
|
|
if (eType != XFA_Element::Field && eType != XFA_Element::ExclGroup)
|
|
return false;
|
|
|
|
pNode->ResetData();
|
|
UpdateUIDisplay(pNode, nullptr);
|
|
CXFA_Validate* validate = pNode->GetValidateIfExists();
|
|
if (!validate)
|
|
return true;
|
|
|
|
AddValidateNode(pNode);
|
|
validate->SetFlag(XFA_NodeFlag_NeedsInitApp);
|
|
return true;
|
|
}
|
|
|
|
void CXFA_FFDocView::ResetNode(CXFA_Node* pNode) {
|
|
m_bLayoutEvent = true;
|
|
bool bChanged = false;
|
|
CXFA_Node* pFormNode = nullptr;
|
|
if (pNode) {
|
|
bChanged = ResetSingleNodeData(pNode);
|
|
pFormNode = pNode;
|
|
} else {
|
|
pFormNode = GetRootSubform();
|
|
}
|
|
if (!pFormNode)
|
|
return;
|
|
|
|
if (pFormNode->GetElementType() != XFA_Element::Field &&
|
|
pFormNode->GetElementType() != XFA_Element::ExclGroup) {
|
|
CXFA_ReadyNodeIterator it(pFormNode);
|
|
while (CXFA_Node* next_node = it.MoveToNext()) {
|
|
bChanged |= ResetSingleNodeData(next_node);
|
|
if (next_node->GetElementType() == XFA_Element::ExclGroup)
|
|
it.SkipTree();
|
|
}
|
|
}
|
|
if (bChanged)
|
|
m_pDoc->GetDocEnvironment()->SetChangeMark(m_pDoc.Get());
|
|
}
|
|
|
|
CXFA_FFWidget* CXFA_FFDocView::GetWidgetForNode(CXFA_Node* node) {
|
|
return GetFFWidget(ToContentLayoutItem(GetXFALayout()->GetLayoutItem(node)));
|
|
}
|
|
|
|
CXFA_FFWidgetHandler* CXFA_FFDocView::GetWidgetHandler() {
|
|
if (!m_pWidgetHandler)
|
|
m_pWidgetHandler = pdfium::MakeUnique<CXFA_FFWidgetHandler>(this);
|
|
return m_pWidgetHandler.get();
|
|
}
|
|
|
|
std::unique_ptr<CXFA_ReadyNodeIterator>
|
|
CXFA_FFDocView::CreateReadyNodeIterator() {
|
|
CXFA_Subform* pFormRoot = GetRootSubform();
|
|
return pFormRoot ? pdfium::MakeUnique<CXFA_ReadyNodeIterator>(pFormRoot)
|
|
: nullptr;
|
|
}
|
|
|
|
bool CXFA_FFDocView::SetFocus(CXFA_FFWidget* pNewFocus) {
|
|
if (pNewFocus == m_pFocusWidget)
|
|
return false;
|
|
|
|
ObservedPtr<CXFA_FFWidget> pNewWatched(pNewFocus);
|
|
if (m_pFocusWidget) {
|
|
CXFA_ContentLayoutItem* pItem = m_pFocusWidget->GetLayoutItem();
|
|
if (pItem->TestStatusBits(XFA_WidgetStatus_Visible) &&
|
|
!pItem->TestStatusBits(XFA_WidgetStatus_Focused)) {
|
|
if (!m_pFocusWidget->IsLoaded())
|
|
m_pFocusWidget->LoadWidget();
|
|
if (!m_pFocusWidget->OnSetFocus(m_pFocusWidget.Get()))
|
|
m_pFocusWidget.Reset();
|
|
}
|
|
}
|
|
if (m_pFocusWidget) {
|
|
if (!m_pFocusWidget->OnKillFocus(pNewWatched.Get()))
|
|
return false;
|
|
}
|
|
|
|
if (pNewWatched) {
|
|
if (pNewWatched->GetLayoutItem()->TestStatusBits(
|
|
XFA_WidgetStatus_Visible)) {
|
|
if (!pNewWatched->IsLoaded())
|
|
pNewWatched->LoadWidget();
|
|
if (!pNewWatched->OnSetFocus(m_pFocusWidget.Get()))
|
|
pNewWatched.Reset();
|
|
}
|
|
}
|
|
if (pNewWatched) {
|
|
CXFA_Node* node = pNewWatched->GetNode();
|
|
m_pFocusNode = node->IsWidgetReady() ? node : nullptr;
|
|
m_pFocusWidget.Reset(pNewWatched.Get());
|
|
} else {
|
|
m_pFocusNode.Reset();
|
|
m_pFocusWidget.Reset();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CXFA_FFDocView::SetFocusNode(CXFA_Node* node) {
|
|
CXFA_FFWidget* pNewFocus = node ? GetWidgetForNode(node) : nullptr;
|
|
if (!SetFocus(pNewFocus))
|
|
return;
|
|
|
|
m_pFocusNode = node;
|
|
if (m_iStatus != XFA_DOCVIEW_LAYOUTSTATUS_End)
|
|
return;
|
|
|
|
m_pDoc->GetDocEnvironment()->SetFocusWidget(m_pDoc.Get(),
|
|
m_pFocusWidget.Get());
|
|
}
|
|
|
|
void CXFA_FFDocView::DeleteLayoutItem(CXFA_FFWidget* pWidget) {
|
|
if (m_pFocusNode != pWidget->GetNode())
|
|
return;
|
|
|
|
m_pFocusNode.Reset();
|
|
m_pFocusWidget.Reset();
|
|
}
|
|
|
|
static XFA_EventError XFA_ProcessEvent(CXFA_FFDocView* pDocView,
|
|
CXFA_Node* pNode,
|
|
CXFA_EventParam* pParam) {
|
|
if (!pParam || pParam->m_eType == XFA_EVENT_Unknown)
|
|
return XFA_EventError::kNotExist;
|
|
if (pNode && pNode->GetElementType() == XFA_Element::Draw)
|
|
return XFA_EventError::kNotExist;
|
|
|
|
switch (pParam->m_eType) {
|
|
case XFA_EVENT_Calculate:
|
|
return pNode->ProcessCalculate(pDocView);
|
|
case XFA_EVENT_Validate:
|
|
if (pDocView->GetDoc()->GetDocEnvironment()->IsValidationsEnabled(
|
|
pDocView->GetDoc())) {
|
|
return pNode->ProcessValidate(pDocView, 0x01);
|
|
}
|
|
return XFA_EventError::kDisabled;
|
|
case XFA_EVENT_InitCalculate: {
|
|
CXFA_Calculate* calc = pNode->GetCalculateIfExists();
|
|
if (!calc)
|
|
return XFA_EventError::kNotExist;
|
|
if (pNode->IsUserInteractive())
|
|
return XFA_EventError::kDisabled;
|
|
|
|
return pNode->ExecuteScript(pDocView, calc->GetScriptIfExists(), pParam);
|
|
}
|
|
default:
|
|
return pNode->ProcessEvent(pDocView, gs_EventActivity[pParam->m_eType],
|
|
pParam);
|
|
}
|
|
}
|
|
|
|
XFA_EventError CXFA_FFDocView::ExecEventActivityByDeepFirst(
|
|
CXFA_Node* pFormNode,
|
|
XFA_EVENTTYPE eEventType,
|
|
bool bIsFormReady,
|
|
bool bRecursive) {
|
|
if (!pFormNode)
|
|
return XFA_EventError::kNotExist;
|
|
|
|
XFA_Element elementType = pFormNode->GetElementType();
|
|
if (elementType == XFA_Element::Field) {
|
|
if (eEventType == XFA_EVENT_IndexChange)
|
|
return XFA_EventError::kNotExist;
|
|
|
|
if (!pFormNode->IsWidgetReady())
|
|
return XFA_EventError::kNotExist;
|
|
|
|
CXFA_EventParam eParam;
|
|
eParam.m_eType = eEventType;
|
|
eParam.m_pTarget = pFormNode;
|
|
eParam.m_bIsFormReady = bIsFormReady;
|
|
return XFA_ProcessEvent(this, pFormNode, &eParam);
|
|
}
|
|
|
|
XFA_EventError iRet = XFA_EventError::kNotExist;
|
|
if (bRecursive) {
|
|
for (CXFA_Node* pNode = pFormNode->GetFirstContainerChild(); pNode;
|
|
pNode = pNode->GetNextContainerSibling()) {
|
|
elementType = pNode->GetElementType();
|
|
if (elementType != XFA_Element::Variables &&
|
|
elementType != XFA_Element::Draw) {
|
|
XFA_EventErrorAccumulate(
|
|
&iRet, ExecEventActivityByDeepFirst(pNode, eEventType, bIsFormReady,
|
|
bRecursive));
|
|
}
|
|
}
|
|
}
|
|
if (!pFormNode->IsWidgetReady())
|
|
return iRet;
|
|
|
|
CXFA_EventParam eParam;
|
|
eParam.m_eType = eEventType;
|
|
eParam.m_pTarget = pFormNode;
|
|
eParam.m_bIsFormReady = bIsFormReady;
|
|
|
|
XFA_EventErrorAccumulate(&iRet, XFA_ProcessEvent(this, pFormNode, &eParam));
|
|
return iRet;
|
|
}
|
|
|
|
CXFA_FFWidget* CXFA_FFDocView::GetWidgetByName(const WideString& wsName,
|
|
CXFA_FFWidget* pRefWidget) {
|
|
CFXJSE_Engine* pScriptContext = m_pDoc->GetXFADoc()->GetScriptContext();
|
|
CXFA_Node* pRefNode = nullptr;
|
|
if (pRefWidget) {
|
|
CXFA_Node* node = pRefWidget->GetNode();
|
|
pRefNode = node->IsWidgetReady() ? node : nullptr;
|
|
}
|
|
WideString wsExpression = (!pRefNode ? L"$form." : L"") + wsName;
|
|
|
|
XFA_RESOLVENODE_RS resolveNodeRS;
|
|
constexpr uint32_t kStyle = XFA_RESOLVENODE_Children |
|
|
XFA_RESOLVENODE_Properties |
|
|
XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_Parent;
|
|
if (!pScriptContext->ResolveObjects(pRefNode, wsExpression.AsStringView(),
|
|
&resolveNodeRS, kStyle, nullptr)) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (resolveNodeRS.dwFlags == XFA_ResolveNode_RSType_Nodes) {
|
|
CXFA_Node* pNode = resolveNodeRS.objects.front()->AsNode();
|
|
if (pNode && pNode->IsWidgetReady())
|
|
return GetWidgetForNode(pNode);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void CXFA_FFDocView::OnPageEvent(CXFA_ViewLayoutItem* pSender,
|
|
uint32_t dwEvent) {
|
|
CXFA_FFPageView* pFFPageView = pSender ? pSender->GetPageView() : nullptr;
|
|
m_pDoc->GetDocEnvironment()->PageViewEvent(pFFPageView, dwEvent);
|
|
}
|
|
|
|
void CXFA_FFDocView::InvalidateRect(CXFA_FFPageView* pPageView,
|
|
const CFX_RectF& rtInvalidate) {
|
|
m_pDoc->GetDocEnvironment()->InvalidateRect(pPageView, rtInvalidate);
|
|
}
|
|
|
|
bool CXFA_FFDocView::RunLayout() {
|
|
LockUpdate();
|
|
m_bInLayoutStatus = true;
|
|
if (!m_pXFADocLayout->IncrementLayout() &&
|
|
m_pXFADocLayout->StartLayout(false) < 100) {
|
|
m_pXFADocLayout->DoLayout();
|
|
UnlockUpdate();
|
|
m_bInLayoutStatus = false;
|
|
m_pDoc->GetDocEnvironment()->PageViewEvent(nullptr,
|
|
XFA_PAGEVIEWEVENT_StopLayout);
|
|
return true;
|
|
}
|
|
|
|
m_bInLayoutStatus = false;
|
|
m_pDoc->GetDocEnvironment()->PageViewEvent(nullptr,
|
|
XFA_PAGEVIEWEVENT_StopLayout);
|
|
UnlockUpdate();
|
|
return false;
|
|
}
|
|
|
|
void CXFA_FFDocView::RunSubformIndexChange() {
|
|
std::set<CXFA_Node*> seen;
|
|
while (!m_IndexChangedSubforms.empty()) {
|
|
CXFA_Node* pSubformNode = m_IndexChangedSubforms.front();
|
|
m_IndexChangedSubforms.pop_front();
|
|
bool bInserted = seen.insert(pSubformNode).second;
|
|
if (!bInserted || !pSubformNode->IsWidgetReady())
|
|
continue;
|
|
|
|
CXFA_EventParam eParam;
|
|
eParam.m_eType = XFA_EVENT_IndexChange;
|
|
eParam.m_pTarget = pSubformNode;
|
|
pSubformNode->ProcessEvent(this, XFA_AttributeValue::IndexChange, &eParam);
|
|
}
|
|
}
|
|
|
|
void CXFA_FFDocView::AddNewFormNode(CXFA_Node* pNode) {
|
|
m_NewAddedNodes.push_back(pNode);
|
|
InitLayout(pNode);
|
|
}
|
|
|
|
void CXFA_FFDocView::AddIndexChangedSubform(CXFA_Node* pNode) {
|
|
ASSERT(pNode->GetElementType() == XFA_Element::Subform);
|
|
if (!pdfium::ContainsValue(m_IndexChangedSubforms, pNode))
|
|
m_IndexChangedSubforms.push_back(pNode);
|
|
}
|
|
|
|
void CXFA_FFDocView::RunDocClose() {
|
|
CXFA_Node* pRootItem =
|
|
ToNode(m_pDoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form));
|
|
if (!pRootItem)
|
|
return;
|
|
|
|
ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_DocClose, false, true);
|
|
}
|
|
|
|
void CXFA_FFDocView::AddCalculateNode(CXFA_Node* node) {
|
|
CXFA_Node* pCurrentNode =
|
|
!m_CalculateNodes.empty() ? m_CalculateNodes.back() : nullptr;
|
|
if (pCurrentNode != node)
|
|
m_CalculateNodes.push_back(node);
|
|
}
|
|
|
|
void CXFA_FFDocView::AddCalculateNodeNotify(CXFA_Node* pNodeChange) {
|
|
CXFA_CalcData* pGlobalData = pNodeChange->JSObject()->GetCalcData();
|
|
if (!pGlobalData)
|
|
return;
|
|
|
|
for (auto* pResult : pGlobalData->m_Globals) {
|
|
if (!pResult->HasRemovedChildren() && pResult->IsWidgetReady())
|
|
AddCalculateNode(pResult);
|
|
}
|
|
}
|
|
|
|
size_t CXFA_FFDocView::RunCalculateRecursive(size_t index) {
|
|
while (index < m_CalculateNodes.size()) {
|
|
CXFA_Node* node = m_CalculateNodes[index];
|
|
|
|
AddCalculateNodeNotify(node);
|
|
size_t recurse = node->JSObject()->GetCalcRecursionCount() + 1;
|
|
node->JSObject()->SetCalcRecursionCount(recurse);
|
|
if (recurse > 11)
|
|
break;
|
|
if (node->ProcessCalculate(this) == XFA_EventError::kSuccess &&
|
|
node->IsWidgetReady()) {
|
|
AddValidateNode(node);
|
|
}
|
|
|
|
index = RunCalculateRecursive(++index);
|
|
}
|
|
return index;
|
|
}
|
|
|
|
XFA_EventError CXFA_FFDocView::RunCalculateWidgets() {
|
|
if (!m_pDoc->GetDocEnvironment()->IsCalculationsEnabled(m_pDoc.Get()))
|
|
return XFA_EventError::kDisabled;
|
|
|
|
if (!m_CalculateNodes.empty())
|
|
RunCalculateRecursive(0);
|
|
|
|
for (CXFA_Node* node : m_CalculateNodes)
|
|
node->JSObject()->SetCalcRecursionCount(0);
|
|
|
|
m_CalculateNodes.clear();
|
|
return XFA_EventError::kSuccess;
|
|
}
|
|
|
|
void CXFA_FFDocView::AddValidateNode(CXFA_Node* node) {
|
|
if (!pdfium::ContainsValue(m_ValidateNodes, node))
|
|
m_ValidateNodes.push_back(node);
|
|
}
|
|
|
|
void CXFA_FFDocView::InitCalculate(CXFA_Node* pNode) {
|
|
ExecEventActivityByDeepFirst(pNode, XFA_EVENT_InitCalculate, false, true);
|
|
}
|
|
|
|
void CXFA_FFDocView::ProcessValueChanged(CXFA_Node* node) {
|
|
AddValidateNode(node);
|
|
AddCalculateNode(node);
|
|
RunCalculateWidgets();
|
|
RunValidate();
|
|
}
|
|
|
|
bool CXFA_FFDocView::InitValidate(CXFA_Node* pNode) {
|
|
if (!m_pDoc->GetDocEnvironment()->IsValidationsEnabled(m_pDoc.Get()))
|
|
return false;
|
|
|
|
ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Validate, false, true);
|
|
m_ValidateNodes.clear();
|
|
return true;
|
|
}
|
|
|
|
bool CXFA_FFDocView::RunValidate() {
|
|
if (!m_pDoc->GetDocEnvironment()->IsValidationsEnabled(m_pDoc.Get()))
|
|
return false;
|
|
|
|
while (!m_ValidateNodes.empty()) {
|
|
CXFA_Node* node = m_ValidateNodes.front();
|
|
m_ValidateNodes.pop_front();
|
|
if (!node->HasRemovedChildren())
|
|
node->ProcessValidate(this, 0);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CXFA_FFDocView::RunEventLayoutReady() {
|
|
CXFA_Node* pRootItem =
|
|
ToNode(m_pDoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form));
|
|
if (!pRootItem)
|
|
return false;
|
|
|
|
ExecEventActivityByDeepFirst(pRootItem, XFA_EVENT_Ready, false, true);
|
|
RunLayout();
|
|
return true;
|
|
}
|
|
|
|
void CXFA_FFDocView::RunBindItems() {
|
|
while (!m_BindItems.empty()) {
|
|
CXFA_BindItems* item = m_BindItems.front();
|
|
m_BindItems.pop_front();
|
|
if (item->HasRemovedChildren())
|
|
continue;
|
|
|
|
CXFA_Node* pWidgetNode = item->GetParent();
|
|
if (!pWidgetNode || !pWidgetNode->IsWidgetReady())
|
|
continue;
|
|
|
|
CFXJSE_Engine* pScriptContext =
|
|
pWidgetNode->GetDocument()->GetScriptContext();
|
|
WideString wsRef = item->GetRef();
|
|
constexpr uint32_t kStyle =
|
|
XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
|
|
XFA_RESOLVENODE_Siblings | XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_ALL;
|
|
XFA_RESOLVENODE_RS rs;
|
|
pScriptContext->ResolveObjects(pWidgetNode, wsRef.AsStringView(), &rs,
|
|
kStyle, nullptr);
|
|
pWidgetNode->DeleteItem(-1, false, false);
|
|
if (rs.dwFlags != XFA_ResolveNode_RSType_Nodes || rs.objects.empty())
|
|
continue;
|
|
|
|
WideString wsValueRef = item->GetValueRef();
|
|
WideString wsLabelRef = item->GetLabelRef();
|
|
const bool bUseValue = wsLabelRef.IsEmpty() || wsLabelRef == wsValueRef;
|
|
const bool bLabelUseContent =
|
|
wsLabelRef.IsEmpty() || wsLabelRef.EqualsASCII("$");
|
|
const bool bValueUseContent =
|
|
wsValueRef.IsEmpty() || wsValueRef.EqualsASCII("$");
|
|
WideString wsValue;
|
|
WideString wsLabel;
|
|
uint32_t uValueHash = FX_HashCode_GetW(wsValueRef.AsStringView(), false);
|
|
for (auto& refObject : rs.objects) {
|
|
CXFA_Node* refNode = refObject->AsNode();
|
|
if (!refNode)
|
|
continue;
|
|
|
|
if (bValueUseContent) {
|
|
wsValue = refNode->JSObject()->GetContent(false);
|
|
} else {
|
|
CXFA_Node* nodeValue = refNode->GetFirstChildByName(uValueHash);
|
|
wsValue = nodeValue ? nodeValue->JSObject()->GetContent(false)
|
|
: refNode->JSObject()->GetContent(false);
|
|
}
|
|
|
|
if (!bUseValue) {
|
|
if (bLabelUseContent) {
|
|
wsLabel = refNode->JSObject()->GetContent(false);
|
|
} else {
|
|
CXFA_Node* nodeLabel =
|
|
refNode->GetFirstChildByName(wsLabelRef.AsStringView());
|
|
if (nodeLabel)
|
|
wsLabel = nodeLabel->JSObject()->GetContent(false);
|
|
}
|
|
} else {
|
|
wsLabel = wsValue;
|
|
}
|
|
pWidgetNode->InsertItem(wsLabel, wsValue, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CXFA_FFDocView::SetChangeMark() {
|
|
if (m_iStatus < XFA_DOCVIEW_LAYOUTSTATUS_End)
|
|
return;
|
|
|
|
m_pDoc->GetDocEnvironment()->SetChangeMark(m_pDoc.Get());
|
|
}
|
|
|
|
CXFA_Subform* CXFA_FFDocView::GetRootSubform() {
|
|
CXFA_Node* pFormPacketNode =
|
|
ToNode(m_pDoc->GetXFADoc()->GetXFAObject(XFA_HASHCODE_Form));
|
|
if (!pFormPacketNode)
|
|
return nullptr;
|
|
|
|
return pFormPacketNode->GetFirstChildByClass<CXFA_Subform>(
|
|
XFA_Element::Subform);
|
|
}
|