| // 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/parser/cxfa_layoutpagemgr.h" | |
| #include "fxjs/cfxjse_engine.h" | |
| #include "third_party/base/stl_util.h" | |
| #include "xfa/fxfa/cxfa_ffnotify.h" | |
| #include "xfa/fxfa/parser/cxfa_containerlayoutitem.h" | |
| #include "xfa/fxfa/parser/cxfa_contentlayoutitem.h" | |
| #include "xfa/fxfa/parser/cxfa_document.h" | |
| #include "xfa/fxfa/parser/cxfa_itemlayoutprocessor.h" | |
| #include "xfa/fxfa/parser/cxfa_layoutprocessor.h" | |
| #include "xfa/fxfa/parser/cxfa_localemgr.h" | |
| #include "xfa/fxfa/parser/cxfa_measurement.h" | |
| #include "xfa/fxfa/parser/cxfa_node.h" | |
| #include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h" | |
| #include "xfa/fxfa/parser/cxfa_object.h" | |
| #include "xfa/fxfa/parser/cxfa_traversestrategy_contentareacontainerlayoutitem.h" | |
| #include "xfa/fxfa/parser/cxfa_traversestrategy_layoutitem.h" | |
| #include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h" | |
| #include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h" | |
| #include "xfa/fxfa/parser/xfa_document_datamerger_imp.h" | |
| #include "xfa/fxfa/parser/xfa_resolvenode_rs.h" | |
| namespace { | |
| class PageSetContainerLayoutItem { | |
| public: | |
| static CXFA_ContainerLayoutItem* GetFirstChild( | |
| CXFA_ContainerLayoutItem* pLayoutItem) { | |
| if (pLayoutItem->m_pFormNode->GetElementType() != XFA_Element::PageSet) | |
| return nullptr; | |
| CXFA_ContainerLayoutItem* pChildItem = | |
| static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pFirstChild); | |
| while (pChildItem && | |
| pChildItem->m_pFormNode->GetElementType() != XFA_Element::PageSet) { | |
| pChildItem = | |
| static_cast<CXFA_ContainerLayoutItem*>(pChildItem->m_pNextSibling); | |
| } | |
| return pChildItem; | |
| } | |
| static CXFA_ContainerLayoutItem* GetNextSibling( | |
| CXFA_ContainerLayoutItem* pLayoutItem) { | |
| CXFA_ContainerLayoutItem* pChildItem = | |
| static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pNextSibling); | |
| while (pChildItem && | |
| pChildItem->m_pFormNode->GetElementType() != XFA_Element::PageSet) { | |
| pChildItem = | |
| static_cast<CXFA_ContainerLayoutItem*>(pChildItem->m_pNextSibling); | |
| } | |
| return pChildItem; | |
| } | |
| static CXFA_ContainerLayoutItem* GetParent( | |
| CXFA_ContainerLayoutItem* pLayoutItem) { | |
| return static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pParent); | |
| } | |
| }; | |
| uint32_t GetRelevant(CXFA_Node* pFormItem, uint32_t dwParentRelvant) { | |
| uint32_t dwRelevant = XFA_WidgetStatus_Viewable | XFA_WidgetStatus_Printable; | |
| WideString wsRelevant = | |
| pFormItem->JSNode()->GetCData(XFA_Attribute::Relevant); | |
| if (!wsRelevant.IsEmpty()) { | |
| if (wsRelevant == L"+print" || wsRelevant == L"print") | |
| dwRelevant &= ~XFA_WidgetStatus_Viewable; | |
| else if (wsRelevant == L"-print") | |
| dwRelevant &= ~XFA_WidgetStatus_Printable; | |
| } | |
| if (!(dwParentRelvant & XFA_WidgetStatus_Viewable) && | |
| (dwRelevant != XFA_WidgetStatus_Viewable)) { | |
| dwRelevant &= ~XFA_WidgetStatus_Viewable; | |
| } | |
| if (!(dwParentRelvant & XFA_WidgetStatus_Printable) && | |
| (dwRelevant != XFA_WidgetStatus_Printable)) { | |
| dwRelevant &= ~XFA_WidgetStatus_Printable; | |
| } | |
| return dwRelevant; | |
| } | |
| void SyncContainer(CXFA_FFNotify* pNotify, | |
| CXFA_LayoutProcessor* pDocLayout, | |
| CXFA_LayoutItem* pContainerItem, | |
| uint32_t dwRelevant, | |
| bool bVisible, | |
| int32_t nPageIndex) { | |
| bool bVisibleItem = false; | |
| uint32_t dwStatus = 0; | |
| uint32_t dwRelevantContainer = 0; | |
| if (bVisible) { | |
| XFA_AttributeEnum eAttributeValue = | |
| pContainerItem->m_pFormNode->JSNode() | |
| ->TryEnum(XFA_Attribute::Presence, true) | |
| .value_or(XFA_AttributeEnum::Visible); | |
| if (eAttributeValue == XFA_AttributeEnum::Visible) | |
| bVisibleItem = true; | |
| dwRelevantContainer = GetRelevant(pContainerItem->m_pFormNode, dwRelevant); | |
| dwStatus = | |
| (bVisibleItem ? XFA_WidgetStatus_Visible : 0) | dwRelevantContainer; | |
| } | |
| pNotify->OnLayoutItemAdded(pDocLayout, pContainerItem, nPageIndex, dwStatus); | |
| for (CXFA_LayoutItem* pChild = pContainerItem->m_pFirstChild; pChild; | |
| pChild = pChild->m_pNextSibling) { | |
| if (pChild->IsContentLayoutItem()) { | |
| SyncContainer(pNotify, pDocLayout, pChild, dwRelevantContainer, | |
| bVisibleItem, nPageIndex); | |
| } | |
| } | |
| } | |
| void ReorderLayoutItemToTail(CXFA_ContainerLayoutItem* pLayoutItem) { | |
| CXFA_ContainerLayoutItem* pParentLayoutItem = | |
| static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pParent); | |
| if (!pParentLayoutItem) | |
| return; | |
| pParentLayoutItem->RemoveChild(pLayoutItem); | |
| pParentLayoutItem->AddChild(pLayoutItem); | |
| } | |
| void RemoveLayoutItem(CXFA_ContainerLayoutItem* pLayoutItem) { | |
| CXFA_ContainerLayoutItem* pParentLayoutItem = | |
| static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pParent); | |
| if (!pParentLayoutItem) | |
| return; | |
| pParentLayoutItem->RemoveChild(pLayoutItem); | |
| } | |
| CXFA_Node* ResolveBreakTarget(CXFA_Node* pPageSetRoot, | |
| bool bNewExprStyle, | |
| WideString& wsTargetAll) { | |
| CXFA_Document* pDocument = pPageSetRoot->GetDocument(); | |
| if (wsTargetAll.IsEmpty()) | |
| return nullptr; | |
| wsTargetAll.Trim(); | |
| int32_t iSplitIndex = 0; | |
| bool bTargetAllFind = true; | |
| while (iSplitIndex != -1) { | |
| WideString wsExpr; | |
| pdfium::Optional<size_t> iSplitNextIndex = 0; | |
| if (!bTargetAllFind) { | |
| iSplitNextIndex = wsTargetAll.Find(' ', iSplitIndex); | |
| if (!iSplitNextIndex.has_value()) | |
| return nullptr; | |
| wsExpr = | |
| wsTargetAll.Mid(iSplitIndex, iSplitNextIndex.value() - iSplitIndex); | |
| } else { | |
| wsExpr = wsTargetAll; | |
| } | |
| if (wsExpr.IsEmpty()) | |
| return nullptr; | |
| bTargetAllFind = false; | |
| if (wsExpr[0] == '#') { | |
| CXFA_Node* pNode = pDocument->GetNodeByID( | |
| ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Template)), | |
| wsExpr.Right(wsExpr.GetLength() - 1).AsStringView()); | |
| if (pNode) | |
| return pNode; | |
| } else if (bNewExprStyle) { | |
| WideString wsProcessedTarget = wsExpr; | |
| if (wsExpr.Left(4) == L"som(" && wsExpr.Last() == L')') { | |
| wsProcessedTarget = wsExpr.Mid(4, wsExpr.GetLength() - 5); | |
| } | |
| XFA_RESOLVENODE_RS rs; | |
| bool iRet = pDocument->GetScriptContext()->ResolveObjects( | |
| pPageSetRoot, wsProcessedTarget.AsStringView(), &rs, | |
| XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties | | |
| XFA_RESOLVENODE_Attributes | XFA_RESOLVENODE_Siblings | | |
| XFA_RESOLVENODE_Parent, | |
| nullptr); | |
| if (iRet && rs.objects.front()->IsNode()) | |
| return rs.objects.front()->AsNode(); | |
| } | |
| iSplitIndex = iSplitNextIndex.value(); | |
| } | |
| return nullptr; | |
| } | |
| void SetLayoutGeneratedNodeFlag(CXFA_Node* pNode) { | |
| pNode->SetFlag(XFA_NodeFlag_LayoutGeneratedNode, false); | |
| pNode->ClearFlag(XFA_NodeFlag_UnusedNode); | |
| } | |
| bool CheckContentAreaNotUsed( | |
| CXFA_ContainerLayoutItem* pPageAreaLayoutItem, | |
| CXFA_Node* pContentArea, | |
| CXFA_ContainerLayoutItem*& pContentAreaLayoutItem) { | |
| for (CXFA_ContainerLayoutItem* pLayoutItem = | |
| static_cast<CXFA_ContainerLayoutItem*>( | |
| pPageAreaLayoutItem->m_pFirstChild); | |
| pLayoutItem; pLayoutItem = static_cast<CXFA_ContainerLayoutItem*>( | |
| pLayoutItem->m_pNextSibling)) { | |
| if (pLayoutItem->m_pFormNode == pContentArea) { | |
| if (!pLayoutItem->m_pFirstChild) { | |
| pContentAreaLayoutItem = pLayoutItem; | |
| return true; | |
| } | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| void SyncRemoveLayoutItem(CXFA_LayoutItem* pParentLayoutItem, | |
| CXFA_FFNotify* pNotify, | |
| CXFA_LayoutProcessor* pDocLayout) { | |
| CXFA_LayoutItem* pNextLayoutItem; | |
| CXFA_LayoutItem* pCurLayoutItem = pParentLayoutItem->m_pFirstChild; | |
| while (pCurLayoutItem) { | |
| pNextLayoutItem = pCurLayoutItem->m_pNextSibling; | |
| if (pCurLayoutItem->m_pFirstChild) | |
| SyncRemoveLayoutItem(pCurLayoutItem, pNotify, pDocLayout); | |
| pNotify->OnLayoutItemRemoving(pDocLayout, pCurLayoutItem); | |
| delete pCurLayoutItem; | |
| pCurLayoutItem = pNextLayoutItem; | |
| } | |
| } | |
| } // namespace | |
| class CXFA_ContainerRecord { | |
| public: | |
| CXFA_ContainerRecord(CXFA_ContainerLayoutItem* pPageSet = nullptr, | |
| CXFA_ContainerLayoutItem* pPageArea = nullptr, | |
| CXFA_ContainerLayoutItem* pContentArea = nullptr) | |
| : pCurPageSet(pPageSet), | |
| pCurPageArea(pPageArea), | |
| pCurContentArea(pContentArea) {} | |
| CXFA_ContainerLayoutItem* pCurPageSet; | |
| CXFA_ContainerLayoutItem* pCurPageArea; | |
| CXFA_ContainerLayoutItem* pCurContentArea; | |
| }; | |
| CXFA_LayoutPageMgr::CXFA_LayoutPageMgr(CXFA_LayoutProcessor* pLayoutProcessor) | |
| : m_pLayoutProcessor(pLayoutProcessor), | |
| m_pTemplatePageSetRoot(nullptr), | |
| m_pPageSetLayoutItemRoot(nullptr), | |
| m_pPageSetCurRoot(nullptr), | |
| m_CurrentContainerRecordIter(m_ProposedContainerRecords.end()), | |
| m_pCurPageArea(nullptr), | |
| m_nAvailPages(0), | |
| m_nCurPageCount(0), | |
| m_ePageSetMode(XFA_AttributeEnum::OrderedOccurrence), | |
| m_bCreateOverFlowPage(false) {} | |
| CXFA_LayoutPageMgr::~CXFA_LayoutPageMgr() { | |
| ClearData(); | |
| CXFA_LayoutItem* pLayoutItem = GetRootLayoutItem(); | |
| CXFA_LayoutItem* pNextLayout = nullptr; | |
| for (; pLayoutItem; pLayoutItem = pNextLayout) { | |
| pNextLayout = pLayoutItem->m_pNextSibling; | |
| XFA_ReleaseLayoutItem(pLayoutItem); | |
| } | |
| } | |
| bool CXFA_LayoutPageMgr::InitLayoutPage(CXFA_Node* pFormNode) { | |
| PrepareLayout(); | |
| CXFA_Node* pTemplateNode = pFormNode->GetTemplateNode(); | |
| if (!pTemplateNode) | |
| return false; | |
| m_pTemplatePageSetRoot = | |
| pTemplateNode->JSNode()->GetProperty(0, XFA_Element::PageSet, true); | |
| ASSERT(m_pTemplatePageSetRoot); | |
| if (m_pPageSetLayoutItemRoot) { | |
| m_pPageSetLayoutItemRoot->m_pParent = nullptr; | |
| m_pPageSetLayoutItemRoot->m_pFirstChild = nullptr; | |
| m_pPageSetLayoutItemRoot->m_pNextSibling = nullptr; | |
| m_pPageSetLayoutItemRoot->m_pFormNode = m_pTemplatePageSetRoot; | |
| } else { | |
| m_pPageSetLayoutItemRoot = | |
| new CXFA_ContainerLayoutItem(m_pTemplatePageSetRoot); | |
| } | |
| m_pPageSetCurRoot = m_pPageSetLayoutItemRoot; | |
| m_pTemplatePageSetRoot->JSNode()->SetLayoutItem(m_pPageSetLayoutItemRoot); | |
| XFA_AttributeEnum eRelation = | |
| m_pTemplatePageSetRoot->JSNode()->GetEnum(XFA_Attribute::Relation); | |
| if (eRelation != XFA_AttributeEnum::Unknown) | |
| m_ePageSetMode = eRelation; | |
| InitPageSetMap(); | |
| CXFA_Node* pPageArea = nullptr; | |
| int32_t iCount = 0; | |
| for (pPageArea = m_pTemplatePageSetRoot->GetNodeItem(XFA_NODEITEM_FirstChild); | |
| pPageArea; | |
| pPageArea = pPageArea->GetNodeItem(XFA_NODEITEM_NextSibling)) { | |
| if (pPageArea->GetElementType() == XFA_Element::PageArea) { | |
| iCount++; | |
| if (pPageArea->GetFirstChildByClass(XFA_Element::ContentArea)) | |
| return true; | |
| } | |
| } | |
| if (iCount > 0) | |
| return false; | |
| CXFA_Document* pDocument = pTemplateNode->GetDocument(); | |
| pPageArea = m_pTemplatePageSetRoot->GetChild(0, XFA_Element::PageArea, false); | |
| if (!pPageArea) { | |
| pPageArea = pDocument->CreateNode(m_pTemplatePageSetRoot->GetPacketType(), | |
| XFA_Element::PageArea); | |
| if (!pPageArea) | |
| return false; | |
| m_pTemplatePageSetRoot->InsertChild(pPageArea, nullptr); | |
| pPageArea->SetFlag(XFA_NodeFlag_Initialized, true); | |
| } | |
| CXFA_Node* pContentArea = | |
| pPageArea->GetChild(0, XFA_Element::ContentArea, false); | |
| if (!pContentArea) { | |
| pContentArea = pDocument->CreateNode(pPageArea->GetPacketType(), | |
| XFA_Element::ContentArea); | |
| if (!pContentArea) | |
| return false; | |
| pPageArea->InsertChild(pContentArea, nullptr); | |
| pContentArea->SetFlag(XFA_NodeFlag_Initialized, true); | |
| pContentArea->JSNode()->SetMeasure( | |
| XFA_Attribute::X, CXFA_Measurement(0.25f, XFA_Unit::In), false); | |
| pContentArea->JSNode()->SetMeasure( | |
| XFA_Attribute::Y, CXFA_Measurement(0.25f, XFA_Unit::In), false); | |
| pContentArea->JSNode()->SetMeasure( | |
| XFA_Attribute::W, CXFA_Measurement(8.0f, XFA_Unit::In), false); | |
| pContentArea->JSNode()->SetMeasure( | |
| XFA_Attribute::H, CXFA_Measurement(10.5f, XFA_Unit::In), false); | |
| } | |
| CXFA_Node* pMedium = pPageArea->GetChild(0, XFA_Element::Medium, false); | |
| if (!pMedium) { | |
| pMedium = | |
| pDocument->CreateNode(pPageArea->GetPacketType(), XFA_Element::Medium); | |
| if (!pContentArea) | |
| return false; | |
| pPageArea->InsertChild(pMedium, nullptr); | |
| pMedium->SetFlag(XFA_NodeFlag_Initialized, true); | |
| pMedium->JSNode()->SetMeasure(XFA_Attribute::Short, | |
| CXFA_Measurement(8.5f, XFA_Unit::In), false); | |
| pMedium->JSNode()->SetMeasure(XFA_Attribute::Long, | |
| CXFA_Measurement(11.0f, XFA_Unit::In), false); | |
| } | |
| return true; | |
| } | |
| bool CXFA_LayoutPageMgr::PrepareFirstPage(CXFA_Node* pRootSubform) { | |
| bool bProBreakBefore = false; | |
| CXFA_Node* pBreakBeforeNode = nullptr; | |
| while (pRootSubform) { | |
| for (CXFA_Node* pBreakNode = | |
| pRootSubform->GetNodeItem(XFA_NODEITEM_FirstChild); | |
| pBreakNode; | |
| pBreakNode = pBreakNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { | |
| XFA_Element eType = pBreakNode->GetElementType(); | |
| if (eType == XFA_Element::BreakBefore || | |
| (eType == XFA_Element::Break && | |
| pBreakNode->JSNode()->GetEnum(XFA_Attribute::Before) != | |
| XFA_AttributeEnum::Auto)) { | |
| bProBreakBefore = true; | |
| pBreakBeforeNode = pBreakNode; | |
| break; | |
| } | |
| } | |
| if (bProBreakBefore) | |
| break; | |
| bProBreakBefore = true; | |
| pRootSubform = pRootSubform->GetFirstChildByClass(XFA_Element::Subform); | |
| while (pRootSubform && | |
| !XFA_ItemLayoutProcessor_IsTakingSpace(pRootSubform)) { | |
| pRootSubform = | |
| pRootSubform->GetNextSameClassSibling(XFA_Element::Subform); | |
| } | |
| } | |
| CXFA_Node* pLeader; | |
| CXFA_Node* pTrailer; | |
| if (pBreakBeforeNode && | |
| ExecuteBreakBeforeOrAfter(pBreakBeforeNode, true, pLeader, pTrailer)) { | |
| m_CurrentContainerRecordIter = m_ProposedContainerRecords.begin(); | |
| return true; | |
| } | |
| return AppendNewPage(true); | |
| } | |
| bool CXFA_LayoutPageMgr::AppendNewPage(bool bFirstTemPage) { | |
| if (m_CurrentContainerRecordIter != GetTailPosition()) | |
| return true; | |
| CXFA_Node* pPageNode = GetNextAvailPageArea(nullptr); | |
| if (!pPageNode) | |
| return false; | |
| if (bFirstTemPage && | |
| m_CurrentContainerRecordIter == m_ProposedContainerRecords.end()) { | |
| m_CurrentContainerRecordIter = m_ProposedContainerRecords.begin(); | |
| } | |
| return !bFirstTemPage || | |
| m_CurrentContainerRecordIter != m_ProposedContainerRecords.end(); | |
| } | |
| void CXFA_LayoutPageMgr::RemoveLayoutRecord(CXFA_ContainerRecord* pNewRecord, | |
| CXFA_ContainerRecord* pPrevRecord) { | |
| if (!pNewRecord || !pPrevRecord) | |
| return; | |
| if (pNewRecord->pCurPageSet != pPrevRecord->pCurPageSet) { | |
| RemoveLayoutItem(pNewRecord->pCurPageSet); | |
| return; | |
| } | |
| if (pNewRecord->pCurPageArea != pPrevRecord->pCurPageArea) { | |
| RemoveLayoutItem(pNewRecord->pCurPageArea); | |
| return; | |
| } | |
| if (pNewRecord->pCurContentArea != pPrevRecord->pCurContentArea) { | |
| RemoveLayoutItem(pNewRecord->pCurContentArea); | |
| return; | |
| } | |
| } | |
| void CXFA_LayoutPageMgr::ReorderPendingLayoutRecordToTail( | |
| CXFA_ContainerRecord* pNewRecord, | |
| CXFA_ContainerRecord* pPrevRecord) { | |
| if (!pNewRecord || !pPrevRecord) | |
| return; | |
| if (pNewRecord->pCurPageSet != pPrevRecord->pCurPageSet) { | |
| ReorderLayoutItemToTail(pNewRecord->pCurPageSet); | |
| return; | |
| } | |
| if (pNewRecord->pCurPageArea != pPrevRecord->pCurPageArea) { | |
| ReorderLayoutItemToTail(pNewRecord->pCurPageArea); | |
| return; | |
| } | |
| if (pNewRecord->pCurContentArea != pPrevRecord->pCurContentArea) { | |
| ReorderLayoutItemToTail(pNewRecord->pCurContentArea); | |
| return; | |
| } | |
| } | |
| void CXFA_LayoutPageMgr::SubmitContentItem( | |
| CXFA_ContentLayoutItem* pContentLayoutItem, | |
| XFA_ItemLayoutProcessorResult eStatus) { | |
| if (pContentLayoutItem) { | |
| GetCurrentContainerRecord()->pCurContentArea->AddChild(pContentLayoutItem); | |
| m_bCreateOverFlowPage = false; | |
| } | |
| if (eStatus != XFA_ItemLayoutProcessorResult::Done) { | |
| if (eStatus == XFA_ItemLayoutProcessorResult::PageFullBreak && | |
| m_CurrentContainerRecordIter == GetTailPosition()) { | |
| AppendNewPage(); | |
| } | |
| m_CurrentContainerRecordIter = GetTailPosition(); | |
| m_pCurPageArea = GetCurrentContainerRecord()->pCurPageArea->m_pFormNode; | |
| } | |
| } | |
| float CXFA_LayoutPageMgr::GetAvailHeight() { | |
| CXFA_ContainerLayoutItem* pLayoutItem = | |
| GetCurrentContainerRecord()->pCurContentArea; | |
| if (!pLayoutItem || !pLayoutItem->m_pFormNode) | |
| return 0.0f; | |
| float fAvailHeight = pLayoutItem->m_pFormNode->JSNode() | |
| ->GetMeasure(XFA_Attribute::H) | |
| .ToUnit(XFA_Unit::Pt); | |
| if (fAvailHeight >= XFA_LAYOUT_FLOAT_PERCISION) | |
| return fAvailHeight; | |
| if (m_CurrentContainerRecordIter == m_ProposedContainerRecords.begin()) | |
| return 0.0f; | |
| return FLT_MAX; | |
| } | |
| bool XFA_LayoutPageMgr_RunBreakTestScript(CXFA_Node* pTestScript) { | |
| WideString wsExpression = pTestScript->JSNode()->GetContent(false); | |
| if (wsExpression.IsEmpty()) | |
| return true; | |
| return pTestScript->GetDocument()->GetNotify()->RunScript( | |
| pTestScript, pTestScript->GetNodeItem(XFA_NODEITEM_Parent, | |
| XFA_ObjectType::ContainerNode)); | |
| } | |
| CXFA_ContainerRecord* CXFA_LayoutPageMgr::CreateContainerRecord( | |
| CXFA_Node* pPageNode, | |
| bool bCreateNew) { | |
| CXFA_ContainerRecord* pNewRecord = new CXFA_ContainerRecord(); | |
| if (m_CurrentContainerRecordIter != m_ProposedContainerRecords.end()) { | |
| if (!IsPageSetRootOrderedOccurrence() || !pPageNode) { | |
| *pNewRecord = *GetCurrentContainerRecord(); | |
| m_ProposedContainerRecords.push_back(pNewRecord); | |
| return pNewRecord; | |
| } | |
| CXFA_Node* pPageSet = pPageNode->GetNodeItem(XFA_NODEITEM_Parent); | |
| if (!bCreateNew) { | |
| if (pPageSet == m_pTemplatePageSetRoot) { | |
| pNewRecord->pCurPageSet = m_pPageSetCurRoot; | |
| } else { | |
| CXFA_ContainerLayoutItem* pParentLayoutItem = | |
| static_cast<CXFA_ContainerLayoutItem*>( | |
| pPageSet->JSNode()->GetLayoutItem()); | |
| if (!pParentLayoutItem) | |
| pParentLayoutItem = m_pPageSetCurRoot; | |
| pNewRecord->pCurPageSet = pParentLayoutItem; | |
| } | |
| } else { | |
| CXFA_ContainerLayoutItem* pParentPageSetLayout = nullptr; | |
| if (pPageSet == GetCurrentContainerRecord()->pCurPageSet->m_pFormNode) { | |
| pParentPageSetLayout = static_cast<CXFA_ContainerLayoutItem*>( | |
| GetCurrentContainerRecord()->pCurPageSet->m_pParent); | |
| } else { | |
| pParentPageSetLayout = static_cast<CXFA_ContainerLayoutItem*>( | |
| pPageSet->GetNodeItem(XFA_NODEITEM_Parent) | |
| ->JSNode() | |
| ->GetLayoutItem()); | |
| } | |
| CXFA_ContainerLayoutItem* pPageSetLayoutItem = | |
| new CXFA_ContainerLayoutItem(pPageSet); | |
| pPageSet->JSNode()->SetLayoutItem(pPageSetLayoutItem); | |
| if (!pParentPageSetLayout) { | |
| CXFA_ContainerLayoutItem* pPrePageSet = m_pPageSetLayoutItemRoot; | |
| while (pPrePageSet->m_pNextSibling) { | |
| pPrePageSet = static_cast<CXFA_ContainerLayoutItem*>( | |
| pPrePageSet->m_pNextSibling); | |
| } | |
| pPrePageSet->m_pNextSibling = pPageSetLayoutItem; | |
| m_pPageSetCurRoot = pPageSetLayoutItem; | |
| } else { | |
| pParentPageSetLayout->AddChild(pPageSetLayoutItem); | |
| } | |
| pNewRecord->pCurPageSet = pPageSetLayoutItem; | |
| } | |
| } else { | |
| if (pPageNode) { | |
| CXFA_Node* pPageSet = pPageNode->GetNodeItem(XFA_NODEITEM_Parent); | |
| if (pPageSet == m_pTemplatePageSetRoot) { | |
| pNewRecord->pCurPageSet = m_pPageSetLayoutItemRoot; | |
| } else { | |
| CXFA_ContainerLayoutItem* pPageSetLayoutItem = | |
| new CXFA_ContainerLayoutItem(pPageSet); | |
| pPageSet->JSNode()->SetLayoutItem(pPageSetLayoutItem); | |
| m_pPageSetLayoutItemRoot->AddChild(pPageSetLayoutItem); | |
| pNewRecord->pCurPageSet = pPageSetLayoutItem; | |
| } | |
| } else { | |
| pNewRecord->pCurPageSet = m_pPageSetLayoutItemRoot; | |
| } | |
| } | |
| m_ProposedContainerRecords.push_back(pNewRecord); | |
| return pNewRecord; | |
| } | |
| void CXFA_LayoutPageMgr::AddPageAreaLayoutItem(CXFA_ContainerRecord* pNewRecord, | |
| CXFA_Node* pNewPageArea) { | |
| CXFA_ContainerLayoutItem* pNewPageAreaLayoutItem = nullptr; | |
| if (pdfium::IndexInBounds(m_PageArray, m_nAvailPages)) { | |
| CXFA_ContainerLayoutItem* pContainerItem = m_PageArray[m_nAvailPages]; | |
| pContainerItem->m_pFormNode = pNewPageArea; | |
| m_nAvailPages++; | |
| pNewPageAreaLayoutItem = pContainerItem; | |
| } else { | |
| CXFA_FFNotify* pNotify = pNewPageArea->GetDocument()->GetNotify(); | |
| auto* pContainerItem = static_cast<CXFA_ContainerLayoutItem*>( | |
| pNotify->OnCreateLayoutItem(pNewPageArea)); | |
| m_PageArray.push_back(pContainerItem); | |
| m_nAvailPages++; | |
| pNotify->OnPageEvent(pContainerItem, XFA_PAGEVIEWEVENT_PostRemoved); | |
| pNewPageAreaLayoutItem = pContainerItem; | |
| } | |
| pNewRecord->pCurPageSet->AddChild(pNewPageAreaLayoutItem); | |
| pNewRecord->pCurPageArea = pNewPageAreaLayoutItem; | |
| pNewRecord->pCurContentArea = nullptr; | |
| } | |
| void CXFA_LayoutPageMgr::AddContentAreaLayoutItem( | |
| CXFA_ContainerRecord* pNewRecord, | |
| CXFA_Node* pContentArea) { | |
| if (!pContentArea) { | |
| pNewRecord->pCurContentArea = nullptr; | |
| return; | |
| } | |
| CXFA_ContainerLayoutItem* pNewContentAreaLayoutItem = | |
| new CXFA_ContainerLayoutItem(pContentArea); | |
| ASSERT(pNewRecord->pCurPageArea); | |
| pNewRecord->pCurPageArea->AddChild(pNewContentAreaLayoutItem); | |
| pNewRecord->pCurContentArea = pNewContentAreaLayoutItem; | |
| } | |
| void CXFA_LayoutPageMgr::FinishPaginatedPageSets() { | |
| CXFA_ContainerLayoutItem* pRootPageSetLayoutItem = m_pPageSetLayoutItemRoot; | |
| for (; pRootPageSetLayoutItem; | |
| pRootPageSetLayoutItem = static_cast<CXFA_ContainerLayoutItem*>( | |
| pRootPageSetLayoutItem->m_pNextSibling)) { | |
| CXFA_NodeIteratorTemplate<CXFA_ContainerLayoutItem, | |
| PageSetContainerLayoutItem> | |
| sIterator(pRootPageSetLayoutItem); | |
| for (CXFA_ContainerLayoutItem* pPageSetLayoutItem = sIterator.GetCurrent(); | |
| pPageSetLayoutItem; pPageSetLayoutItem = sIterator.MoveToNext()) { | |
| XFA_AttributeEnum ePageRelation = | |
| pPageSetLayoutItem->m_pFormNode->JSNode()->GetEnum( | |
| XFA_Attribute::Relation); | |
| switch (ePageRelation) { | |
| case XFA_AttributeEnum::OrderedOccurrence: | |
| default: { ProcessLastPageSet(); } break; | |
| case XFA_AttributeEnum::SimplexPaginated: | |
| case XFA_AttributeEnum::DuplexPaginated: { | |
| CXFA_LayoutItem* pLastPageAreaLayoutItem = nullptr; | |
| int32_t nPageAreaCount = 0; | |
| for (CXFA_LayoutItem* pPageAreaLayoutItem = | |
| pPageSetLayoutItem->m_pFirstChild; | |
| pPageAreaLayoutItem; | |
| pPageAreaLayoutItem = pPageAreaLayoutItem->m_pNextSibling) { | |
| if (pPageAreaLayoutItem->m_pFormNode->GetElementType() != | |
| XFA_Element::PageArea) { | |
| continue; | |
| } | |
| nPageAreaCount++; | |
| pLastPageAreaLayoutItem = pPageAreaLayoutItem; | |
| } | |
| if (!pLastPageAreaLayoutItem) | |
| break; | |
| if (!FindPageAreaFromPageSet_SimplexDuplex( | |
| pPageSetLayoutItem->m_pFormNode, nullptr, nullptr, nullptr, | |
| true, true, | |
| nPageAreaCount == 1 ? XFA_AttributeEnum::Only | |
| : XFA_AttributeEnum::Last) && | |
| (nPageAreaCount == 1 && | |
| !FindPageAreaFromPageSet_SimplexDuplex( | |
| pPageSetLayoutItem->m_pFormNode, nullptr, nullptr, nullptr, | |
| true, true, XFA_AttributeEnum::Last))) { | |
| break; | |
| } | |
| CXFA_Node* pNode = m_pCurPageArea; | |
| XFA_AttributeEnum eCurChoice = | |
| pNode->JSNode()->GetEnum(XFA_Attribute::PagePosition); | |
| if (eCurChoice == XFA_AttributeEnum::Last) { | |
| XFA_AttributeEnum eOddOrEven = | |
| pNode->JSNode()->GetEnum(XFA_Attribute::OddOrEven); | |
| XFA_AttributeEnum eLastChoice = | |
| pLastPageAreaLayoutItem->m_pFormNode->JSNode()->GetEnum( | |
| XFA_Attribute::PagePosition); | |
| if (eLastChoice == XFA_AttributeEnum::First && | |
| (ePageRelation == XFA_AttributeEnum::SimplexPaginated || | |
| eOddOrEven != XFA_AttributeEnum::Odd)) { | |
| CXFA_ContainerRecord* pRecord = CreateContainerRecord(); | |
| AddPageAreaLayoutItem(pRecord, pNode); | |
| break; | |
| } | |
| } | |
| bool bUsable = true; | |
| std::vector<float> rgUsedHeights; | |
| for (CXFA_LayoutItem* pChildLayoutItem = | |
| pLastPageAreaLayoutItem->m_pFirstChild; | |
| pChildLayoutItem; | |
| pChildLayoutItem = pChildLayoutItem->m_pNextSibling) { | |
| if (pChildLayoutItem->m_pFormNode->GetElementType() != | |
| XFA_Element::ContentArea) { | |
| continue; | |
| } | |
| float fUsedHeight = 0; | |
| for (CXFA_LayoutItem* pContentChildLayoutItem = | |
| pChildLayoutItem->m_pFirstChild; | |
| pContentChildLayoutItem; | |
| pContentChildLayoutItem = | |
| pContentChildLayoutItem->m_pNextSibling) { | |
| if (CXFA_ContentLayoutItem* pContent = | |
| pContentChildLayoutItem->AsContentLayoutItem()) { | |
| fUsedHeight += pContent->m_sSize.height; | |
| } | |
| } | |
| rgUsedHeights.push_back(fUsedHeight); | |
| } | |
| int32_t iCurContentAreaIndex = -1; | |
| for (CXFA_Node* pContentAreaNode = | |
| pNode->GetNodeItem(XFA_NODEITEM_FirstChild); | |
| pContentAreaNode; | |
| pContentAreaNode = | |
| pContentAreaNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { | |
| if (pContentAreaNode->GetElementType() != | |
| XFA_Element::ContentArea) { | |
| continue; | |
| } | |
| iCurContentAreaIndex++; | |
| if (rgUsedHeights[iCurContentAreaIndex] > | |
| pContentAreaNode->JSNode() | |
| ->GetMeasure(XFA_Attribute::H) | |
| .ToUnit(XFA_Unit::Pt) + | |
| XFA_LAYOUT_FLOAT_PERCISION) { | |
| bUsable = false; | |
| break; | |
| } | |
| } | |
| if (bUsable) { | |
| CXFA_LayoutItem* pChildLayoutItem = | |
| pLastPageAreaLayoutItem->m_pFirstChild; | |
| CXFA_Node* pContentAreaNode = | |
| pNode->GetNodeItem(XFA_NODEITEM_FirstChild); | |
| pLastPageAreaLayoutItem->m_pFormNode = pNode; | |
| while (pChildLayoutItem && pContentAreaNode) { | |
| if (pChildLayoutItem->m_pFormNode->GetElementType() != | |
| XFA_Element::ContentArea) { | |
| pChildLayoutItem = pChildLayoutItem->m_pNextSibling; | |
| continue; | |
| } | |
| if (pContentAreaNode->GetElementType() != | |
| XFA_Element::ContentArea) { | |
| pContentAreaNode = | |
| pContentAreaNode->GetNodeItem(XFA_NODEITEM_NextSibling); | |
| continue; | |
| } | |
| pChildLayoutItem->m_pFormNode = pContentAreaNode; | |
| pChildLayoutItem = pChildLayoutItem->m_pNextSibling; | |
| pContentAreaNode = | |
| pContentAreaNode->GetNodeItem(XFA_NODEITEM_NextSibling); | |
| } | |
| } else if (pNode->JSNode()->GetEnum(XFA_Attribute::PagePosition) == | |
| XFA_AttributeEnum::Last) { | |
| CXFA_ContainerRecord* pRecord = CreateContainerRecord(); | |
| AddPageAreaLayoutItem(pRecord, pNode); | |
| } | |
| } break; | |
| } | |
| } | |
| } | |
| } | |
| int32_t CXFA_LayoutPageMgr::GetPageCount() const { | |
| return pdfium::CollectionSize<int32_t>(m_PageArray); | |
| } | |
| CXFA_ContainerLayoutItem* CXFA_LayoutPageMgr::GetPage(int32_t index) const { | |
| if (!pdfium::IndexInBounds(m_PageArray, index)) | |
| return nullptr; | |
| return m_PageArray[index]; | |
| } | |
| int32_t CXFA_LayoutPageMgr::GetPageIndex( | |
| const CXFA_ContainerLayoutItem* pPage) const { | |
| auto it = std::find(m_PageArray.begin(), m_PageArray.end(), pPage); | |
| return it != m_PageArray.end() ? it - m_PageArray.begin() : -1; | |
| } | |
| bool CXFA_LayoutPageMgr::RunBreak(XFA_Element eBreakType, | |
| XFA_AttributeEnum eTargetType, | |
| CXFA_Node* pTarget, | |
| bool bStartNew) { | |
| bool bRet = false; | |
| switch (eTargetType) { | |
| case XFA_AttributeEnum::ContentArea: | |
| if (pTarget && pTarget->GetElementType() != XFA_Element::ContentArea) | |
| pTarget = nullptr; | |
| if (!pTarget || | |
| m_CurrentContainerRecordIter == m_ProposedContainerRecords.end() || | |
| pTarget != | |
| GetCurrentContainerRecord()->pCurContentArea->m_pFormNode || | |
| bStartNew) { | |
| CXFA_Node* pPageArea = nullptr; | |
| if (pTarget) | |
| pPageArea = pTarget->GetNodeItem(XFA_NODEITEM_Parent); | |
| pPageArea = GetNextAvailPageArea(pPageArea, pTarget); | |
| bRet = !!pPageArea; | |
| } | |
| break; | |
| case XFA_AttributeEnum::PageArea: | |
| if (pTarget && pTarget->GetElementType() != XFA_Element::PageArea) | |
| pTarget = nullptr; | |
| if (!pTarget || | |
| m_CurrentContainerRecordIter == m_ProposedContainerRecords.end() || | |
| pTarget != GetCurrentContainerRecord()->pCurPageArea->m_pFormNode || | |
| bStartNew) { | |
| CXFA_Node* pPageArea = GetNextAvailPageArea(pTarget, nullptr, true); | |
| bRet = !!pPageArea; | |
| } | |
| break; | |
| case XFA_AttributeEnum::PageOdd: | |
| if (pTarget && pTarget->GetElementType() != XFA_Element::PageArea) | |
| pTarget = nullptr; | |
| break; | |
| case XFA_AttributeEnum::PageEven: | |
| if (pTarget && pTarget->GetElementType() != XFA_Element::PageArea) | |
| pTarget = nullptr; | |
| break; | |
| case XFA_AttributeEnum::Auto: | |
| default: | |
| break; | |
| } | |
| return bRet; | |
| } | |
| bool CXFA_LayoutPageMgr::ExecuteBreakBeforeOrAfter( | |
| CXFA_Node* pCurNode, | |
| bool bBefore, | |
| CXFA_Node*& pBreakLeaderTemplate, | |
| CXFA_Node*& pBreakTrailerTemplate) { | |
| XFA_Element eType = pCurNode->GetElementType(); | |
| switch (eType) { | |
| case XFA_Element::BreakBefore: | |
| case XFA_Element::BreakAfter: { | |
| WideString wsBreakLeader; | |
| WideString wsBreakTrailer; | |
| CXFA_Node* pFormNode = pCurNode->GetNodeItem( | |
| XFA_NODEITEM_Parent, XFA_ObjectType::ContainerNode); | |
| CXFA_Node* pContainer = pFormNode->GetTemplateNode(); | |
| bool bStartNew = | |
| pCurNode->JSNode()->GetInteger(XFA_Attribute::StartNew) != 0; | |
| CXFA_Node* pScript = pCurNode->GetFirstChildByClass(XFA_Element::Script); | |
| if (pScript && !XFA_LayoutPageMgr_RunBreakTestScript(pScript)) | |
| return false; | |
| WideString wsTarget = pCurNode->JSNode()->GetCData(XFA_Attribute::Target); | |
| CXFA_Node* pTarget = | |
| ResolveBreakTarget(m_pTemplatePageSetRoot, true, wsTarget); | |
| wsBreakTrailer = pCurNode->JSNode()->GetCData(XFA_Attribute::Trailer); | |
| wsBreakLeader = pCurNode->JSNode()->GetCData(XFA_Attribute::Leader); | |
| pBreakLeaderTemplate = | |
| ResolveBreakTarget(pContainer, true, wsBreakLeader); | |
| pBreakTrailerTemplate = | |
| ResolveBreakTarget(pContainer, true, wsBreakTrailer); | |
| if (RunBreak(eType, | |
| pCurNode->JSNode()->GetEnum(XFA_Attribute::TargetType), | |
| pTarget, bStartNew)) { | |
| return true; | |
| } | |
| if (!m_ProposedContainerRecords.empty() && | |
| m_CurrentContainerRecordIter == m_ProposedContainerRecords.begin() && | |
| eType == XFA_Element::BreakBefore) { | |
| CXFA_Node* pParentNode = pFormNode->GetNodeItem( | |
| XFA_NODEITEM_Parent, XFA_ObjectType::ContainerNode); | |
| if (!pParentNode || | |
| pFormNode != | |
| pParentNode->GetNodeItem(XFA_NODEITEM_FirstChild, | |
| XFA_ObjectType::ContainerNode)) { | |
| break; | |
| } | |
| pParentNode = pParentNode->GetNodeItem(XFA_NODEITEM_Parent); | |
| if (!pParentNode || | |
| pParentNode->GetElementType() != XFA_Element::Form) { | |
| break; | |
| } | |
| return true; | |
| } | |
| break; | |
| } | |
| case XFA_Element::Break: { | |
| bool bStartNew = | |
| pCurNode->JSNode()->GetInteger(XFA_Attribute::StartNew) != 0; | |
| WideString wsTarget = pCurNode->JSNode()->GetCData( | |
| bBefore ? XFA_Attribute::BeforeTarget : XFA_Attribute::AfterTarget); | |
| CXFA_Node* pTarget = | |
| ResolveBreakTarget(m_pTemplatePageSetRoot, true, wsTarget); | |
| if (RunBreak(bBefore ? XFA_Element::BreakBefore : XFA_Element::BreakAfter, | |
| pCurNode->JSNode()->GetEnum(bBefore ? XFA_Attribute::Before | |
| : XFA_Attribute::After), | |
| pTarget, bStartNew)) { | |
| return true; | |
| } | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| return false; | |
| } | |
| bool CXFA_LayoutPageMgr::ProcessBreakBeforeOrAfter( | |
| CXFA_Node* pBreakNode, | |
| bool bBefore, | |
| CXFA_Node*& pBreakLeaderNode, | |
| CXFA_Node*& pBreakTrailerNode, | |
| bool& bCreatePage) { | |
| CXFA_Node* pLeaderTemplate = nullptr; | |
| CXFA_Node* pTrailerTemplate = nullptr; | |
| CXFA_Node* pFormNode = pBreakNode->GetNodeItem(XFA_NODEITEM_Parent, | |
| XFA_ObjectType::ContainerNode); | |
| if (XFA_ItemLayoutProcessor_IsTakingSpace(pFormNode)) { | |
| bCreatePage = ExecuteBreakBeforeOrAfter(pBreakNode, bBefore, | |
| pLeaderTemplate, pTrailerTemplate); | |
| CXFA_Document* pDocument = pBreakNode->GetDocument(); | |
| CXFA_Node* pDataScope = nullptr; | |
| pFormNode = pFormNode->GetNodeItem(XFA_NODEITEM_Parent, | |
| XFA_ObjectType::ContainerNode); | |
| if (pLeaderTemplate) { | |
| if (!pDataScope) | |
| pDataScope = XFA_DataMerge_FindDataScope(pFormNode); | |
| pBreakLeaderNode = pDocument->DataMerge_CopyContainer( | |
| pLeaderTemplate, pFormNode, pDataScope, true, true, true); | |
| pDocument->DataMerge_UpdateBindingRelations(pBreakLeaderNode); | |
| SetLayoutGeneratedNodeFlag(pBreakLeaderNode); | |
| } | |
| if (pTrailerTemplate) { | |
| if (!pDataScope) | |
| pDataScope = XFA_DataMerge_FindDataScope(pFormNode); | |
| pBreakTrailerNode = pDocument->DataMerge_CopyContainer( | |
| pTrailerTemplate, pFormNode, pDataScope, true, true, true); | |
| pDocument->DataMerge_UpdateBindingRelations(pBreakTrailerNode); | |
| SetLayoutGeneratedNodeFlag(pBreakTrailerNode); | |
| } | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool CXFA_LayoutPageMgr::ProcessBookendLeaderOrTrailer( | |
| CXFA_Node* pBookendNode, | |
| bool bLeader, | |
| CXFA_Node*& pBookendAppendNode) { | |
| CXFA_Node* pLeaderTemplate = nullptr; | |
| CXFA_Node* pFormNode = pBookendNode->GetNodeItem( | |
| XFA_NODEITEM_Parent, XFA_ObjectType::ContainerNode); | |
| if (ResolveBookendLeaderOrTrailer(pBookendNode, bLeader, pLeaderTemplate)) { | |
| CXFA_Document* pDocument = pBookendNode->GetDocument(); | |
| CXFA_Node* pDataScope = nullptr; | |
| if (pLeaderTemplate) { | |
| if (!pDataScope) | |
| pDataScope = XFA_DataMerge_FindDataScope(pFormNode); | |
| pBookendAppendNode = pDocument->DataMerge_CopyContainer( | |
| pLeaderTemplate, pFormNode, pDataScope, true, true, true); | |
| pDocument->DataMerge_UpdateBindingRelations(pBookendAppendNode); | |
| SetLayoutGeneratedNodeFlag(pBookendAppendNode); | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| CXFA_Node* CXFA_LayoutPageMgr::BreakOverflow(CXFA_Node* pOverflowNode, | |
| CXFA_Node*& pLeaderTemplate, | |
| CXFA_Node*& pTrailerTemplate, | |
| bool bCreatePage) { | |
| CXFA_Node* pContainer = | |
| pOverflowNode | |
| ->GetNodeItem(XFA_NODEITEM_Parent, XFA_ObjectType::ContainerNode) | |
| ->GetTemplateNode(); | |
| if (pOverflowNode->GetElementType() == XFA_Element::Break) { | |
| WideString wsOverflowLeader = | |
| pOverflowNode->JSNode()->GetCData(XFA_Attribute::OverflowLeader); | |
| WideString wsOverflowTarget = | |
| pOverflowNode->JSNode()->GetCData(XFA_Attribute::OverflowTarget); | |
| WideString wsOverflowTrailer = | |
| pOverflowNode->JSNode()->GetCData(XFA_Attribute::OverflowTrailer); | |
| if (wsOverflowTarget.IsEmpty() && wsOverflowLeader.IsEmpty() && | |
| wsOverflowTrailer.IsEmpty()) { | |
| return nullptr; | |
| } | |
| if (!wsOverflowTarget.IsEmpty() && bCreatePage && !m_bCreateOverFlowPage) { | |
| CXFA_Node* pTarget = | |
| ResolveBreakTarget(m_pTemplatePageSetRoot, true, wsOverflowTarget); | |
| if (pTarget) { | |
| m_bCreateOverFlowPage = true; | |
| switch (pTarget->GetElementType()) { | |
| case XFA_Element::PageArea: | |
| RunBreak(XFA_Element::Overflow, XFA_AttributeEnum::PageArea, | |
| pTarget, true); | |
| break; | |
| case XFA_Element::ContentArea: | |
| RunBreak(XFA_Element::Overflow, XFA_AttributeEnum::ContentArea, | |
| pTarget, true); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| } | |
| if (!bCreatePage) { | |
| pLeaderTemplate = ResolveBreakTarget(pContainer, true, wsOverflowLeader); | |
| pTrailerTemplate = | |
| ResolveBreakTarget(pContainer, true, wsOverflowTrailer); | |
| } | |
| return pOverflowNode; | |
| } | |
| if (pOverflowNode->GetElementType() != XFA_Element::Overflow) | |
| return nullptr; | |
| WideString wsOverflowTarget = | |
| pOverflowNode->JSNode()->GetCData(XFA_Attribute::Target); | |
| if (!wsOverflowTarget.IsEmpty() && bCreatePage && !m_bCreateOverFlowPage) { | |
| CXFA_Node* pTarget = | |
| ResolveBreakTarget(m_pTemplatePageSetRoot, true, wsOverflowTarget); | |
| if (pTarget) { | |
| m_bCreateOverFlowPage = true; | |
| switch (pTarget->GetElementType()) { | |
| case XFA_Element::PageArea: | |
| RunBreak(XFA_Element::Overflow, XFA_AttributeEnum::PageArea, pTarget, | |
| true); | |
| break; | |
| case XFA_Element::ContentArea: | |
| RunBreak(XFA_Element::Overflow, XFA_AttributeEnum::ContentArea, | |
| pTarget, true); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| } | |
| if (!bCreatePage) { | |
| WideString wsLeader = | |
| pOverflowNode->JSNode()->GetCData(XFA_Attribute::Leader); | |
| WideString wsTrailer = | |
| pOverflowNode->JSNode()->GetCData(XFA_Attribute::Trailer); | |
| pLeaderTemplate = ResolveBreakTarget(pContainer, true, wsLeader); | |
| pTrailerTemplate = ResolveBreakTarget(pContainer, true, wsTrailer); | |
| } | |
| return pOverflowNode; | |
| } | |
| bool CXFA_LayoutPageMgr::ProcessOverflow(CXFA_Node* pFormNode, | |
| CXFA_Node*& pLeaderNode, | |
| CXFA_Node*& pTrailerNode, | |
| bool bDataMerge, | |
| bool bCreatePage) { | |
| if (!pFormNode) | |
| return false; | |
| CXFA_Node* pLeaderTemplate = nullptr; | |
| CXFA_Node* pTrailerTemplate = nullptr; | |
| bool bIsOverflowNode = false; | |
| if (pFormNode->GetElementType() == XFA_Element::Overflow || | |
| pFormNode->GetElementType() == XFA_Element::Break) { | |
| bIsOverflowNode = true; | |
| } | |
| for (CXFA_Node* pCurNode = | |
| bIsOverflowNode ? pFormNode | |
| : pFormNode->GetNodeItem(XFA_NODEITEM_FirstChild); | |
| pCurNode; pCurNode = pCurNode->GetNodeItem((XFA_NODEITEM_NextSibling))) { | |
| if (BreakOverflow(pCurNode, pLeaderTemplate, pTrailerTemplate, | |
| bCreatePage)) { | |
| if (bIsOverflowNode) | |
| pFormNode = pCurNode->GetNodeItem(XFA_NODEITEM_Parent); | |
| CXFA_Document* pDocument = pCurNode->GetDocument(); | |
| CXFA_Node* pDataScope = nullptr; | |
| if (pLeaderTemplate) { | |
| if (!pDataScope) | |
| pDataScope = XFA_DataMerge_FindDataScope(pFormNode); | |
| pLeaderNode = pDocument->DataMerge_CopyContainer( | |
| pLeaderTemplate, pFormNode, pDataScope, true, true, true); | |
| pDocument->DataMerge_UpdateBindingRelations(pLeaderNode); | |
| SetLayoutGeneratedNodeFlag(pLeaderNode); | |
| } | |
| if (pTrailerTemplate) { | |
| if (!pDataScope) | |
| pDataScope = XFA_DataMerge_FindDataScope(pFormNode); | |
| pTrailerNode = pDocument->DataMerge_CopyContainer( | |
| pTrailerTemplate, pFormNode, pDataScope, true, true, true); | |
| pDocument->DataMerge_UpdateBindingRelations(pTrailerNode); | |
| SetLayoutGeneratedNodeFlag(pTrailerNode); | |
| } | |
| return true; | |
| } | |
| if (bIsOverflowNode) { | |
| break; | |
| } | |
| } | |
| return false; | |
| } | |
| bool CXFA_LayoutPageMgr::ResolveBookendLeaderOrTrailer( | |
| CXFA_Node* pBookendNode, | |
| bool bLeader, | |
| CXFA_Node*& pBookendAppendTemplate) { | |
| CXFA_Node* pContainer = | |
| pBookendNode | |
| ->GetNodeItem(XFA_NODEITEM_Parent, XFA_ObjectType::ContainerNode) | |
| ->GetTemplateNode(); | |
| if (pBookendNode->GetElementType() == XFA_Element::Break) { | |
| WideString leader = pBookendNode->JSNode()->GetCData( | |
| bLeader ? XFA_Attribute::BookendLeader : XFA_Attribute::BookendTrailer); | |
| if (!leader.IsEmpty()) { | |
| pBookendAppendTemplate = ResolveBreakTarget(pContainer, false, leader); | |
| return true; | |
| } | |
| return false; | |
| } | |
| if (pBookendNode->GetElementType() == XFA_Element::Bookend) { | |
| WideString leader = pBookendNode->JSNode()->GetCData( | |
| bLeader ? XFA_Attribute::Leader : XFA_Attribute::Trailer); | |
| pBookendAppendTemplate = ResolveBreakTarget(pContainer, true, leader); | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool CXFA_LayoutPageMgr::FindPageAreaFromPageSet(CXFA_Node* pPageSet, | |
| CXFA_Node* pStartChild, | |
| CXFA_Node* pTargetPageArea, | |
| CXFA_Node* pTargetContentArea, | |
| bool bNewPage, | |
| bool bQuery) { | |
| if (!pPageSet && !pStartChild) | |
| return false; | |
| if (IsPageSetRootOrderedOccurrence()) { | |
| return FindPageAreaFromPageSet_Ordered(pPageSet, pStartChild, | |
| pTargetPageArea, pTargetContentArea, | |
| bNewPage, bQuery); | |
| } | |
| XFA_AttributeEnum ePreferredPosition = | |
| m_CurrentContainerRecordIter != m_ProposedContainerRecords.end() | |
| ? XFA_AttributeEnum::Rest | |
| : XFA_AttributeEnum::First; | |
| return FindPageAreaFromPageSet_SimplexDuplex( | |
| pPageSet, pStartChild, pTargetPageArea, pTargetContentArea, bNewPage, | |
| bQuery, ePreferredPosition); | |
| } | |
| bool CXFA_LayoutPageMgr::FindPageAreaFromPageSet_Ordered( | |
| CXFA_Node* pPageSet, | |
| CXFA_Node* pStartChild, | |
| CXFA_Node* pTargetPageArea, | |
| CXFA_Node* pTargetContentArea, | |
| bool bNewPage, | |
| bool bQuery) { | |
| int32_t iPageSetCount = 0; | |
| if (!pStartChild && !bQuery) { | |
| auto it = m_pPageSetMap.find(pPageSet); | |
| if (it != m_pPageSetMap.end()) | |
| iPageSetCount = it->second; | |
| int32_t iMax = -1; | |
| CXFA_Node* pOccurNode = pPageSet->GetFirstChildByClass(XFA_Element::Occur); | |
| if (pOccurNode) { | |
| pdfium::Optional<int32_t> ret = | |
| pOccurNode->JSNode()->TryInteger(XFA_Attribute::Max, false); | |
| if (ret) | |
| iMax = *ret; | |
| } | |
| if (iMax >= 0 && iMax <= iPageSetCount) | |
| return false; | |
| } | |
| bool bRes = false; | |
| CXFA_Node* pCurrentNode = | |
| pStartChild ? pStartChild->GetNodeItem(XFA_NODEITEM_NextSibling) | |
| : pPageSet->GetNodeItem(XFA_NODEITEM_FirstChild); | |
| for (; pCurrentNode; | |
| pCurrentNode = pCurrentNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { | |
| if (pCurrentNode->GetElementType() == XFA_Element::PageArea) { | |
| if ((pTargetPageArea == pCurrentNode || !pTargetPageArea)) { | |
| if (!pCurrentNode->GetFirstChildByClass(XFA_Element::ContentArea)) { | |
| if (pTargetPageArea == pCurrentNode) { | |
| CreateMinPageRecord(pCurrentNode, true); | |
| pTargetPageArea = nullptr; | |
| } | |
| continue; | |
| } | |
| if (!bQuery) { | |
| CXFA_ContainerRecord* pNewRecord = | |
| CreateContainerRecord(pCurrentNode, !pStartChild); | |
| AddPageAreaLayoutItem(pNewRecord, pCurrentNode); | |
| if (!pTargetContentArea) { | |
| pTargetContentArea = | |
| pCurrentNode->GetFirstChildByClass(XFA_Element::ContentArea); | |
| } | |
| AddContentAreaLayoutItem(pNewRecord, pTargetContentArea); | |
| } | |
| m_pCurPageArea = pCurrentNode; | |
| m_nCurPageCount = 1; | |
| bRes = true; | |
| break; | |
| } | |
| if (!bQuery) | |
| CreateMinPageRecord(pCurrentNode, false); | |
| } else if (pCurrentNode->GetElementType() == XFA_Element::PageSet) { | |
| if (FindPageAreaFromPageSet_Ordered(pCurrentNode, nullptr, | |
| pTargetPageArea, pTargetContentArea, | |
| bNewPage, bQuery)) { | |
| bRes = true; | |
| break; | |
| } | |
| if (!bQuery) | |
| CreateMinPageSetRecord(pCurrentNode, true); | |
| } | |
| } | |
| if (!pStartChild && bRes && !bQuery) | |
| m_pPageSetMap[pPageSet] = ++iPageSetCount; | |
| return bRes; | |
| } | |
| bool CXFA_LayoutPageMgr::FindPageAreaFromPageSet_SimplexDuplex( | |
| CXFA_Node* pPageSet, | |
| CXFA_Node* pStartChild, | |
| CXFA_Node* pTargetPageArea, | |
| CXFA_Node* pTargetContentArea, | |
| bool bNewPage, | |
| bool bQuery, | |
| XFA_AttributeEnum ePreferredPosition) { | |
| const XFA_AttributeEnum eFallbackPosition = XFA_AttributeEnum::Any; | |
| CXFA_Node* pPreferredPageArea = nullptr; | |
| CXFA_Node* pFallbackPageArea = nullptr; | |
| CXFA_Node* pCurrentNode = nullptr; | |
| if (!pStartChild || pStartChild->GetElementType() == XFA_Element::PageArea) | |
| pCurrentNode = pPageSet->GetNodeItem(XFA_NODEITEM_FirstChild); | |
| else | |
| pCurrentNode = pStartChild->GetNodeItem(XFA_NODEITEM_NextSibling); | |
| for (; pCurrentNode; | |
| pCurrentNode = pCurrentNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { | |
| if (pCurrentNode->GetElementType() == XFA_Element::PageArea) { | |
| if (!MatchPageAreaOddOrEven(pCurrentNode)) | |
| continue; | |
| XFA_AttributeEnum eCurPagePosition = | |
| pCurrentNode->JSNode()->GetEnum(XFA_Attribute::PagePosition); | |
| if (ePreferredPosition == XFA_AttributeEnum::Last) { | |
| if (eCurPagePosition != ePreferredPosition) | |
| continue; | |
| if (m_ePageSetMode == XFA_AttributeEnum::SimplexPaginated || | |
| pCurrentNode->JSNode()->GetEnum(XFA_Attribute::OddOrEven) == | |
| XFA_AttributeEnum::Any) { | |
| pPreferredPageArea = pCurrentNode; | |
| break; | |
| } | |
| CXFA_ContainerRecord* pNewRecord = CreateContainerRecord(); | |
| AddPageAreaLayoutItem(pNewRecord, pCurrentNode); | |
| AddContentAreaLayoutItem(pNewRecord, pCurrentNode->GetFirstChildByClass( | |
| XFA_Element::ContentArea)); | |
| pPreferredPageArea = pCurrentNode; | |
| return false; | |
| } | |
| if (ePreferredPosition == XFA_AttributeEnum::Only) { | |
| if (eCurPagePosition != ePreferredPosition) | |
| continue; | |
| if (m_ePageSetMode != XFA_AttributeEnum::DuplexPaginated || | |
| pCurrentNode->JSNode()->GetEnum(XFA_Attribute::OddOrEven) == | |
| XFA_AttributeEnum::Any) { | |
| pPreferredPageArea = pCurrentNode; | |
| break; | |
| } | |
| return false; | |
| } | |
| if ((pTargetPageArea == pCurrentNode || !pTargetPageArea)) { | |
| if (!pCurrentNode->GetFirstChildByClass(XFA_Element::ContentArea)) { | |
| if (pTargetPageArea == pCurrentNode) { | |
| CXFA_ContainerRecord* pNewRecord = CreateContainerRecord(); | |
| AddPageAreaLayoutItem(pNewRecord, pCurrentNode); | |
| pTargetPageArea = nullptr; | |
| } | |
| continue; | |
| } | |
| if ((ePreferredPosition == XFA_AttributeEnum::Rest && | |
| eCurPagePosition == XFA_AttributeEnum::Any) || | |
| eCurPagePosition == ePreferredPosition) { | |
| pPreferredPageArea = pCurrentNode; | |
| break; | |
| } | |
| if (eCurPagePosition == eFallbackPosition && !pFallbackPageArea) { | |
| pFallbackPageArea = pCurrentNode; | |
| } | |
| } else if (pTargetPageArea && !MatchPageAreaOddOrEven(pTargetPageArea)) { | |
| CXFA_ContainerRecord* pNewRecord = CreateContainerRecord(); | |
| AddPageAreaLayoutItem(pNewRecord, pCurrentNode); | |
| AddContentAreaLayoutItem(pNewRecord, pCurrentNode->GetFirstChildByClass( | |
| XFA_Element::ContentArea)); | |
| } | |
| } else if (pCurrentNode->GetElementType() == XFA_Element::PageSet) { | |
| if (FindPageAreaFromPageSet_SimplexDuplex( | |
| pCurrentNode, nullptr, pTargetPageArea, pTargetContentArea, | |
| bNewPage, bQuery, ePreferredPosition)) { | |
| break; | |
| } | |
| } | |
| } | |
| CXFA_Node* pCurPageArea = nullptr; | |
| if (pPreferredPageArea) | |
| pCurPageArea = pPreferredPageArea; | |
| else if (pFallbackPageArea) | |
| pCurPageArea = pFallbackPageArea; | |
| if (!pCurPageArea) | |
| return false; | |
| if (!bQuery) { | |
| CXFA_ContainerRecord* pNewRecord = CreateContainerRecord(); | |
| AddPageAreaLayoutItem(pNewRecord, pCurPageArea); | |
| if (!pTargetContentArea) { | |
| pTargetContentArea = | |
| pCurPageArea->GetFirstChildByClass(XFA_Element::ContentArea); | |
| } | |
| AddContentAreaLayoutItem(pNewRecord, pTargetContentArea); | |
| } | |
| m_pCurPageArea = pCurPageArea; | |
| return true; | |
| } | |
| bool CXFA_LayoutPageMgr::MatchPageAreaOddOrEven(CXFA_Node* pPageArea) { | |
| if (m_ePageSetMode != XFA_AttributeEnum::DuplexPaginated) | |
| return true; | |
| pdfium::Optional<XFA_AttributeEnum> ret = | |
| pPageArea->JSNode()->TryEnum(XFA_Attribute::OddOrEven, true); | |
| if (!ret || *ret == XFA_AttributeEnum::Any) | |
| return true; | |
| int32_t iPageLast = GetPageCount() % 2; | |
| return *ret == XFA_AttributeEnum::Odd ? iPageLast == 0 : iPageLast == 1; | |
| } | |
| CXFA_Node* CXFA_LayoutPageMgr::GetNextAvailPageArea( | |
| CXFA_Node* pTargetPageArea, | |
| CXFA_Node* pTargetContentArea, | |
| bool bNewPage, | |
| bool bQuery) { | |
| if (!m_pCurPageArea) { | |
| FindPageAreaFromPageSet(m_pTemplatePageSetRoot, nullptr, pTargetPageArea, | |
| pTargetContentArea, bNewPage, bQuery); | |
| ASSERT(m_pCurPageArea); | |
| return m_pCurPageArea; | |
| } | |
| if (!pTargetPageArea || pTargetPageArea == m_pCurPageArea) { | |
| if (!bNewPage && GetNextContentArea(pTargetContentArea)) | |
| return m_pCurPageArea; | |
| if (IsPageSetRootOrderedOccurrence()) { | |
| int32_t iMax = -1; | |
| CXFA_Node* pOccurNode = | |
| m_pCurPageArea->GetFirstChildByClass(XFA_Element::Occur); | |
| if (pOccurNode) { | |
| pdfium::Optional<int32_t> ret = | |
| pOccurNode->JSNode()->TryInteger(XFA_Attribute::Max, false); | |
| if (ret) | |
| iMax = *ret; | |
| } | |
| if ((iMax < 0 || m_nCurPageCount < iMax)) { | |
| if (!bQuery) { | |
| CXFA_ContainerRecord* pNewRecord = | |
| CreateContainerRecord(m_pCurPageArea); | |
| AddPageAreaLayoutItem(pNewRecord, m_pCurPageArea); | |
| if (!pTargetContentArea) { | |
| pTargetContentArea = | |
| m_pCurPageArea->GetFirstChildByClass(XFA_Element::ContentArea); | |
| } | |
| AddContentAreaLayoutItem(pNewRecord, pTargetContentArea); | |
| } | |
| m_nCurPageCount++; | |
| return m_pCurPageArea; | |
| } | |
| } | |
| } | |
| if (!bQuery && IsPageSetRootOrderedOccurrence()) | |
| CreateMinPageRecord(m_pCurPageArea, false, true); | |
| if (FindPageAreaFromPageSet(m_pCurPageArea->GetNodeItem(XFA_NODEITEM_Parent), | |
| m_pCurPageArea, pTargetPageArea, | |
| pTargetContentArea, bNewPage, bQuery)) { | |
| return m_pCurPageArea; | |
| } | |
| CXFA_Node* pPageSet = m_pCurPageArea->GetNodeItem(XFA_NODEITEM_Parent); | |
| while (true) { | |
| if (FindPageAreaFromPageSet(pPageSet, nullptr, pTargetPageArea, | |
| pTargetContentArea, bNewPage, bQuery)) { | |
| return m_pCurPageArea; | |
| } | |
| if (!bQuery && IsPageSetRootOrderedOccurrence()) | |
| CreateMinPageSetRecord(pPageSet); | |
| if (FindPageAreaFromPageSet(nullptr, pPageSet, pTargetPageArea, | |
| pTargetContentArea, bNewPage, bQuery)) { | |
| return m_pCurPageArea; | |
| } | |
| if (pPageSet == m_pTemplatePageSetRoot) | |
| break; | |
| pPageSet = pPageSet->GetNodeItem(XFA_NODEITEM_Parent); | |
| } | |
| return nullptr; | |
| } | |
| bool CXFA_LayoutPageMgr::GetNextContentArea(CXFA_Node* pContentArea) { | |
| CXFA_Node* pCurContentNode = | |
| GetCurrentContainerRecord()->pCurContentArea->m_pFormNode; | |
| if (!pContentArea) { | |
| pContentArea = | |
| pCurContentNode->GetNextSameClassSibling(XFA_Element::ContentArea); | |
| if (!pContentArea) | |
| return false; | |
| } else { | |
| if (pContentArea->GetNodeItem(XFA_NODEITEM_Parent) != m_pCurPageArea) | |
| return false; | |
| CXFA_ContainerLayoutItem* pContentAreaLayout = nullptr; | |
| if (!CheckContentAreaNotUsed(GetCurrentContainerRecord()->pCurPageArea, | |
| pContentArea, pContentAreaLayout)) { | |
| return false; | |
| } | |
| if (pContentAreaLayout) { | |
| if (pContentAreaLayout->m_pFormNode != pCurContentNode) { | |
| CXFA_ContainerRecord* pNewRecord = CreateContainerRecord(); | |
| pNewRecord->pCurContentArea = pContentAreaLayout; | |
| return true; | |
| } | |
| return false; | |
| } | |
| } | |
| CXFA_ContainerRecord* pNewRecord = CreateContainerRecord(); | |
| AddContentAreaLayoutItem(pNewRecord, pContentArea); | |
| return true; | |
| } | |
| void CXFA_LayoutPageMgr::InitPageSetMap() { | |
| if (!IsPageSetRootOrderedOccurrence()) | |
| return; | |
| CXFA_NodeIterator sIterator(m_pTemplatePageSetRoot); | |
| for (CXFA_Node* pPageSetNode = sIterator.GetCurrent(); pPageSetNode; | |
| pPageSetNode = sIterator.MoveToNext()) { | |
| if (pPageSetNode->GetElementType() == XFA_Element::PageSet) { | |
| XFA_AttributeEnum eRelation = | |
| pPageSetNode->JSNode()->GetEnum(XFA_Attribute::Relation); | |
| if (eRelation == XFA_AttributeEnum::OrderedOccurrence) | |
| m_pPageSetMap[pPageSetNode] = 0; | |
| } | |
| } | |
| } | |
| int32_t CXFA_LayoutPageMgr::CreateMinPageRecord(CXFA_Node* pPageArea, | |
| bool bTargetPageArea, | |
| bool bCreateLast) { | |
| if (!pPageArea) | |
| return 0; | |
| int32_t iMin = 0; | |
| pdfium::Optional<int32_t> ret; | |
| CXFA_Node* pOccurNode = pPageArea->GetFirstChildByClass(XFA_Element::Occur); | |
| if (pOccurNode) { | |
| ret = pOccurNode->JSNode()->TryInteger(XFA_Attribute::Min, false); | |
| if (ret) | |
| iMin = *ret; | |
| } | |
| if (!ret && !bTargetPageArea) | |
| return iMin; | |
| CXFA_Node* pContentArea = | |
| pPageArea->GetFirstChildByClass(XFA_Element::ContentArea); | |
| if (iMin < 1 && bTargetPageArea && !pContentArea) | |
| iMin = 1; | |
| int32_t i = 0; | |
| if (bCreateLast) | |
| i = m_nCurPageCount; | |
| for (; i < iMin; i++) { | |
| CXFA_ContainerRecord* pNewRecord = CreateContainerRecord(); | |
| AddPageAreaLayoutItem(pNewRecord, pPageArea); | |
| AddContentAreaLayoutItem(pNewRecord, pContentArea); | |
| } | |
| return iMin; | |
| } | |
| void CXFA_LayoutPageMgr::CreateMinPageSetRecord(CXFA_Node* pPageSet, | |
| bool bCreateAll) { | |
| if (!pPageSet) | |
| return; | |
| auto it = m_pPageSetMap.find(pPageSet); | |
| if (it == m_pPageSetMap.end()) | |
| return; | |
| int32_t iCurSetCount = it->second; | |
| if (bCreateAll) | |
| iCurSetCount = 0; | |
| CXFA_Node* pOccurNode = pPageSet->GetFirstChildByClass(XFA_Element::Occur); | |
| if (!pOccurNode) | |
| return; | |
| pdfium::Optional<int32_t> iMin = | |
| pOccurNode->JSNode()->TryInteger(XFA_Attribute::Min, false); | |
| if (!iMin || iCurSetCount >= *iMin) | |
| return; | |
| for (int32_t i = 0; i < *iMin - iCurSetCount; i++) { | |
| for (CXFA_Node* node = pPageSet->GetNodeItem(XFA_NODEITEM_FirstChild); node; | |
| node = node->GetNodeItem(XFA_NODEITEM_NextSibling)) { | |
| if (node->GetElementType() == XFA_Element::PageArea) | |
| CreateMinPageRecord(node, false); | |
| else if (node->GetElementType() == XFA_Element::PageSet) | |
| CreateMinPageSetRecord(node, true); | |
| } | |
| } | |
| m_pPageSetMap[pPageSet] = *iMin; | |
| } | |
| void CXFA_LayoutPageMgr::CreateNextMinRecord(CXFA_Node* pRecordNode) { | |
| if (!pRecordNode) | |
| return; | |
| for (CXFA_Node* pCurrentNode = | |
| pRecordNode->GetNodeItem(XFA_NODEITEM_NextSibling); | |
| pCurrentNode; | |
| pCurrentNode = pCurrentNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { | |
| if (pCurrentNode->GetElementType() == XFA_Element::PageArea) | |
| CreateMinPageRecord(pCurrentNode, false); | |
| else if (pCurrentNode->GetElementType() == XFA_Element::PageSet) | |
| CreateMinPageSetRecord(pCurrentNode, true); | |
| } | |
| } | |
| void CXFA_LayoutPageMgr::ProcessLastPageSet() { | |
| CreateMinPageRecord(m_pCurPageArea, false, true); | |
| CreateNextMinRecord(m_pCurPageArea); | |
| CXFA_Node* pPageSet = m_pCurPageArea->GetNodeItem(XFA_NODEITEM_Parent); | |
| while (true) { | |
| CreateMinPageSetRecord(pPageSet); | |
| if (pPageSet == m_pTemplatePageSetRoot) | |
| break; | |
| CreateNextMinRecord(pPageSet); | |
| pPageSet = pPageSet->GetNodeItem(XFA_NODEITEM_Parent); | |
| } | |
| } | |
| bool CXFA_LayoutPageMgr::GetNextAvailContentHeight(float fChildHeight) { | |
| CXFA_Node* pCurContentNode = | |
| GetCurrentContainerRecord()->pCurContentArea->m_pFormNode; | |
| if (!pCurContentNode) | |
| return false; | |
| pCurContentNode = | |
| pCurContentNode->GetNextSameClassSibling(XFA_Element::ContentArea); | |
| if (pCurContentNode) { | |
| float fNextContentHeight = pCurContentNode->JSNode() | |
| ->GetMeasure(XFA_Attribute::H) | |
| .ToUnit(XFA_Unit::Pt); | |
| return fNextContentHeight > fChildHeight; | |
| } | |
| CXFA_Node* pPageNode = GetCurrentContainerRecord()->pCurPageArea->m_pFormNode; | |
| CXFA_Node* pOccurNode = pPageNode->GetFirstChildByClass(XFA_Element::Occur); | |
| int32_t iMax = 0; | |
| pdfium::Optional<int32_t> ret; | |
| if (pOccurNode) { | |
| ret = pOccurNode->JSNode()->TryInteger(XFA_Attribute::Max, false); | |
| if (ret) | |
| iMax = *ret; | |
| } | |
| if (ret) { | |
| if (m_nCurPageCount == iMax) { | |
| CXFA_Node* pSrcPage = m_pCurPageArea; | |
| int32_t nSrcPageCount = m_nCurPageCount; | |
| auto psSrcIter = GetTailPosition(); | |
| CXFA_Node* pNextPage = | |
| GetNextAvailPageArea(nullptr, nullptr, false, true); | |
| m_pCurPageArea = pSrcPage; | |
| m_nCurPageCount = nSrcPageCount; | |
| CXFA_ContainerRecord* pPrevRecord = *psSrcIter++; | |
| while (psSrcIter != m_ProposedContainerRecords.end()) { | |
| auto psSaveIter = psSrcIter; | |
| CXFA_ContainerRecord* pInsertRecord = *psSrcIter++; | |
| RemoveLayoutRecord(pInsertRecord, pPrevRecord); | |
| delete pInsertRecord; | |
| m_ProposedContainerRecords.erase(psSaveIter); | |
| } | |
| if (pNextPage) { | |
| CXFA_Node* pContentArea = | |
| pNextPage->GetFirstChildByClass(XFA_Element::ContentArea); | |
| if (pContentArea) { | |
| float fNextContentHeight = pContentArea->JSNode() | |
| ->GetMeasure(XFA_Attribute::H) | |
| .ToUnit(XFA_Unit::Pt); | |
| if (fNextContentHeight > fChildHeight) | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| } | |
| CXFA_Node* pContentArea = | |
| pPageNode->GetFirstChildByClass(XFA_Element::ContentArea); | |
| float fNextContentHeight = | |
| pContentArea->JSNode()->GetMeasure(XFA_Attribute::H).ToUnit(XFA_Unit::Pt); | |
| if (fNextContentHeight < XFA_LAYOUT_FLOAT_PERCISION) | |
| return true; | |
| if (fNextContentHeight > fChildHeight) | |
| return true; | |
| return false; | |
| } | |
| void CXFA_LayoutPageMgr::ClearData() { | |
| if (!m_pTemplatePageSetRoot) | |
| return; | |
| auto sPos = m_ProposedContainerRecords.begin(); | |
| while (sPos != m_ProposedContainerRecords.end()) { | |
| CXFA_ContainerRecord* pRecord = *sPos++; | |
| delete pRecord; | |
| } | |
| m_ProposedContainerRecords.clear(); | |
| m_CurrentContainerRecordIter = m_ProposedContainerRecords.end(); | |
| m_pCurPageArea = nullptr; | |
| m_nCurPageCount = 0; | |
| m_bCreateOverFlowPage = false; | |
| m_pPageSetMap.clear(); | |
| } | |
| void CXFA_LayoutPageMgr::SaveLayoutItem(CXFA_LayoutItem* pParentLayoutItem) { | |
| CXFA_LayoutItem* pNextLayoutItem; | |
| CXFA_LayoutItem* pCurLayoutItem = pParentLayoutItem->m_pFirstChild; | |
| while (pCurLayoutItem) { | |
| pNextLayoutItem = pCurLayoutItem->m_pNextSibling; | |
| if (pCurLayoutItem->IsContentLayoutItem()) { | |
| if (pCurLayoutItem->m_pFormNode->HasRemovedChildren()) { | |
| CXFA_FFNotify* pNotify = | |
| m_pTemplatePageSetRoot->GetDocument()->GetNotify(); | |
| CXFA_LayoutProcessor* pDocLayout = | |
| m_pTemplatePageSetRoot->GetDocument()->GetDocLayout(); | |
| if (pCurLayoutItem->m_pFirstChild) | |
| SyncRemoveLayoutItem(pCurLayoutItem, pNotify, pDocLayout); | |
| pNotify->OnLayoutItemRemoving(pDocLayout, pCurLayoutItem); | |
| delete pCurLayoutItem; | |
| pCurLayoutItem = pNextLayoutItem; | |
| continue; | |
| } | |
| if (pCurLayoutItem->m_pFormNode->IsLayoutGeneratedNode()) { | |
| CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> | |
| sIterator(pCurLayoutItem->m_pFormNode); | |
| for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode; | |
| pNode = sIterator.MoveToNext()) { | |
| pNode->SetFlag(XFA_NodeFlag_UnusedNode, false); | |
| } | |
| } | |
| } | |
| if (pCurLayoutItem->m_pFirstChild) | |
| SaveLayoutItem(pCurLayoutItem); | |
| pCurLayoutItem->m_pParent = nullptr; | |
| pCurLayoutItem->m_pNextSibling = nullptr; | |
| pCurLayoutItem->m_pFirstChild = nullptr; | |
| if (!pCurLayoutItem->IsContentLayoutItem() && | |
| pCurLayoutItem->m_pFormNode->GetElementType() != | |
| XFA_Element::PageArea) { | |
| delete pCurLayoutItem; | |
| } | |
| pCurLayoutItem = pNextLayoutItem; | |
| } | |
| } | |
| CXFA_Node* CXFA_LayoutPageMgr::QueryOverflow(CXFA_Node* pFormNode) { | |
| for (CXFA_Node* pCurNode = pFormNode->GetNodeItem(XFA_NODEITEM_FirstChild); | |
| pCurNode; pCurNode = pCurNode->GetNodeItem((XFA_NODEITEM_NextSibling))) { | |
| if (pCurNode->GetElementType() == XFA_Element::Break) { | |
| WideString wsOverflowLeader = | |
| pCurNode->JSNode()->GetCData(XFA_Attribute::OverflowLeader); | |
| WideString wsOverflowTarget = | |
| pCurNode->JSNode()->GetCData(XFA_Attribute::OverflowTarget); | |
| WideString wsOverflowTrailer = | |
| pCurNode->JSNode()->GetCData(XFA_Attribute::OverflowTrailer); | |
| if (!wsOverflowLeader.IsEmpty() || !wsOverflowTrailer.IsEmpty() || | |
| !wsOverflowTarget.IsEmpty()) { | |
| return pCurNode; | |
| } | |
| return nullptr; | |
| } | |
| if (pCurNode->GetElementType() == XFA_Element::Overflow) | |
| return pCurNode; | |
| } | |
| return nullptr; | |
| } | |
| void CXFA_LayoutPageMgr::MergePageSetContents() { | |
| CXFA_Document* pDocument = m_pTemplatePageSetRoot->GetDocument(); | |
| CXFA_FFNotify* pNotify = pDocument->GetNotify(); | |
| CXFA_LayoutProcessor* pDocLayout = pDocument->GetDocLayout(); | |
| CXFA_ContainerLayoutItem* pRootLayout = GetRootLayoutItem(); | |
| for (CXFA_Node* pPageNode : pDocument->m_pPendingPageSet) { | |
| CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> | |
| sIterator(pPageNode); | |
| for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode; | |
| pNode = sIterator.MoveToNext()) { | |
| if (pNode->IsContainerNode()) { | |
| CXFA_Node* pBindNode = pNode->GetBindData(); | |
| if (pBindNode) { | |
| pBindNode->RemoveBindItem(pNode); | |
| pNode->JSNode()->SetBindingNode(nullptr); | |
| } | |
| } | |
| pNode->SetFlag(XFA_NodeFlag_UnusedNode, true); | |
| } | |
| } | |
| int32_t iIndex = 0; | |
| for (; pRootLayout; pRootLayout = static_cast<CXFA_ContainerLayoutItem*>( | |
| pRootLayout->m_pNextSibling)) { | |
| CXFA_Node* pPendingPageSet = nullptr; | |
| CXFA_NodeIteratorTemplate< | |
| CXFA_ContainerLayoutItem, | |
| CXFA_TraverseStrategy_ContentAreaContainerLayoutItem> | |
| iterator(pRootLayout); | |
| CXFA_ContainerLayoutItem* pRootPageSetContainerItem = iterator.GetCurrent(); | |
| ASSERT(pRootPageSetContainerItem->m_pFormNode->GetElementType() == | |
| XFA_Element::PageSet); | |
| if (iIndex < | |
| pdfium::CollectionSize<int32_t>(pDocument->m_pPendingPageSet)) { | |
| pPendingPageSet = pDocument->m_pPendingPageSet[iIndex]; | |
| iIndex++; | |
| } | |
| if (!pPendingPageSet) { | |
| if (pRootPageSetContainerItem->m_pFormNode->GetPacketType() == | |
| XFA_PacketType::Template) { | |
| pPendingPageSet = | |
| pRootPageSetContainerItem->m_pFormNode->CloneTemplateToForm(false); | |
| } else { | |
| pPendingPageSet = pRootPageSetContainerItem->m_pFormNode; | |
| } | |
| } | |
| if (pRootPageSetContainerItem->m_pFormNode->JSNode()->GetLayoutItem() == | |
| pRootPageSetContainerItem) { | |
| pRootPageSetContainerItem->m_pFormNode->JSNode()->SetLayoutItem(nullptr); | |
| } | |
| pRootPageSetContainerItem->m_pFormNode = pPendingPageSet; | |
| pPendingPageSet->ClearFlag(XFA_NodeFlag_UnusedNode); | |
| for (CXFA_ContainerLayoutItem* pContainerItem = iterator.MoveToNext(); | |
| pContainerItem; pContainerItem = iterator.MoveToNext()) { | |
| CXFA_Node* pNode = pContainerItem->m_pFormNode; | |
| if (pNode->GetPacketType() != XFA_PacketType::Template) | |
| continue; | |
| switch (pNode->GetElementType()) { | |
| case XFA_Element::PageSet: { | |
| CXFA_Node* pParentNode = pContainerItem->m_pParent->m_pFormNode; | |
| pContainerItem->m_pFormNode = XFA_NodeMerge_CloneOrMergeContainer( | |
| pDocument, pParentNode, pContainerItem->m_pFormNode, true, | |
| nullptr); | |
| break; | |
| } | |
| case XFA_Element::PageArea: { | |
| CXFA_LayoutItem* pFormLayout = pContainerItem; | |
| CXFA_Node* pParentNode = pContainerItem->m_pParent->m_pFormNode; | |
| bool bIsExistForm = true; | |
| for (int32_t iLevel = 0; iLevel < 3; iLevel++) { | |
| pFormLayout = pFormLayout->m_pFirstChild; | |
| if (iLevel == 2) { | |
| while (pFormLayout && | |
| !XFA_ItemLayoutProcessor_IsTakingSpace( | |
| pFormLayout->m_pFormNode)) { | |
| pFormLayout = pFormLayout->m_pNextSibling; | |
| } | |
| } | |
| if (!pFormLayout) { | |
| bIsExistForm = false; | |
| break; | |
| } | |
| } | |
| if (bIsExistForm) { | |
| CXFA_Node* pNewSubform = pFormLayout->m_pFormNode; | |
| if (pContainerItem->m_pOldSubform && | |
| pContainerItem->m_pOldSubform != pNewSubform) { | |
| CXFA_Node* pExistingNode = XFA_DataMerge_FindFormDOMInstance( | |
| pDocument, pContainerItem->m_pFormNode->GetElementType(), | |
| pContainerItem->m_pFormNode->GetNameHash(), pParentNode); | |
| CXFA_ContainerIterator sIterator(pExistingNode); | |
| for (CXFA_Node* pIter = sIterator.GetCurrent(); pIter; | |
| pIter = sIterator.MoveToNext()) { | |
| if (pIter->GetElementType() != XFA_Element::ContentArea) { | |
| CXFA_LayoutItem* pLayoutItem = | |
| pIter->JSNode()->GetLayoutItem(); | |
| if (pLayoutItem) { | |
| pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem); | |
| delete pLayoutItem; | |
| } | |
| } | |
| } | |
| if (pExistingNode) { | |
| pParentNode->RemoveChild(pExistingNode, true); | |
| } | |
| } | |
| pContainerItem->m_pOldSubform = pNewSubform; | |
| } | |
| pContainerItem->m_pFormNode = pDocument->DataMerge_CopyContainer( | |
| pContainerItem->m_pFormNode, pParentNode, | |
| ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Record)), true, true, | |
| true); | |
| break; | |
| } | |
| case XFA_Element::ContentArea: { | |
| CXFA_Node* pParentNode = pContainerItem->m_pParent->m_pFormNode; | |
| for (CXFA_Node* pChildNode = | |
| pParentNode->GetNodeItem(XFA_NODEITEM_FirstChild); | |
| pChildNode; | |
| pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_NextSibling)) { | |
| if (pChildNode->GetTemplateNode() != pContainerItem->m_pFormNode) { | |
| continue; | |
| } | |
| pContainerItem->m_pFormNode = pChildNode; | |
| break; | |
| } | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| } | |
| if (!pPendingPageSet->GetNodeItem(XFA_NODEITEM_Parent)) { | |
| CXFA_Node* pFormToplevelSubform = | |
| pDocument->GetXFAObject(XFA_HASHCODE_Form) | |
| ->AsNode() | |
| ->GetFirstChildByClass(XFA_Element::Subform); | |
| pFormToplevelSubform->InsertChild(pPendingPageSet, nullptr); | |
| } | |
| pDocument->DataMerge_UpdateBindingRelations(pPendingPageSet); | |
| pPendingPageSet->SetFlag(XFA_NodeFlag_Initialized, true); | |
| } | |
| CXFA_Node* pPageSet = GetRootLayoutItem()->m_pFormNode; | |
| while (pPageSet) { | |
| CXFA_Node* pNextPageSet = | |
| pPageSet->GetNextSameClassSibling(XFA_Element::PageSet); | |
| CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> | |
| sIterator(pPageSet); | |
| CXFA_Node* pNode = sIterator.GetCurrent(); | |
| while (pNode) { | |
| if (pNode->IsUnusedNode()) { | |
| if (pNode->IsContainerNode()) { | |
| XFA_Element eType = pNode->GetElementType(); | |
| if (eType == XFA_Element::PageArea || eType == XFA_Element::PageSet) { | |
| CXFA_ContainerIterator iteChild(pNode); | |
| CXFA_Node* pChildNode = iteChild.MoveToNext(); | |
| for (; pChildNode; pChildNode = iteChild.MoveToNext()) { | |
| CXFA_LayoutItem* pLayoutItem = | |
| pChildNode->JSNode()->GetLayoutItem(); | |
| if (pLayoutItem) { | |
| pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem); | |
| delete pLayoutItem; | |
| } | |
| } | |
| } else if (eType != XFA_Element::ContentArea) { | |
| CXFA_LayoutItem* pLayoutItem = pNode->JSNode()->GetLayoutItem(); | |
| if (pLayoutItem) { | |
| pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem); | |
| delete pLayoutItem; | |
| } | |
| } | |
| CXFA_Node* pNext = sIterator.SkipChildrenAndMoveToNext(); | |
| pNode->GetNodeItem(XFA_NODEITEM_Parent)->RemoveChild(pNode, true); | |
| pNode = pNext; | |
| } else { | |
| pNode->ClearFlag(XFA_NodeFlag_UnusedNode); | |
| pNode->SetFlag(XFA_NodeFlag_Initialized, true); | |
| pNode = sIterator.MoveToNext(); | |
| } | |
| } else { | |
| pNode->SetFlag(XFA_NodeFlag_Initialized, true); | |
| pNode = sIterator.MoveToNext(); | |
| } | |
| } | |
| pPageSet = pNextPageSet; | |
| } | |
| } | |
| void CXFA_LayoutPageMgr::LayoutPageSetContents() { | |
| CXFA_ContainerLayoutItem* pRootLayoutItem = GetRootLayoutItem(); | |
| for (; pRootLayoutItem; | |
| pRootLayoutItem = static_cast<CXFA_ContainerLayoutItem*>( | |
| pRootLayoutItem->m_pNextSibling)) { | |
| CXFA_NodeIteratorTemplate< | |
| CXFA_ContainerLayoutItem, | |
| CXFA_TraverseStrategy_ContentAreaContainerLayoutItem> | |
| iterator(pRootLayoutItem); | |
| for (CXFA_ContainerLayoutItem* pContainerItem = iterator.GetCurrent(); | |
| pContainerItem; pContainerItem = iterator.MoveToNext()) { | |
| CXFA_Node* pNode = pContainerItem->m_pFormNode; | |
| switch (pNode->GetElementType()) { | |
| case XFA_Element::PageArea: | |
| m_pLayoutProcessor->GetRootRootItemLayoutProcessor() | |
| ->DoLayoutPageArea(pContainerItem); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| void CXFA_LayoutPageMgr::SyncLayoutData() { | |
| MergePageSetContents(); | |
| LayoutPageSetContents(); | |
| CXFA_FFNotify* pNotify = m_pTemplatePageSetRoot->GetDocument()->GetNotify(); | |
| int32_t nPageIdx = -1; | |
| CXFA_ContainerLayoutItem* pRootLayoutItem = GetRootLayoutItem(); | |
| for (; pRootLayoutItem; | |
| pRootLayoutItem = static_cast<CXFA_ContainerLayoutItem*>( | |
| pRootLayoutItem->m_pNextSibling)) { | |
| CXFA_NodeIteratorTemplate< | |
| CXFA_ContainerLayoutItem, | |
| CXFA_TraverseStrategy_ContentAreaContainerLayoutItem> | |
| iteratorParent(pRootLayoutItem); | |
| for (CXFA_ContainerLayoutItem* pContainerItem = iteratorParent.GetCurrent(); | |
| pContainerItem; pContainerItem = iteratorParent.MoveToNext()) { | |
| switch (pContainerItem->m_pFormNode->GetElementType()) { | |
| case XFA_Element::PageArea: { | |
| nPageIdx++; | |
| uint32_t dwRelevant = | |
| XFA_WidgetStatus_Viewable | XFA_WidgetStatus_Printable; | |
| CXFA_NodeIteratorTemplate<CXFA_LayoutItem, | |
| CXFA_TraverseStrategy_LayoutItem> | |
| iterator(pContainerItem); | |
| CXFA_LayoutItem* pChildLayoutItem = iterator.GetCurrent(); | |
| while (pChildLayoutItem) { | |
| CXFA_ContentLayoutItem* pContentItem = | |
| pChildLayoutItem->AsContentLayoutItem(); | |
| if (!pContentItem) { | |
| pChildLayoutItem = iterator.MoveToNext(); | |
| continue; | |
| } | |
| XFA_AttributeEnum presence = | |
| pContentItem->m_pFormNode->JSNode() | |
| ->TryEnum(XFA_Attribute::Presence, true) | |
| .value_or(XFA_AttributeEnum::Visible); | |
| bool bVisible = presence == XFA_AttributeEnum::Visible; | |
| uint32_t dwRelevantChild = | |
| GetRelevant(pContentItem->m_pFormNode, dwRelevant); | |
| SyncContainer(pNotify, m_pLayoutProcessor, pContentItem, | |
| dwRelevantChild, bVisible, nPageIdx); | |
| pChildLayoutItem = iterator.SkipChildrenAndMoveToNext(); | |
| } | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| } | |
| } | |
| int32_t nPage = pdfium::CollectionSize<int32_t>(m_PageArray); | |
| for (int32_t i = nPage - 1; i >= m_nAvailPages; i--) { | |
| CXFA_ContainerLayoutItem* pPage = m_PageArray[i]; | |
| m_PageArray.erase(m_PageArray.begin() + i); | |
| pNotify->OnPageEvent(pPage, XFA_PAGEVIEWEVENT_PostRemoved); | |
| delete pPage; | |
| } | |
| ClearData(); | |
| } | |
| void XFA_ReleaseLayoutItem_NoPageArea(CXFA_LayoutItem* pLayoutItem) { | |
| CXFA_LayoutItem *pNext, *pNode = pLayoutItem->m_pFirstChild; | |
| while (pNode) { | |
| pNext = pNode->m_pNextSibling; | |
| pNode->m_pParent = nullptr; | |
| XFA_ReleaseLayoutItem_NoPageArea(pNode); | |
| pNode = pNext; | |
| } | |
| if (pLayoutItem->m_pFormNode->GetElementType() != XFA_Element::PageArea) | |
| delete pLayoutItem; | |
| } | |
| void CXFA_LayoutPageMgr::PrepareLayout() { | |
| m_pPageSetCurRoot = nullptr; | |
| m_ePageSetMode = XFA_AttributeEnum::OrderedOccurrence; | |
| m_nAvailPages = 0; | |
| ClearData(); | |
| if (!m_pPageSetLayoutItemRoot) | |
| return; | |
| CXFA_ContainerLayoutItem* pRootLayoutItem = m_pPageSetLayoutItemRoot; | |
| if (pRootLayoutItem && | |
| pRootLayoutItem->m_pFormNode->GetPacketType() == XFA_PacketType::Form) { | |
| CXFA_Node* pPageSetFormNode = pRootLayoutItem->m_pFormNode; | |
| pRootLayoutItem->m_pFormNode->GetDocument()->m_pPendingPageSet.clear(); | |
| if (pPageSetFormNode->HasRemovedChildren()) { | |
| XFA_ReleaseLayoutItem(pRootLayoutItem); | |
| m_pPageSetLayoutItemRoot = nullptr; | |
| pRootLayoutItem = nullptr; | |
| pPageSetFormNode = nullptr; | |
| m_PageArray.clear(); | |
| } | |
| while (pPageSetFormNode) { | |
| CXFA_Node* pNextPageSet = | |
| pPageSetFormNode->GetNextSameClassSibling(XFA_Element::PageSet); | |
| pPageSetFormNode->GetNodeItem(XFA_NODEITEM_Parent) | |
| ->RemoveChild(pPageSetFormNode, false); | |
| pRootLayoutItem->m_pFormNode->GetDocument()->m_pPendingPageSet.push_back( | |
| pPageSetFormNode); | |
| pPageSetFormNode = pNextPageSet; | |
| } | |
| } | |
| pRootLayoutItem = m_pPageSetLayoutItemRoot; | |
| CXFA_ContainerLayoutItem* pNextLayout = nullptr; | |
| for (; pRootLayoutItem; pRootLayoutItem = pNextLayout) { | |
| pNextLayout = | |
| static_cast<CXFA_ContainerLayoutItem*>(pRootLayoutItem->m_pNextSibling); | |
| SaveLayoutItem(pRootLayoutItem); | |
| delete pRootLayoutItem; | |
| } | |
| m_pPageSetLayoutItemRoot = nullptr; | |
| } |