blob: 7d4ef85803fc86e0a7f3ea59a2bb5c45b523ab3b [file] [log] [blame]
// Copyright 2014 The PDFium Authors
// 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 "core/fxcrt/stl_util.h"
#include "core/fxcrt/xml/cfx_xmlparser.h"
#include "fxjs/gc/container_trace.h"
#include "fxjs/xfa/cfxjse_engine.h"
#include "fxjs/xfa/cjx_object.h"
#include "third_party/base/check_op.h"
#include "third_party/base/containers/contains.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_utils.h"
namespace {
bool IsValidXMLNameString(const WideString& str) {
bool first = true;
for (const auto ch : str) {
if (!CFX_XMLParser::IsXMLNameChar(ch, first)) {
return false;
}
first = false;
}
return true;
}
} // namespace
const XFA_AttributeValue kXFAEventActivity[] = {
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::UpdateScope::UpdateScope(CXFA_FFDocView* pDocView)
: m_pDocView(pDocView) {
m_pDocView->LockUpdate();
}
CXFA_FFDocView::UpdateScope::~UpdateScope() {
m_pDocView->UnlockUpdate();
m_pDocView->UpdateDocView();
}
CXFA_FFDocView::CXFA_FFDocView(CXFA_FFDoc* pDoc) : m_pDoc(pDoc) {}
CXFA_FFDocView::~CXFA_FFDocView() = default;
void CXFA_FFDocView::Trace(cppgc::Visitor* visitor) const {
visitor->Trace(m_pDoc);
visitor->Trace(m_pWidgetHandler);
visitor->Trace(m_pFocusNode);
visitor->Trace(m_pFocusWidget);
ContainerTrace(visitor, m_ValidateNodes);
ContainerTrace(visitor, m_CalculateNodes);
ContainerTrace(visitor, m_NewAddedNodes);
ContainerTrace(visitor, m_BindItems);
ContainerTrace(visitor, m_IndexChangedSubforms);
}
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 = LayoutStatus::kStart;
m_pDoc->GetXFADoc()->DoProtoMerge();
m_pDoc->GetXFADoc()->DoDataMerge();
int32_t iStatus = GetLayoutProcessor()->StartLayout();
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 = LayoutStatus::kStart;
return iStatus;
}
int32_t CXFA_FFDocView::DoLayout() {
int32_t iStatus = GetLayoutProcessor()->DoLayout();
if (iStatus != 100)
return iStatus;
m_iStatus = LayoutStatus::kDoing;
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);
m_iStatus = LayoutStatus::kEnd;
}
void CXFA_FFDocView::AddNullTestMsg(const WideString& msg) {
m_NullTestMsgArray.push_back(msg);
}
void CXFA_FFDocView::ShowNullTestMsg() {
int32_t iCount = fxcrt::CollectionSize<int32_t>(m_NullTestMsgArray);
CXFA_FFApp* pApp = m_pDoc->GetApp();
CXFA_FFApp::CallbackIface* 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_NullTestMsgArray[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_NullTestMsgArray.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;
}
pWidget->UpdateFWLData();
pWidget->InvalidateRect();
}
}
int32_t CXFA_FFDocView::CountPageViews() const {
CXFA_LayoutProcessor* pProcessor = GetLayoutProcessor();
return pProcessor ? pProcessor->CountPages() : 0;
}
CXFA_FFPageView* CXFA_FFDocView::GetPageView(int32_t nIndex) const {
CXFA_LayoutProcessor* pProcessor = GetLayoutProcessor();
if (!pProcessor)
return nullptr;
auto* pPage = pProcessor->GetPage(nIndex);
return pPage ? pPage->GetPageView() : nullptr;
}
CXFA_LayoutProcessor* CXFA_FFDocView::GetLayoutProcessor() 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::kNeedsInitApp);
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->SetChangeMark();
}
CXFA_FFWidget* CXFA_FFDocView::GetWidgetForNode(CXFA_Node* node) {
return GetFFWidget(
ToContentLayoutItem(GetLayoutProcessor()->GetLayoutItem(node)));
}
CXFA_FFWidgetHandler* CXFA_FFDocView::GetWidgetHandler() {
if (!m_pWidgetHandler) {
m_pWidgetHandler = cppgc::MakeGarbageCollected<CXFA_FFWidgetHandler>(
m_pDoc->GetHeap()->GetAllocationHandle(), this);
}
return m_pWidgetHandler;
}
bool CXFA_FFDocView::SetFocus(CXFA_FFWidget* pNewFocus) {
if (pNewFocus == m_pFocusWidget)
return false;
if (m_pFocusWidget) {
CXFA_ContentLayoutItem* pItem = m_pFocusWidget->GetLayoutItem();
if (pItem->TestStatusBits(XFA_WidgetStatus::kVisible) &&
!pItem->TestStatusBits(XFA_WidgetStatus::kFocused)) {
if (!m_pFocusWidget->IsLoaded())
m_pFocusWidget->LoadWidget();
if (!m_pFocusWidget->OnSetFocus(m_pFocusWidget))
m_pFocusWidget.Clear();
}
}
if (m_pFocusWidget) {
if (!m_pFocusWidget->OnKillFocus(pNewFocus))
return false;
}
if (pNewFocus) {
if (pNewFocus->GetLayoutItem()->TestStatusBits(
XFA_WidgetStatus::kVisible)) {
if (!pNewFocus->IsLoaded())
pNewFocus->LoadWidget();
if (!pNewFocus->OnSetFocus(m_pFocusWidget))
pNewFocus = nullptr;
}
}
if (pNewFocus) {
CXFA_Node* node = pNewFocus->GetNode();
m_pFocusNode = node->IsWidgetReady() ? node : nullptr;
m_pFocusWidget = pNewFocus;
} else {
m_pFocusNode.Clear();
m_pFocusWidget.Clear();
}
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 != LayoutStatus::kEnd)
return;
m_pDoc->SetFocusWidget(m_pFocusWidget);
}
void CXFA_FFDocView::DeleteLayoutItem(CXFA_FFWidget* pWidget) {
if (m_pFocusNode != pWidget->GetNode())
return;
m_pFocusNode.Clear();
m_pFocusWidget.Clear();
}
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()->IsValidationsEnabled())
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, kXFAEventActivity[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_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_bIsFormReady = bIsFormReady;
XFA_EventErrorAccumulate(&iRet, XFA_ProcessEvent(this, pFormNode, &eParam));
return iRet;
}
CXFA_FFWidget* CXFA_FFDocView::GetWidgetByName(const WideString& wsName,
CXFA_FFWidget* pRefWidget) {
if (!IsValidXMLNameString(wsName)) {
return nullptr;
}
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;
absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
pScriptContext->ResolveObjects(
pRefNode, wsExpression.AsStringView(),
Mask<XFA_ResolveFlag>{
XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kProperties,
XFA_ResolveFlag::kSiblings, XFA_ResolveFlag::kParent});
if (!maybeResult.has_value())
return nullptr;
if (maybeResult.value().type == CFXJSE_Engine::ResolveResult::Type::kNodes) {
CXFA_Node* pNode = maybeResult.value().objects.front()->AsNode();
if (pNode && pNode->IsWidgetReady())
return GetWidgetForNode(pNode);
}
return nullptr;
}
void CXFA_FFDocView::OnPageViewEvent(CXFA_ViewLayoutItem* pSender,
CXFA_FFDoc::PageViewEvent eEvent) {
CXFA_FFPageView* pFFPageView = pSender ? pSender->GetPageView() : nullptr;
m_pDoc->OnPageViewEvent(pFFPageView, eEvent);
}
void CXFA_FFDocView::InvalidateRect(CXFA_FFPageView* pPageView,
const CFX_RectF& rtInvalidate) {
m_pDoc->InvalidateRect(pPageView, rtInvalidate);
}
bool CXFA_FFDocView::RunLayout() {
LockUpdate();
m_bInLayoutStatus = true;
CXFA_LayoutProcessor* pProcessor = GetLayoutProcessor();
if (!pProcessor->IncrementLayout() && pProcessor->StartLayout() < 100) {
pProcessor->DoLayout();
UnlockUpdate();
m_bInLayoutStatus = false;
m_pDoc->OnPageViewEvent(nullptr, CXFA_FFDoc::PageViewEvent::kStopLayout);
return true;
}
m_bInLayoutStatus = false;
m_pDoc->OnPageViewEvent(nullptr, CXFA_FFDoc::PageViewEvent::kStopLayout);
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;
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_Subform* pNode) {
if (!pdfium::Contains(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) {
CJX_Object::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->IsCalculationsEnabled())
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::Contains(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->IsValidationsEnabled())
return false;
ExecEventActivityByDeepFirst(pNode, XFA_EVENT_Validate, false, true);
m_ValidateNodes.clear();
return true;
}
bool CXFA_FFDocView::RunValidate() {
if (!m_pDoc->IsValidationsEnabled())
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();
absl::optional<CFXJSE_Engine::ResolveResult> maybeRS =
pScriptContext->ResolveObjects(
pWidgetNode, wsRef.AsStringView(),
Mask<XFA_ResolveFlag>{
XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kProperties,
XFA_ResolveFlag::kSiblings, XFA_ResolveFlag::kParent,
XFA_ResolveFlag::kALL});
pWidgetNode->DeleteItem(-1, false, false);
if (!maybeRS.has_value() ||
maybeRS.value().type != CFXJSE_Engine::ResolveResult::Type::kNodes ||
maybeRS.value().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());
for (auto& refObject : maybeRS.value().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 != LayoutStatus::kEnd)
return;
m_pDoc->SetChangeMark();
}
CXFA_Node* 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);
}