// 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(pLayoutItem->m_pFirstChild); while (pChildItem && pChildItem->m_pFormNode->GetElementType() != XFA_Element::PageSet) { pChildItem = static_cast(pChildItem->m_pNextSibling); } return pChildItem; } static CXFA_ContainerLayoutItem* GetNextSibling( CXFA_ContainerLayoutItem* pLayoutItem) { CXFA_ContainerLayoutItem* pChildItem = static_cast(pLayoutItem->m_pNextSibling); while (pChildItem && pChildItem->m_pFormNode->GetElementType() != XFA_Element::PageSet) { pChildItem = static_cast(pChildItem->m_pNextSibling); } return pChildItem; } static CXFA_ContainerLayoutItem* GetParent( CXFA_ContainerLayoutItem* pLayoutItem) { return static_cast(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(pLayoutItem->m_pParent); if (!pParentLayoutItem) return; pParentLayoutItem->RemoveChild(pLayoutItem); pParentLayoutItem->AddChild(pLayoutItem); } void RemoveLayoutItem(CXFA_ContainerLayoutItem* pLayoutItem) { CXFA_ContainerLayoutItem* pParentLayoutItem = static_cast(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 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( pPageAreaLayoutItem->m_pFirstChild); pLayoutItem; pLayoutItem = static_cast( 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( 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( GetCurrentContainerRecord()->pCurPageSet->m_pParent); } else { pParentPageSetLayout = static_cast( 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( 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( 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( pRootPageSetLayoutItem->m_pNextSibling)) { CXFA_NodeIteratorTemplate 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 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(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 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 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 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 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 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 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 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 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( 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(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 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( 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( 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 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(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(pRootLayoutItem->m_pNextSibling); SaveLayoutItem(pRootLayoutItem); delete pRootLayoutItem; } m_pPageSetLayoutItemRoot = nullptr; }