• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "xfa/fxfa/parser/cxfa_layoutpagemgr.h"
8 
9 #include "fxjs/cfxjse_engine.h"
10 #include "fxjs/xfa/cjx_object.h"
11 #include "third_party/base/stl_util.h"
12 #include "xfa/fxfa/cxfa_ffnotify.h"
13 #include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
14 #include "xfa/fxfa/parser/cxfa_contentarea.h"
15 #include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
16 #include "xfa/fxfa/parser/cxfa_document.h"
17 #include "xfa/fxfa/parser/cxfa_itemlayoutprocessor.h"
18 #include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
19 #include "xfa/fxfa/parser/cxfa_localemgr.h"
20 #include "xfa/fxfa/parser/cxfa_measurement.h"
21 #include "xfa/fxfa/parser/cxfa_medium.h"
22 #include "xfa/fxfa/parser/cxfa_node.h"
23 #include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
24 #include "xfa/fxfa/parser/cxfa_object.h"
25 #include "xfa/fxfa/parser/cxfa_occur.h"
26 #include "xfa/fxfa/parser/cxfa_pageset.h"
27 #include "xfa/fxfa/parser/cxfa_subform.h"
28 #include "xfa/fxfa/parser/cxfa_traversestrategy_contentareacontainerlayoutitem.h"
29 #include "xfa/fxfa/parser/cxfa_traversestrategy_layoutitem.h"
30 #include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
31 #include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
32 #include "xfa/fxfa/parser/xfa_document_datamerger_imp.h"
33 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
34 
35 namespace {
36 
37 class PageSetContainerLayoutItem {
38  public:
GetFirstChild(CXFA_ContainerLayoutItem * pLayoutItem)39   static CXFA_ContainerLayoutItem* GetFirstChild(
40       CXFA_ContainerLayoutItem* pLayoutItem) {
41     if (pLayoutItem->m_pFormNode->GetElementType() != XFA_Element::PageSet)
42       return nullptr;
43 
44     CXFA_ContainerLayoutItem* pChildItem =
45         static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pFirstChild);
46     while (pChildItem &&
47            pChildItem->m_pFormNode->GetElementType() != XFA_Element::PageSet) {
48       pChildItem =
49           static_cast<CXFA_ContainerLayoutItem*>(pChildItem->m_pNextSibling);
50     }
51     return pChildItem;
52   }
53 
GetNextSibling(CXFA_ContainerLayoutItem * pLayoutItem)54   static CXFA_ContainerLayoutItem* GetNextSibling(
55       CXFA_ContainerLayoutItem* pLayoutItem) {
56     CXFA_ContainerLayoutItem* pChildItem =
57         static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pNextSibling);
58     while (pChildItem &&
59            pChildItem->m_pFormNode->GetElementType() != XFA_Element::PageSet) {
60       pChildItem =
61           static_cast<CXFA_ContainerLayoutItem*>(pChildItem->m_pNextSibling);
62     }
63     return pChildItem;
64   }
65 
GetParent(CXFA_ContainerLayoutItem * pLayoutItem)66   static CXFA_ContainerLayoutItem* GetParent(
67       CXFA_ContainerLayoutItem* pLayoutItem) {
68     return static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pParent);
69   }
70 };
71 
GetRelevant(CXFA_Node * pFormItem,uint32_t dwParentRelvant)72 uint32_t GetRelevant(CXFA_Node* pFormItem, uint32_t dwParentRelvant) {
73   uint32_t dwRelevant = XFA_WidgetStatus_Viewable | XFA_WidgetStatus_Printable;
74   WideString wsRelevant =
75       pFormItem->JSObject()->GetCData(XFA_Attribute::Relevant);
76   if (!wsRelevant.IsEmpty()) {
77     if (wsRelevant == L"+print" || wsRelevant == L"print")
78       dwRelevant &= ~XFA_WidgetStatus_Viewable;
79     else if (wsRelevant == L"-print")
80       dwRelevant &= ~XFA_WidgetStatus_Printable;
81   }
82 
83   if (!(dwParentRelvant & XFA_WidgetStatus_Viewable) &&
84       (dwRelevant != XFA_WidgetStatus_Viewable)) {
85     dwRelevant &= ~XFA_WidgetStatus_Viewable;
86   }
87 
88   if (!(dwParentRelvant & XFA_WidgetStatus_Printable) &&
89       (dwRelevant != XFA_WidgetStatus_Printable)) {
90     dwRelevant &= ~XFA_WidgetStatus_Printable;
91   }
92   return dwRelevant;
93 }
94 
SyncContainer(CXFA_FFNotify * pNotify,CXFA_LayoutProcessor * pDocLayout,CXFA_LayoutItem * pContainerItem,uint32_t dwRelevant,bool bVisible,int32_t nPageIndex)95 void SyncContainer(CXFA_FFNotify* pNotify,
96                    CXFA_LayoutProcessor* pDocLayout,
97                    CXFA_LayoutItem* pContainerItem,
98                    uint32_t dwRelevant,
99                    bool bVisible,
100                    int32_t nPageIndex) {
101   bool bVisibleItem = false;
102   uint32_t dwStatus = 0;
103   uint32_t dwRelevantContainer = 0;
104   if (bVisible) {
105     XFA_AttributeEnum eAttributeValue =
106         pContainerItem->m_pFormNode->JSObject()
107             ->TryEnum(XFA_Attribute::Presence, true)
108             .value_or(XFA_AttributeEnum::Visible);
109     if (eAttributeValue == XFA_AttributeEnum::Visible)
110       bVisibleItem = true;
111 
112     dwRelevantContainer = GetRelevant(pContainerItem->m_pFormNode, dwRelevant);
113     dwStatus =
114         (bVisibleItem ? XFA_WidgetStatus_Visible : 0) | dwRelevantContainer;
115   }
116   pNotify->OnLayoutItemAdded(pDocLayout, pContainerItem, nPageIndex, dwStatus);
117   for (CXFA_LayoutItem* pChild = pContainerItem->m_pFirstChild; pChild;
118        pChild = pChild->m_pNextSibling) {
119     if (pChild->IsContentLayoutItem()) {
120       SyncContainer(pNotify, pDocLayout, pChild, dwRelevantContainer,
121                     bVisibleItem, nPageIndex);
122     }
123   }
124 }
125 
ReorderLayoutItemToTail(CXFA_ContainerLayoutItem * pLayoutItem)126 void ReorderLayoutItemToTail(CXFA_ContainerLayoutItem* pLayoutItem) {
127   CXFA_ContainerLayoutItem* pParentLayoutItem =
128       static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pParent);
129   if (!pParentLayoutItem)
130     return;
131 
132   pParentLayoutItem->RemoveChild(pLayoutItem);
133   pParentLayoutItem->AddChild(pLayoutItem);
134 }
135 
RemoveLayoutItem(CXFA_ContainerLayoutItem * pLayoutItem)136 void RemoveLayoutItem(CXFA_ContainerLayoutItem* pLayoutItem) {
137   CXFA_ContainerLayoutItem* pParentLayoutItem =
138       static_cast<CXFA_ContainerLayoutItem*>(pLayoutItem->m_pParent);
139   if (!pParentLayoutItem)
140     return;
141 
142   pParentLayoutItem->RemoveChild(pLayoutItem);
143 }
144 
ResolveBreakTarget(CXFA_Node * pPageSetRoot,bool bNewExprStyle,WideString & wsTargetAll)145 CXFA_Node* ResolveBreakTarget(CXFA_Node* pPageSetRoot,
146                               bool bNewExprStyle,
147                               WideString& wsTargetAll) {
148   if (!pPageSetRoot)
149     return nullptr;
150 
151   CXFA_Document* pDocument = pPageSetRoot->GetDocument();
152   if (wsTargetAll.IsEmpty())
153     return nullptr;
154 
155   wsTargetAll.Trim();
156   int32_t iSplitIndex = 0;
157   bool bTargetAllFind = true;
158   while (iSplitIndex != -1) {
159     WideString wsExpr;
160     Optional<size_t> iSplitNextIndex = 0;
161     if (!bTargetAllFind) {
162       iSplitNextIndex = wsTargetAll.Find(' ', iSplitIndex);
163       if (!iSplitNextIndex.has_value())
164         return nullptr;
165       wsExpr =
166           wsTargetAll.Mid(iSplitIndex, iSplitNextIndex.value() - iSplitIndex);
167     } else {
168       wsExpr = wsTargetAll;
169     }
170     if (wsExpr.IsEmpty())
171       return nullptr;
172 
173     bTargetAllFind = false;
174     if (wsExpr[0] == '#') {
175       CXFA_Node* pNode = pDocument->GetNodeByID(
176           ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Template)),
177           wsExpr.Right(wsExpr.GetLength() - 1).AsStringView());
178       if (pNode)
179         return pNode;
180     } else if (bNewExprStyle) {
181       WideString wsProcessedTarget = wsExpr;
182       if (wsExpr.Left(4) == L"som(" && wsExpr.Last() == L')') {
183         wsProcessedTarget = wsExpr.Mid(4, wsExpr.GetLength() - 5);
184       }
185       XFA_RESOLVENODE_RS rs;
186       bool iRet = pDocument->GetScriptContext()->ResolveObjects(
187           pPageSetRoot, wsProcessedTarget.AsStringView(), &rs,
188           XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Properties |
189               XFA_RESOLVENODE_Attributes | XFA_RESOLVENODE_Siblings |
190               XFA_RESOLVENODE_Parent,
191           nullptr);
192       if (iRet && rs.objects.front()->IsNode())
193         return rs.objects.front()->AsNode();
194     }
195     iSplitIndex = iSplitNextIndex.value();
196   }
197   return nullptr;
198 }
199 
SetLayoutGeneratedNodeFlag(CXFA_Node * pNode)200 void SetLayoutGeneratedNodeFlag(CXFA_Node* pNode) {
201   pNode->SetFlag(XFA_NodeFlag_LayoutGeneratedNode, false);
202   pNode->ClearFlag(XFA_NodeFlag_UnusedNode);
203 }
204 
CheckContentAreaNotUsed(CXFA_ContainerLayoutItem * pPageAreaLayoutItem,CXFA_Node * pContentArea,CXFA_ContainerLayoutItem * & pContentAreaLayoutItem)205 bool CheckContentAreaNotUsed(
206     CXFA_ContainerLayoutItem* pPageAreaLayoutItem,
207     CXFA_Node* pContentArea,
208     CXFA_ContainerLayoutItem*& pContentAreaLayoutItem) {
209   for (CXFA_ContainerLayoutItem* pLayoutItem =
210            static_cast<CXFA_ContainerLayoutItem*>(
211                pPageAreaLayoutItem->m_pFirstChild);
212        pLayoutItem; pLayoutItem = static_cast<CXFA_ContainerLayoutItem*>(
213                         pLayoutItem->m_pNextSibling)) {
214     if (pLayoutItem->m_pFormNode == pContentArea) {
215       if (!pLayoutItem->m_pFirstChild) {
216         pContentAreaLayoutItem = pLayoutItem;
217         return true;
218       }
219       return false;
220     }
221   }
222   return true;
223 }
224 
SyncRemoveLayoutItem(CXFA_LayoutItem * pParentLayoutItem,CXFA_FFNotify * pNotify,CXFA_LayoutProcessor * pDocLayout)225 void SyncRemoveLayoutItem(CXFA_LayoutItem* pParentLayoutItem,
226                           CXFA_FFNotify* pNotify,
227                           CXFA_LayoutProcessor* pDocLayout) {
228   CXFA_LayoutItem* pNextLayoutItem;
229   CXFA_LayoutItem* pCurLayoutItem = pParentLayoutItem->m_pFirstChild;
230   while (pCurLayoutItem) {
231     pNextLayoutItem = pCurLayoutItem->m_pNextSibling;
232     if (pCurLayoutItem->m_pFirstChild)
233       SyncRemoveLayoutItem(pCurLayoutItem, pNotify, pDocLayout);
234 
235     pNotify->OnLayoutItemRemoving(pDocLayout, pCurLayoutItem);
236     delete pCurLayoutItem;
237     pCurLayoutItem = pNextLayoutItem;
238   }
239 }
240 
RunBreakTestScript(CXFA_Script * pTestScript)241 bool RunBreakTestScript(CXFA_Script* pTestScript) {
242   WideString wsExpression = pTestScript->JSObject()->GetContent(false);
243   if (wsExpression.IsEmpty())
244     return true;
245   return pTestScript->GetDocument()->GetNotify()->RunScript(
246       pTestScript, pTestScript->GetContainerParent());
247 }
248 
249 }  // namespace
250 
251 class CXFA_ContainerRecord {
252  public:
CXFA_ContainerRecord(CXFA_ContainerLayoutItem * pPageSet=nullptr,CXFA_ContainerLayoutItem * pPageArea=nullptr,CXFA_ContainerLayoutItem * pContentArea=nullptr)253   CXFA_ContainerRecord(CXFA_ContainerLayoutItem* pPageSet = nullptr,
254                        CXFA_ContainerLayoutItem* pPageArea = nullptr,
255                        CXFA_ContainerLayoutItem* pContentArea = nullptr)
256       : pCurPageSet(pPageSet),
257         pCurPageArea(pPageArea),
258         pCurContentArea(pContentArea) {}
259 
260   CXFA_ContainerLayoutItem* pCurPageSet;
261   CXFA_ContainerLayoutItem* pCurPageArea;
262   CXFA_ContainerLayoutItem* pCurContentArea;
263 };
264 
CXFA_LayoutPageMgr(CXFA_LayoutProcessor * pLayoutProcessor)265 CXFA_LayoutPageMgr::CXFA_LayoutPageMgr(CXFA_LayoutProcessor* pLayoutProcessor)
266     : m_pLayoutProcessor(pLayoutProcessor),
267       m_pTemplatePageSetRoot(nullptr),
268       m_pPageSetLayoutItemRoot(nullptr),
269       m_pPageSetCurRoot(nullptr),
270       m_CurrentContainerRecordIter(m_ProposedContainerRecords.end()),
271       m_pCurPageArea(nullptr),
272       m_nAvailPages(0),
273       m_nCurPageCount(0),
274       m_ePageSetMode(XFA_AttributeEnum::OrderedOccurrence),
275       m_bCreateOverFlowPage(false) {}
276 
~CXFA_LayoutPageMgr()277 CXFA_LayoutPageMgr::~CXFA_LayoutPageMgr() {
278   ClearData();
279   CXFA_LayoutItem* pLayoutItem = GetRootLayoutItem();
280   CXFA_LayoutItem* pNextLayout = nullptr;
281   for (; pLayoutItem; pLayoutItem = pNextLayout) {
282     pNextLayout = pLayoutItem->m_pNextSibling;
283     XFA_ReleaseLayoutItem(pLayoutItem);
284   }
285 }
286 
InitLayoutPage(CXFA_Node * pFormNode)287 bool CXFA_LayoutPageMgr::InitLayoutPage(CXFA_Node* pFormNode) {
288   PrepareLayout();
289   CXFA_Node* pTemplateNode = pFormNode->GetTemplateNodeIfExists();
290   if (!pTemplateNode)
291     return false;
292 
293   m_pTemplatePageSetRoot =
294       pTemplateNode->JSObject()->GetOrCreateProperty<CXFA_PageSet>(
295           0, XFA_Element::PageSet);
296   ASSERT(m_pTemplatePageSetRoot);
297 
298   if (m_pPageSetLayoutItemRoot) {
299     m_pPageSetLayoutItemRoot->m_pParent = nullptr;
300     m_pPageSetLayoutItemRoot->m_pFirstChild = nullptr;
301     m_pPageSetLayoutItemRoot->m_pNextSibling = nullptr;
302     m_pPageSetLayoutItemRoot->m_pFormNode = m_pTemplatePageSetRoot;
303   } else {
304     m_pPageSetLayoutItemRoot =
305         new CXFA_ContainerLayoutItem(m_pTemplatePageSetRoot);
306   }
307   m_pPageSetCurRoot = m_pPageSetLayoutItemRoot;
308   m_pTemplatePageSetRoot->JSObject()->SetLayoutItem(m_pPageSetLayoutItemRoot);
309 
310   XFA_AttributeEnum eRelation =
311       m_pTemplatePageSetRoot->JSObject()->GetEnum(XFA_Attribute::Relation);
312   if (eRelation != XFA_AttributeEnum::Unknown)
313     m_ePageSetMode = eRelation;
314 
315   InitPageSetMap();
316   CXFA_Node* pPageArea = nullptr;
317   int32_t iCount = 0;
318   for (pPageArea = m_pTemplatePageSetRoot->GetFirstChild(); pPageArea;
319        pPageArea = pPageArea->GetNextSibling()) {
320     if (pPageArea->GetElementType() == XFA_Element::PageArea) {
321       iCount++;
322       if (pPageArea->GetFirstChildByClass<CXFA_ContentArea>(
323               XFA_Element::ContentArea))
324         return true;
325     }
326   }
327   if (iCount > 0)
328     return false;
329 
330   CXFA_Document* pDocument = pTemplateNode->GetDocument();
331   pPageArea = m_pTemplatePageSetRoot->GetChild<CXFA_Node>(
332       0, XFA_Element::PageArea, false);
333   if (!pPageArea) {
334     pPageArea = pDocument->CreateNode(m_pTemplatePageSetRoot->GetPacketType(),
335                                       XFA_Element::PageArea);
336     if (!pPageArea)
337       return false;
338 
339     m_pTemplatePageSetRoot->InsertChild(pPageArea, nullptr);
340     pPageArea->SetFlag(XFA_NodeFlag_Initialized, true);
341   }
342   CXFA_ContentArea* pContentArea =
343       pPageArea->GetChild<CXFA_ContentArea>(0, XFA_Element::ContentArea, false);
344   if (!pContentArea) {
345     pContentArea = static_cast<CXFA_ContentArea*>(pDocument->CreateNode(
346         pPageArea->GetPacketType(), XFA_Element::ContentArea));
347     if (!pContentArea)
348       return false;
349 
350     pPageArea->InsertChild(pContentArea, nullptr);
351     pContentArea->SetFlag(XFA_NodeFlag_Initialized, true);
352     pContentArea->JSObject()->SetMeasure(
353         XFA_Attribute::X, CXFA_Measurement(0.25f, XFA_Unit::In), false);
354     pContentArea->JSObject()->SetMeasure(
355         XFA_Attribute::Y, CXFA_Measurement(0.25f, XFA_Unit::In), false);
356     pContentArea->JSObject()->SetMeasure(
357         XFA_Attribute::W, CXFA_Measurement(8.0f, XFA_Unit::In), false);
358     pContentArea->JSObject()->SetMeasure(
359         XFA_Attribute::H, CXFA_Measurement(10.5f, XFA_Unit::In), false);
360   }
361   CXFA_Medium* pMedium =
362       pPageArea->GetChild<CXFA_Medium>(0, XFA_Element::Medium, false);
363   if (!pMedium) {
364     pMedium = static_cast<CXFA_Medium*>(
365         pDocument->CreateNode(pPageArea->GetPacketType(), XFA_Element::Medium));
366     if (!pContentArea)
367       return false;
368 
369     pPageArea->InsertChild(pMedium, nullptr);
370     pMedium->SetFlag(XFA_NodeFlag_Initialized, true);
371     pMedium->JSObject()->SetMeasure(
372         XFA_Attribute::Short, CXFA_Measurement(8.5f, XFA_Unit::In), false);
373     pMedium->JSObject()->SetMeasure(
374         XFA_Attribute::Long, CXFA_Measurement(11.0f, XFA_Unit::In), false);
375   }
376   return true;
377 }
378 
PrepareFirstPage(CXFA_Node * pRootSubform)379 bool CXFA_LayoutPageMgr::PrepareFirstPage(CXFA_Node* pRootSubform) {
380   bool bProBreakBefore = false;
381   CXFA_Node* pBreakBeforeNode = nullptr;
382   while (pRootSubform) {
383     for (CXFA_Node* pBreakNode = pRootSubform->GetFirstChild(); pBreakNode;
384          pBreakNode = pBreakNode->GetNextSibling()) {
385       XFA_Element eType = pBreakNode->GetElementType();
386       if (eType == XFA_Element::BreakBefore ||
387           (eType == XFA_Element::Break &&
388            pBreakNode->JSObject()->GetEnum(XFA_Attribute::Before) !=
389                XFA_AttributeEnum::Auto)) {
390         bProBreakBefore = true;
391         pBreakBeforeNode = pBreakNode;
392         break;
393       }
394     }
395     if (bProBreakBefore)
396       break;
397 
398     bProBreakBefore = true;
399     pRootSubform =
400         pRootSubform->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
401     while (pRootSubform &&
402            !XFA_ItemLayoutProcessor_IsTakingSpace(pRootSubform)) {
403       pRootSubform = pRootSubform->GetNextSameClassSibling<CXFA_Subform>(
404           XFA_Element::Subform);
405     }
406   }
407   CXFA_Node* pLeader;
408   CXFA_Node* pTrailer;
409   if (pBreakBeforeNode &&
410       ExecuteBreakBeforeOrAfter(pBreakBeforeNode, true, pLeader, pTrailer)) {
411     m_CurrentContainerRecordIter = m_ProposedContainerRecords.begin();
412     return true;
413   }
414   return AppendNewPage(true);
415 }
416 
AppendNewPage(bool bFirstTemPage)417 bool CXFA_LayoutPageMgr::AppendNewPage(bool bFirstTemPage) {
418   if (m_CurrentContainerRecordIter != GetTailPosition())
419     return true;
420 
421   CXFA_Node* pPageNode = GetNextAvailPageArea(nullptr);
422   if (!pPageNode)
423     return false;
424 
425   if (bFirstTemPage &&
426       m_CurrentContainerRecordIter == m_ProposedContainerRecords.end()) {
427     m_CurrentContainerRecordIter = m_ProposedContainerRecords.begin();
428   }
429   return !bFirstTemPage ||
430          m_CurrentContainerRecordIter != m_ProposedContainerRecords.end();
431 }
432 
RemoveLayoutRecord(CXFA_ContainerRecord * pNewRecord,CXFA_ContainerRecord * pPrevRecord)433 void CXFA_LayoutPageMgr::RemoveLayoutRecord(CXFA_ContainerRecord* pNewRecord,
434                                             CXFA_ContainerRecord* pPrevRecord) {
435   if (!pNewRecord || !pPrevRecord)
436     return;
437   if (pNewRecord->pCurPageSet != pPrevRecord->pCurPageSet) {
438     RemoveLayoutItem(pNewRecord->pCurPageSet);
439     return;
440   }
441   if (pNewRecord->pCurPageArea != pPrevRecord->pCurPageArea) {
442     RemoveLayoutItem(pNewRecord->pCurPageArea);
443     return;
444   }
445   if (pNewRecord->pCurContentArea != pPrevRecord->pCurContentArea) {
446     RemoveLayoutItem(pNewRecord->pCurContentArea);
447     return;
448   }
449 }
450 
ReorderPendingLayoutRecordToTail(CXFA_ContainerRecord * pNewRecord,CXFA_ContainerRecord * pPrevRecord)451 void CXFA_LayoutPageMgr::ReorderPendingLayoutRecordToTail(
452     CXFA_ContainerRecord* pNewRecord,
453     CXFA_ContainerRecord* pPrevRecord) {
454   if (!pNewRecord || !pPrevRecord)
455     return;
456   if (pNewRecord->pCurPageSet != pPrevRecord->pCurPageSet) {
457     ReorderLayoutItemToTail(pNewRecord->pCurPageSet);
458     return;
459   }
460   if (pNewRecord->pCurPageArea != pPrevRecord->pCurPageArea) {
461     ReorderLayoutItemToTail(pNewRecord->pCurPageArea);
462     return;
463   }
464   if (pNewRecord->pCurContentArea != pPrevRecord->pCurContentArea) {
465     ReorderLayoutItemToTail(pNewRecord->pCurContentArea);
466     return;
467   }
468 }
469 
SubmitContentItem(CXFA_ContentLayoutItem * pContentLayoutItem,XFA_ItemLayoutProcessorResult eStatus)470 void CXFA_LayoutPageMgr::SubmitContentItem(
471     CXFA_ContentLayoutItem* pContentLayoutItem,
472     XFA_ItemLayoutProcessorResult eStatus) {
473   if (pContentLayoutItem) {
474     GetCurrentContainerRecord()->pCurContentArea->AddChild(pContentLayoutItem);
475     m_bCreateOverFlowPage = false;
476   }
477 
478   if (eStatus != XFA_ItemLayoutProcessorResult::Done) {
479     if (eStatus == XFA_ItemLayoutProcessorResult::PageFullBreak &&
480         m_CurrentContainerRecordIter == GetTailPosition()) {
481       AppendNewPage();
482     }
483     m_CurrentContainerRecordIter = GetTailPosition();
484     m_pCurPageArea = GetCurrentContainerRecord()->pCurPageArea->m_pFormNode;
485   }
486 }
487 
GetAvailHeight()488 float CXFA_LayoutPageMgr::GetAvailHeight() {
489   CXFA_ContainerLayoutItem* pLayoutItem =
490       GetCurrentContainerRecord()->pCurContentArea;
491   if (!pLayoutItem || !pLayoutItem->m_pFormNode)
492     return 0.0f;
493 
494   float fAvailHeight = pLayoutItem->m_pFormNode->JSObject()
495                            ->GetMeasure(XFA_Attribute::H)
496                            .ToUnit(XFA_Unit::Pt);
497   if (fAvailHeight >= XFA_LAYOUT_FLOAT_PERCISION)
498     return fAvailHeight;
499   if (m_CurrentContainerRecordIter == m_ProposedContainerRecords.begin())
500     return 0.0f;
501   return FLT_MAX;
502 }
503 
CreateContainerRecord(CXFA_Node * pPageNode,bool bCreateNew)504 CXFA_ContainerRecord* CXFA_LayoutPageMgr::CreateContainerRecord(
505     CXFA_Node* pPageNode,
506     bool bCreateNew) {
507   CXFA_ContainerRecord* pNewRecord = new CXFA_ContainerRecord();
508   if (m_CurrentContainerRecordIter != m_ProposedContainerRecords.end()) {
509     if (!IsPageSetRootOrderedOccurrence() || !pPageNode) {
510       *pNewRecord = *GetCurrentContainerRecord();
511       m_ProposedContainerRecords.push_back(pNewRecord);
512       return pNewRecord;
513     }
514     CXFA_Node* pPageSet = pPageNode->GetParent();
515     if (!bCreateNew) {
516       if (pPageSet == m_pTemplatePageSetRoot) {
517         pNewRecord->pCurPageSet = m_pPageSetCurRoot;
518       } else {
519         CXFA_ContainerLayoutItem* pParentLayoutItem =
520             static_cast<CXFA_ContainerLayoutItem*>(
521                 pPageSet->JSObject()->GetLayoutItem());
522         if (!pParentLayoutItem)
523           pParentLayoutItem = m_pPageSetCurRoot;
524 
525         pNewRecord->pCurPageSet = pParentLayoutItem;
526       }
527     } else {
528       CXFA_ContainerLayoutItem* pParentPageSetLayout = nullptr;
529       if (pPageSet == GetCurrentContainerRecord()->pCurPageSet->m_pFormNode) {
530         pParentPageSetLayout = static_cast<CXFA_ContainerLayoutItem*>(
531             GetCurrentContainerRecord()->pCurPageSet->m_pParent);
532       } else {
533         pParentPageSetLayout = static_cast<CXFA_ContainerLayoutItem*>(
534             pPageSet->GetParent()->JSObject()->GetLayoutItem());
535       }
536       CXFA_ContainerLayoutItem* pPageSetLayoutItem =
537           new CXFA_ContainerLayoutItem(pPageSet);
538       pPageSet->JSObject()->SetLayoutItem(pPageSetLayoutItem);
539       if (!pParentPageSetLayout) {
540         CXFA_ContainerLayoutItem* pPrePageSet = m_pPageSetLayoutItemRoot;
541         while (pPrePageSet->m_pNextSibling) {
542           pPrePageSet = static_cast<CXFA_ContainerLayoutItem*>(
543               pPrePageSet->m_pNextSibling);
544         }
545 
546         pPrePageSet->m_pNextSibling = pPageSetLayoutItem;
547         m_pPageSetCurRoot = pPageSetLayoutItem;
548       } else {
549         pParentPageSetLayout->AddChild(pPageSetLayoutItem);
550       }
551       pNewRecord->pCurPageSet = pPageSetLayoutItem;
552     }
553   } else {
554     if (pPageNode) {
555       CXFA_Node* pPageSet = pPageNode->GetParent();
556       if (pPageSet == m_pTemplatePageSetRoot) {
557         pNewRecord->pCurPageSet = m_pPageSetLayoutItemRoot;
558       } else {
559         CXFA_ContainerLayoutItem* pPageSetLayoutItem =
560             new CXFA_ContainerLayoutItem(pPageSet);
561         pPageSet->JSObject()->SetLayoutItem(pPageSetLayoutItem);
562         m_pPageSetLayoutItemRoot->AddChild(pPageSetLayoutItem);
563         pNewRecord->pCurPageSet = pPageSetLayoutItem;
564       }
565     } else {
566       pNewRecord->pCurPageSet = m_pPageSetLayoutItemRoot;
567     }
568   }
569   m_ProposedContainerRecords.push_back(pNewRecord);
570   return pNewRecord;
571 }
572 
AddPageAreaLayoutItem(CXFA_ContainerRecord * pNewRecord,CXFA_Node * pNewPageArea)573 void CXFA_LayoutPageMgr::AddPageAreaLayoutItem(CXFA_ContainerRecord* pNewRecord,
574                                                CXFA_Node* pNewPageArea) {
575   CXFA_ContainerLayoutItem* pNewPageAreaLayoutItem = nullptr;
576   if (pdfium::IndexInBounds(m_PageArray, m_nAvailPages)) {
577     CXFA_ContainerLayoutItem* pContainerItem = m_PageArray[m_nAvailPages];
578     pContainerItem->m_pFormNode = pNewPageArea;
579     m_nAvailPages++;
580     pNewPageAreaLayoutItem = pContainerItem;
581   } else {
582     CXFA_FFNotify* pNotify = pNewPageArea->GetDocument()->GetNotify();
583     auto* pContainerItem = pNotify->OnCreateContainerLayoutItem(pNewPageArea);
584     m_PageArray.push_back(pContainerItem);
585     m_nAvailPages++;
586     pNotify->OnPageEvent(pContainerItem, XFA_PAGEVIEWEVENT_PostRemoved);
587     pNewPageAreaLayoutItem = pContainerItem;
588   }
589   pNewRecord->pCurPageSet->AddChild(pNewPageAreaLayoutItem);
590   pNewRecord->pCurPageArea = pNewPageAreaLayoutItem;
591   pNewRecord->pCurContentArea = nullptr;
592 }
593 
AddContentAreaLayoutItem(CXFA_ContainerRecord * pNewRecord,CXFA_Node * pContentArea)594 void CXFA_LayoutPageMgr::AddContentAreaLayoutItem(
595     CXFA_ContainerRecord* pNewRecord,
596     CXFA_Node* pContentArea) {
597   if (!pContentArea) {
598     pNewRecord->pCurContentArea = nullptr;
599     return;
600   }
601   CXFA_ContainerLayoutItem* pNewContentAreaLayoutItem =
602       new CXFA_ContainerLayoutItem(pContentArea);
603   ASSERT(pNewRecord->pCurPageArea);
604   pNewRecord->pCurPageArea->AddChild(pNewContentAreaLayoutItem);
605   pNewRecord->pCurContentArea = pNewContentAreaLayoutItem;
606 }
607 
FinishPaginatedPageSets()608 void CXFA_LayoutPageMgr::FinishPaginatedPageSets() {
609   CXFA_ContainerLayoutItem* pRootPageSetLayoutItem = m_pPageSetLayoutItemRoot;
610   for (; pRootPageSetLayoutItem;
611        pRootPageSetLayoutItem = static_cast<CXFA_ContainerLayoutItem*>(
612            pRootPageSetLayoutItem->m_pNextSibling)) {
613     CXFA_NodeIteratorTemplate<CXFA_ContainerLayoutItem,
614                               PageSetContainerLayoutItem>
615         sIterator(pRootPageSetLayoutItem);
616     for (CXFA_ContainerLayoutItem* pPageSetLayoutItem = sIterator.GetCurrent();
617          pPageSetLayoutItem; pPageSetLayoutItem = sIterator.MoveToNext()) {
618       XFA_AttributeEnum ePageRelation =
619           pPageSetLayoutItem->m_pFormNode->JSObject()->GetEnum(
620               XFA_Attribute::Relation);
621       switch (ePageRelation) {
622         case XFA_AttributeEnum::OrderedOccurrence:
623         default: { ProcessLastPageSet(); } break;
624         case XFA_AttributeEnum::SimplexPaginated:
625         case XFA_AttributeEnum::DuplexPaginated: {
626           CXFA_LayoutItem* pLastPageAreaLayoutItem = nullptr;
627           int32_t nPageAreaCount = 0;
628           for (CXFA_LayoutItem* pPageAreaLayoutItem =
629                    pPageSetLayoutItem->m_pFirstChild;
630                pPageAreaLayoutItem;
631                pPageAreaLayoutItem = pPageAreaLayoutItem->m_pNextSibling) {
632             if (pPageAreaLayoutItem->m_pFormNode->GetElementType() !=
633                 XFA_Element::PageArea) {
634               continue;
635             }
636             nPageAreaCount++;
637             pLastPageAreaLayoutItem = pPageAreaLayoutItem;
638           }
639           if (!pLastPageAreaLayoutItem)
640             break;
641 
642           if (!FindPageAreaFromPageSet_SimplexDuplex(
643                   pPageSetLayoutItem->m_pFormNode, nullptr, nullptr, nullptr,
644                   true, true,
645                   nPageAreaCount == 1 ? XFA_AttributeEnum::Only
646                                       : XFA_AttributeEnum::Last) &&
647               (nPageAreaCount == 1 &&
648                !FindPageAreaFromPageSet_SimplexDuplex(
649                    pPageSetLayoutItem->m_pFormNode, nullptr, nullptr, nullptr,
650                    true, true, XFA_AttributeEnum::Last))) {
651             break;
652           }
653           CXFA_Node* pNode = m_pCurPageArea;
654           XFA_AttributeEnum eCurChoice =
655               pNode->JSObject()->GetEnum(XFA_Attribute::PagePosition);
656           if (eCurChoice == XFA_AttributeEnum::Last) {
657             XFA_AttributeEnum eOddOrEven =
658                 pNode->JSObject()->GetEnum(XFA_Attribute::OddOrEven);
659             XFA_AttributeEnum eLastChoice =
660                 pLastPageAreaLayoutItem->m_pFormNode->JSObject()->GetEnum(
661                     XFA_Attribute::PagePosition);
662             if (eLastChoice == XFA_AttributeEnum::First &&
663                 (ePageRelation == XFA_AttributeEnum::SimplexPaginated ||
664                  eOddOrEven != XFA_AttributeEnum::Odd)) {
665               CXFA_ContainerRecord* pRecord = CreateContainerRecord();
666               AddPageAreaLayoutItem(pRecord, pNode);
667               break;
668             }
669           }
670           bool bUsable = true;
671           std::vector<float> rgUsedHeights;
672           for (CXFA_LayoutItem* pChildLayoutItem =
673                    pLastPageAreaLayoutItem->m_pFirstChild;
674                pChildLayoutItem;
675                pChildLayoutItem = pChildLayoutItem->m_pNextSibling) {
676             if (pChildLayoutItem->m_pFormNode->GetElementType() !=
677                 XFA_Element::ContentArea) {
678               continue;
679             }
680             float fUsedHeight = 0;
681             for (CXFA_LayoutItem* pContentChildLayoutItem =
682                      pChildLayoutItem->m_pFirstChild;
683                  pContentChildLayoutItem;
684                  pContentChildLayoutItem =
685                      pContentChildLayoutItem->m_pNextSibling) {
686               if (CXFA_ContentLayoutItem* pContent =
687                       pContentChildLayoutItem->AsContentLayoutItem()) {
688                 fUsedHeight += pContent->m_sSize.height;
689               }
690             }
691             rgUsedHeights.push_back(fUsedHeight);
692           }
693           int32_t iCurContentAreaIndex = -1;
694           for (CXFA_Node* pContentAreaNode = pNode->GetFirstChild();
695                pContentAreaNode;
696                pContentAreaNode = pContentAreaNode->GetNextSibling()) {
697             if (pContentAreaNode->GetElementType() !=
698                 XFA_Element::ContentArea) {
699               continue;
700             }
701             iCurContentAreaIndex++;
702             if (rgUsedHeights[iCurContentAreaIndex] >
703                 pContentAreaNode->JSObject()
704                         ->GetMeasure(XFA_Attribute::H)
705                         .ToUnit(XFA_Unit::Pt) +
706                     XFA_LAYOUT_FLOAT_PERCISION) {
707               bUsable = false;
708               break;
709             }
710           }
711           if (bUsable) {
712             CXFA_LayoutItem* pChildLayoutItem =
713                 pLastPageAreaLayoutItem->m_pFirstChild;
714             CXFA_Node* pContentAreaNode = pNode->GetFirstChild();
715             pLastPageAreaLayoutItem->m_pFormNode = pNode;
716             while (pChildLayoutItem && pContentAreaNode) {
717               if (pChildLayoutItem->m_pFormNode->GetElementType() !=
718                   XFA_Element::ContentArea) {
719                 pChildLayoutItem = pChildLayoutItem->m_pNextSibling;
720                 continue;
721               }
722               if (pContentAreaNode->GetElementType() !=
723                   XFA_Element::ContentArea) {
724                 pContentAreaNode = pContentAreaNode->GetNextSibling();
725                 continue;
726               }
727               pChildLayoutItem->m_pFormNode = pContentAreaNode;
728               pChildLayoutItem = pChildLayoutItem->m_pNextSibling;
729               pContentAreaNode = pContentAreaNode->GetNextSibling();
730             }
731           } else if (pNode->JSObject()->GetEnum(XFA_Attribute::PagePosition) ==
732                      XFA_AttributeEnum::Last) {
733             CXFA_ContainerRecord* pRecord = CreateContainerRecord();
734             AddPageAreaLayoutItem(pRecord, pNode);
735           }
736         } break;
737       }
738     }
739   }
740 }
741 
GetPageCount() const742 int32_t CXFA_LayoutPageMgr::GetPageCount() const {
743   return pdfium::CollectionSize<int32_t>(m_PageArray);
744 }
745 
GetPage(int32_t index) const746 CXFA_ContainerLayoutItem* CXFA_LayoutPageMgr::GetPage(int32_t index) const {
747   if (!pdfium::IndexInBounds(m_PageArray, index))
748     return nullptr;
749   return m_PageArray[index];
750 }
751 
GetPageIndex(const CXFA_ContainerLayoutItem * pPage) const752 int32_t CXFA_LayoutPageMgr::GetPageIndex(
753     const CXFA_ContainerLayoutItem* pPage) const {
754   auto it = std::find(m_PageArray.begin(), m_PageArray.end(), pPage);
755   return it != m_PageArray.end() ? it - m_PageArray.begin() : -1;
756 }
757 
RunBreak(XFA_Element eBreakType,XFA_AttributeEnum eTargetType,CXFA_Node * pTarget,bool bStartNew)758 bool CXFA_LayoutPageMgr::RunBreak(XFA_Element eBreakType,
759                                   XFA_AttributeEnum eTargetType,
760                                   CXFA_Node* pTarget,
761                                   bool bStartNew) {
762   bool bRet = false;
763   switch (eTargetType) {
764     case XFA_AttributeEnum::ContentArea:
765       if (pTarget && pTarget->GetElementType() != XFA_Element::ContentArea)
766         pTarget = nullptr;
767       if (!pTarget ||
768           m_CurrentContainerRecordIter == m_ProposedContainerRecords.end() ||
769           pTarget !=
770               GetCurrentContainerRecord()->pCurContentArea->m_pFormNode ||
771           bStartNew) {
772         CXFA_Node* pPageArea = nullptr;
773         if (pTarget)
774           pPageArea = pTarget->GetParent();
775 
776         pPageArea = GetNextAvailPageArea(pPageArea, pTarget);
777         bRet = !!pPageArea;
778       }
779       break;
780     case XFA_AttributeEnum::PageArea:
781       if (pTarget && pTarget->GetElementType() != XFA_Element::PageArea)
782         pTarget = nullptr;
783       if (!pTarget ||
784           m_CurrentContainerRecordIter == m_ProposedContainerRecords.end() ||
785           pTarget != GetCurrentContainerRecord()->pCurPageArea->m_pFormNode ||
786           bStartNew) {
787         CXFA_Node* pPageArea = GetNextAvailPageArea(pTarget, nullptr, true);
788         bRet = !!pPageArea;
789       }
790       break;
791     case XFA_AttributeEnum::PageOdd:
792       if (pTarget && pTarget->GetElementType() != XFA_Element::PageArea)
793         pTarget = nullptr;
794       break;
795     case XFA_AttributeEnum::PageEven:
796       if (pTarget && pTarget->GetElementType() != XFA_Element::PageArea)
797         pTarget = nullptr;
798       break;
799     case XFA_AttributeEnum::Auto:
800     default:
801       break;
802   }
803   return bRet;
804 }
805 
ExecuteBreakBeforeOrAfter(CXFA_Node * pCurNode,bool bBefore,CXFA_Node * & pBreakLeaderTemplate,CXFA_Node * & pBreakTrailerTemplate)806 bool CXFA_LayoutPageMgr::ExecuteBreakBeforeOrAfter(
807     CXFA_Node* pCurNode,
808     bool bBefore,
809     CXFA_Node*& pBreakLeaderTemplate,
810     CXFA_Node*& pBreakTrailerTemplate) {
811   XFA_Element eType = pCurNode->GetElementType();
812   switch (eType) {
813     case XFA_Element::BreakBefore:
814     case XFA_Element::BreakAfter: {
815       WideString wsBreakLeader;
816       WideString wsBreakTrailer;
817       CXFA_Node* pFormNode = pCurNode->GetContainerParent();
818       CXFA_Node* pContainer = pFormNode->GetTemplateNodeIfExists();
819       bool bStartNew =
820           pCurNode->JSObject()->GetInteger(XFA_Attribute::StartNew) != 0;
821       CXFA_Script* pScript =
822           pCurNode->GetFirstChildByClass<CXFA_Script>(XFA_Element::Script);
823       if (pScript && !RunBreakTestScript(pScript))
824         return false;
825 
826       WideString wsTarget =
827           pCurNode->JSObject()->GetCData(XFA_Attribute::Target);
828       CXFA_Node* pTarget =
829           ResolveBreakTarget(m_pTemplatePageSetRoot, true, wsTarget);
830       wsBreakTrailer = pCurNode->JSObject()->GetCData(XFA_Attribute::Trailer);
831       wsBreakLeader = pCurNode->JSObject()->GetCData(XFA_Attribute::Leader);
832       pBreakLeaderTemplate =
833           ResolveBreakTarget(pContainer, true, wsBreakLeader);
834       pBreakTrailerTemplate =
835           ResolveBreakTarget(pContainer, true, wsBreakTrailer);
836       if (RunBreak(eType,
837                    pCurNode->JSObject()->GetEnum(XFA_Attribute::TargetType),
838                    pTarget, bStartNew)) {
839         return true;
840       }
841       if (!m_ProposedContainerRecords.empty() &&
842           m_CurrentContainerRecordIter == m_ProposedContainerRecords.begin() &&
843           eType == XFA_Element::BreakBefore) {
844         CXFA_Node* pParentNode = pFormNode->GetContainerParent();
845         if (!pParentNode ||
846             pFormNode != pParentNode->GetFirstContainerChild()) {
847           break;
848         }
849         pParentNode = pParentNode->GetParent();
850         if (!pParentNode ||
851             pParentNode->GetElementType() != XFA_Element::Form) {
852           break;
853         }
854         return true;
855       }
856       break;
857     }
858     case XFA_Element::Break: {
859       bool bStartNew =
860           pCurNode->JSObject()->GetInteger(XFA_Attribute::StartNew) != 0;
861       WideString wsTarget = pCurNode->JSObject()->GetCData(
862           bBefore ? XFA_Attribute::BeforeTarget : XFA_Attribute::AfterTarget);
863       CXFA_Node* pTarget =
864           ResolveBreakTarget(m_pTemplatePageSetRoot, true, wsTarget);
865       if (RunBreak(bBefore ? XFA_Element::BreakBefore : XFA_Element::BreakAfter,
866                    pCurNode->JSObject()->GetEnum(
867                        bBefore ? XFA_Attribute::Before : XFA_Attribute::After),
868                    pTarget, bStartNew)) {
869         return true;
870       }
871       break;
872     }
873     default:
874       break;
875   }
876   return false;
877 }
878 
ProcessBreakBeforeOrAfter(CXFA_Node * pBreakNode,bool bBefore,CXFA_Node * & pBreakLeaderNode,CXFA_Node * & pBreakTrailerNode,bool & bCreatePage)879 bool CXFA_LayoutPageMgr::ProcessBreakBeforeOrAfter(
880     CXFA_Node* pBreakNode,
881     bool bBefore,
882     CXFA_Node*& pBreakLeaderNode,
883     CXFA_Node*& pBreakTrailerNode,
884     bool& bCreatePage) {
885   CXFA_Node* pLeaderTemplate = nullptr;
886   CXFA_Node* pTrailerTemplate = nullptr;
887   CXFA_Node* pFormNode = pBreakNode->GetContainerParent();
888   if (XFA_ItemLayoutProcessor_IsTakingSpace(pFormNode)) {
889     bCreatePage = ExecuteBreakBeforeOrAfter(pBreakNode, bBefore,
890                                             pLeaderTemplate, pTrailerTemplate);
891     CXFA_Document* pDocument = pBreakNode->GetDocument();
892     CXFA_Node* pDataScope = nullptr;
893     pFormNode = pFormNode->GetContainerParent();
894     if (pLeaderTemplate) {
895       if (!pDataScope)
896         pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
897 
898       pBreakLeaderNode = pDocument->DataMerge_CopyContainer(
899           pLeaderTemplate, pFormNode, pDataScope, true, true, true);
900       pDocument->DataMerge_UpdateBindingRelations(pBreakLeaderNode);
901       SetLayoutGeneratedNodeFlag(pBreakLeaderNode);
902     }
903     if (pTrailerTemplate) {
904       if (!pDataScope)
905         pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
906 
907       pBreakTrailerNode = pDocument->DataMerge_CopyContainer(
908           pTrailerTemplate, pFormNode, pDataScope, true, true, true);
909       pDocument->DataMerge_UpdateBindingRelations(pBreakTrailerNode);
910       SetLayoutGeneratedNodeFlag(pBreakTrailerNode);
911     }
912     return true;
913   }
914   return false;
915 }
916 
ProcessBookendLeaderOrTrailer(CXFA_Node * pBookendNode,bool bLeader,CXFA_Node * & pBookendAppendNode)917 bool CXFA_LayoutPageMgr::ProcessBookendLeaderOrTrailer(
918     CXFA_Node* pBookendNode,
919     bool bLeader,
920     CXFA_Node*& pBookendAppendNode) {
921   CXFA_Node* pLeaderTemplate = nullptr;
922   CXFA_Node* pFormNode = pBookendNode->GetContainerParent();
923   if (ResolveBookendLeaderOrTrailer(pBookendNode, bLeader, pLeaderTemplate)) {
924     CXFA_Document* pDocument = pBookendNode->GetDocument();
925     CXFA_Node* pDataScope = nullptr;
926     if (pLeaderTemplate) {
927       if (!pDataScope)
928         pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
929 
930       pBookendAppendNode = pDocument->DataMerge_CopyContainer(
931           pLeaderTemplate, pFormNode, pDataScope, true, true, true);
932       pDocument->DataMerge_UpdateBindingRelations(pBookendAppendNode);
933       SetLayoutGeneratedNodeFlag(pBookendAppendNode);
934       return true;
935     }
936   }
937   return false;
938 }
939 
BreakOverflow(CXFA_Node * pOverflowNode,CXFA_Node * & pLeaderTemplate,CXFA_Node * & pTrailerTemplate,bool bCreatePage)940 CXFA_Node* CXFA_LayoutPageMgr::BreakOverflow(CXFA_Node* pOverflowNode,
941                                              CXFA_Node*& pLeaderTemplate,
942                                              CXFA_Node*& pTrailerTemplate,
943                                              bool bCreatePage) {
944   CXFA_Node* pContainer =
945       pOverflowNode->GetContainerParent()->GetTemplateNodeIfExists();
946   if (pOverflowNode->GetElementType() == XFA_Element::Break) {
947     WideString wsOverflowLeader =
948         pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowLeader);
949     WideString wsOverflowTarget =
950         pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowTarget);
951     WideString wsOverflowTrailer =
952         pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowTrailer);
953     if (wsOverflowTarget.IsEmpty() && wsOverflowLeader.IsEmpty() &&
954         wsOverflowTrailer.IsEmpty()) {
955       return nullptr;
956     }
957 
958     if (!wsOverflowTarget.IsEmpty() && bCreatePage && !m_bCreateOverFlowPage) {
959       CXFA_Node* pTarget =
960           ResolveBreakTarget(m_pTemplatePageSetRoot, true, wsOverflowTarget);
961       if (pTarget) {
962         m_bCreateOverFlowPage = true;
963         switch (pTarget->GetElementType()) {
964           case XFA_Element::PageArea:
965             RunBreak(XFA_Element::Overflow, XFA_AttributeEnum::PageArea,
966                      pTarget, true);
967             break;
968           case XFA_Element::ContentArea:
969             RunBreak(XFA_Element::Overflow, XFA_AttributeEnum::ContentArea,
970                      pTarget, true);
971             break;
972           default:
973             break;
974         }
975       }
976     }
977     if (!bCreatePage) {
978       pLeaderTemplate = ResolveBreakTarget(pContainer, true, wsOverflowLeader);
979       pTrailerTemplate =
980           ResolveBreakTarget(pContainer, true, wsOverflowTrailer);
981     }
982     return pOverflowNode;
983   }
984 
985   if (pOverflowNode->GetElementType() != XFA_Element::Overflow)
986     return nullptr;
987 
988   WideString wsOverflowTarget =
989       pOverflowNode->JSObject()->GetCData(XFA_Attribute::Target);
990   if (!wsOverflowTarget.IsEmpty() && bCreatePage && !m_bCreateOverFlowPage) {
991     CXFA_Node* pTarget =
992         ResolveBreakTarget(m_pTemplatePageSetRoot, true, wsOverflowTarget);
993     if (pTarget) {
994       m_bCreateOverFlowPage = true;
995       switch (pTarget->GetElementType()) {
996         case XFA_Element::PageArea:
997           RunBreak(XFA_Element::Overflow, XFA_AttributeEnum::PageArea, pTarget,
998                    true);
999           break;
1000         case XFA_Element::ContentArea:
1001           RunBreak(XFA_Element::Overflow, XFA_AttributeEnum::ContentArea,
1002                    pTarget, true);
1003           break;
1004         default:
1005           break;
1006       }
1007     }
1008   }
1009   if (!bCreatePage) {
1010     WideString wsLeader =
1011         pOverflowNode->JSObject()->GetCData(XFA_Attribute::Leader);
1012     WideString wsTrailer =
1013         pOverflowNode->JSObject()->GetCData(XFA_Attribute::Trailer);
1014     pLeaderTemplate = ResolveBreakTarget(pContainer, true, wsLeader);
1015     pTrailerTemplate = ResolveBreakTarget(pContainer, true, wsTrailer);
1016   }
1017   return pOverflowNode;
1018 }
1019 
ProcessOverflow(CXFA_Node * pFormNode,CXFA_Node * & pLeaderNode,CXFA_Node * & pTrailerNode,bool bDataMerge,bool bCreatePage)1020 bool CXFA_LayoutPageMgr::ProcessOverflow(CXFA_Node* pFormNode,
1021                                          CXFA_Node*& pLeaderNode,
1022                                          CXFA_Node*& pTrailerNode,
1023                                          bool bDataMerge,
1024                                          bool bCreatePage) {
1025   if (!pFormNode)
1026     return false;
1027 
1028   CXFA_Node* pLeaderTemplate = nullptr;
1029   CXFA_Node* pTrailerTemplate = nullptr;
1030   bool bIsOverflowNode = false;
1031   if (pFormNode->GetElementType() == XFA_Element::Overflow ||
1032       pFormNode->GetElementType() == XFA_Element::Break) {
1033     bIsOverflowNode = true;
1034   }
1035   for (CXFA_Node* pCurNode = bIsOverflowNode ? pFormNode
1036                                              : pFormNode->GetFirstChild();
1037        pCurNode; pCurNode = pCurNode->GetNextSibling()) {
1038     if (BreakOverflow(pCurNode, pLeaderTemplate, pTrailerTemplate,
1039                       bCreatePage)) {
1040       if (bIsOverflowNode)
1041         pFormNode = pCurNode->GetParent();
1042 
1043       CXFA_Document* pDocument = pCurNode->GetDocument();
1044       CXFA_Node* pDataScope = nullptr;
1045       if (pLeaderTemplate) {
1046         if (!pDataScope)
1047           pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
1048 
1049         pLeaderNode = pDocument->DataMerge_CopyContainer(
1050             pLeaderTemplate, pFormNode, pDataScope, true, true, true);
1051         pDocument->DataMerge_UpdateBindingRelations(pLeaderNode);
1052         SetLayoutGeneratedNodeFlag(pLeaderNode);
1053       }
1054       if (pTrailerTemplate) {
1055         if (!pDataScope)
1056           pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
1057 
1058         pTrailerNode = pDocument->DataMerge_CopyContainer(
1059             pTrailerTemplate, pFormNode, pDataScope, true, true, true);
1060         pDocument->DataMerge_UpdateBindingRelations(pTrailerNode);
1061         SetLayoutGeneratedNodeFlag(pTrailerNode);
1062       }
1063       return true;
1064     }
1065     if (bIsOverflowNode) {
1066       break;
1067     }
1068   }
1069   return false;
1070 }
1071 
ResolveBookendLeaderOrTrailer(CXFA_Node * pBookendNode,bool bLeader,CXFA_Node * & pBookendAppendTemplate)1072 bool CXFA_LayoutPageMgr::ResolveBookendLeaderOrTrailer(
1073     CXFA_Node* pBookendNode,
1074     bool bLeader,
1075     CXFA_Node*& pBookendAppendTemplate) {
1076   CXFA_Node* pContainer =
1077       pBookendNode->GetContainerParent()->GetTemplateNodeIfExists();
1078   if (pBookendNode->GetElementType() == XFA_Element::Break) {
1079     WideString leader = pBookendNode->JSObject()->GetCData(
1080         bLeader ? XFA_Attribute::BookendLeader : XFA_Attribute::BookendTrailer);
1081     if (!leader.IsEmpty()) {
1082       pBookendAppendTemplate = ResolveBreakTarget(pContainer, false, leader);
1083       return true;
1084     }
1085     return false;
1086   }
1087 
1088   if (pBookendNode->GetElementType() == XFA_Element::Bookend) {
1089     WideString leader = pBookendNode->JSObject()->GetCData(
1090         bLeader ? XFA_Attribute::Leader : XFA_Attribute::Trailer);
1091     pBookendAppendTemplate = ResolveBreakTarget(pContainer, true, leader);
1092     return true;
1093   }
1094   return false;
1095 }
1096 
FindPageAreaFromPageSet(CXFA_Node * pPageSet,CXFA_Node * pStartChild,CXFA_Node * pTargetPageArea,CXFA_Node * pTargetContentArea,bool bNewPage,bool bQuery)1097 bool CXFA_LayoutPageMgr::FindPageAreaFromPageSet(CXFA_Node* pPageSet,
1098                                                  CXFA_Node* pStartChild,
1099                                                  CXFA_Node* pTargetPageArea,
1100                                                  CXFA_Node* pTargetContentArea,
1101                                                  bool bNewPage,
1102                                                  bool bQuery) {
1103   if (!pPageSet && !pStartChild)
1104     return false;
1105 
1106   if (IsPageSetRootOrderedOccurrence()) {
1107     return FindPageAreaFromPageSet_Ordered(pPageSet, pStartChild,
1108                                            pTargetPageArea, pTargetContentArea,
1109                                            bNewPage, bQuery);
1110   }
1111   XFA_AttributeEnum ePreferredPosition =
1112       m_CurrentContainerRecordIter != m_ProposedContainerRecords.end()
1113           ? XFA_AttributeEnum::Rest
1114           : XFA_AttributeEnum::First;
1115   return FindPageAreaFromPageSet_SimplexDuplex(
1116       pPageSet, pStartChild, pTargetPageArea, pTargetContentArea, bNewPage,
1117       bQuery, ePreferredPosition);
1118 }
1119 
FindPageAreaFromPageSet_Ordered(CXFA_Node * pPageSet,CXFA_Node * pStartChild,CXFA_Node * pTargetPageArea,CXFA_Node * pTargetContentArea,bool bNewPage,bool bQuery)1120 bool CXFA_LayoutPageMgr::FindPageAreaFromPageSet_Ordered(
1121     CXFA_Node* pPageSet,
1122     CXFA_Node* pStartChild,
1123     CXFA_Node* pTargetPageArea,
1124     CXFA_Node* pTargetContentArea,
1125     bool bNewPage,
1126     bool bQuery) {
1127   int32_t iPageSetCount = 0;
1128   if (!pStartChild && !bQuery) {
1129     auto it = m_pPageSetMap.find(pPageSet);
1130     if (it != m_pPageSetMap.end())
1131       iPageSetCount = it->second;
1132     int32_t iMax = -1;
1133     CXFA_Node* pOccurNode =
1134         pPageSet->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1135     if (pOccurNode) {
1136       Optional<int32_t> ret =
1137           pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
1138       if (ret)
1139         iMax = *ret;
1140     }
1141     if (iMax >= 0 && iMax <= iPageSetCount)
1142       return false;
1143   }
1144 
1145   bool bRes = false;
1146   CXFA_Node* pCurrentNode =
1147       pStartChild ? pStartChild->GetNextSibling() : pPageSet->GetFirstChild();
1148   for (; pCurrentNode; pCurrentNode = pCurrentNode->GetNextSibling()) {
1149     if (pCurrentNode->GetElementType() == XFA_Element::PageArea) {
1150       if ((pTargetPageArea == pCurrentNode || !pTargetPageArea)) {
1151         if (!pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1152                 XFA_Element::ContentArea)) {
1153           if (pTargetPageArea == pCurrentNode) {
1154             CreateMinPageRecord(pCurrentNode, true);
1155             pTargetPageArea = nullptr;
1156           }
1157           continue;
1158         }
1159         if (!bQuery) {
1160           CXFA_ContainerRecord* pNewRecord =
1161               CreateContainerRecord(pCurrentNode, !pStartChild);
1162           AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
1163           if (!pTargetContentArea) {
1164             pTargetContentArea =
1165                 pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1166                     XFA_Element::ContentArea);
1167           }
1168           AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
1169         }
1170         m_pCurPageArea = pCurrentNode;
1171         m_nCurPageCount = 1;
1172         bRes = true;
1173         break;
1174       }
1175       if (!bQuery)
1176         CreateMinPageRecord(pCurrentNode, false);
1177     } else if (pCurrentNode->GetElementType() == XFA_Element::PageSet) {
1178       if (FindPageAreaFromPageSet_Ordered(pCurrentNode, nullptr,
1179                                           pTargetPageArea, pTargetContentArea,
1180                                           bNewPage, bQuery)) {
1181         bRes = true;
1182         break;
1183       }
1184       if (!bQuery)
1185         CreateMinPageSetRecord(pCurrentNode, true);
1186     }
1187   }
1188   if (!pStartChild && bRes && !bQuery)
1189     m_pPageSetMap[pPageSet] = ++iPageSetCount;
1190   return bRes;
1191 }
1192 
FindPageAreaFromPageSet_SimplexDuplex(CXFA_Node * pPageSet,CXFA_Node * pStartChild,CXFA_Node * pTargetPageArea,CXFA_Node * pTargetContentArea,bool bNewPage,bool bQuery,XFA_AttributeEnum ePreferredPosition)1193 bool CXFA_LayoutPageMgr::FindPageAreaFromPageSet_SimplexDuplex(
1194     CXFA_Node* pPageSet,
1195     CXFA_Node* pStartChild,
1196     CXFA_Node* pTargetPageArea,
1197     CXFA_Node* pTargetContentArea,
1198     bool bNewPage,
1199     bool bQuery,
1200     XFA_AttributeEnum ePreferredPosition) {
1201   const XFA_AttributeEnum eFallbackPosition = XFA_AttributeEnum::Any;
1202   CXFA_Node* pPreferredPageArea = nullptr;
1203   CXFA_Node* pFallbackPageArea = nullptr;
1204   CXFA_Node* pCurrentNode = nullptr;
1205   if (!pStartChild || pStartChild->GetElementType() == XFA_Element::PageArea)
1206     pCurrentNode = pPageSet->GetFirstChild();
1207   else
1208     pCurrentNode = pStartChild->GetNextSibling();
1209 
1210   for (; pCurrentNode; pCurrentNode = pCurrentNode->GetNextSibling()) {
1211     if (pCurrentNode->GetElementType() == XFA_Element::PageArea) {
1212       if (!MatchPageAreaOddOrEven(pCurrentNode))
1213         continue;
1214 
1215       XFA_AttributeEnum eCurPagePosition =
1216           pCurrentNode->JSObject()->GetEnum(XFA_Attribute::PagePosition);
1217       if (ePreferredPosition == XFA_AttributeEnum::Last) {
1218         if (eCurPagePosition != ePreferredPosition)
1219           continue;
1220         if (m_ePageSetMode == XFA_AttributeEnum::SimplexPaginated ||
1221             pCurrentNode->JSObject()->GetEnum(XFA_Attribute::OddOrEven) ==
1222                 XFA_AttributeEnum::Any) {
1223           pPreferredPageArea = pCurrentNode;
1224           break;
1225         }
1226         CXFA_ContainerRecord* pNewRecord = CreateContainerRecord();
1227         AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
1228         AddContentAreaLayoutItem(
1229             pNewRecord, pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1230                             XFA_Element::ContentArea));
1231         pPreferredPageArea = pCurrentNode;
1232         return false;
1233       }
1234       if (ePreferredPosition == XFA_AttributeEnum::Only) {
1235         if (eCurPagePosition != ePreferredPosition)
1236           continue;
1237         if (m_ePageSetMode != XFA_AttributeEnum::DuplexPaginated ||
1238             pCurrentNode->JSObject()->GetEnum(XFA_Attribute::OddOrEven) ==
1239                 XFA_AttributeEnum::Any) {
1240           pPreferredPageArea = pCurrentNode;
1241           break;
1242         }
1243         return false;
1244       }
1245       if ((pTargetPageArea == pCurrentNode || !pTargetPageArea)) {
1246         if (!pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1247                 XFA_Element::ContentArea)) {
1248           if (pTargetPageArea == pCurrentNode) {
1249             CXFA_ContainerRecord* pNewRecord = CreateContainerRecord();
1250             AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
1251             pTargetPageArea = nullptr;
1252           }
1253           continue;
1254         }
1255         if ((ePreferredPosition == XFA_AttributeEnum::Rest &&
1256              eCurPagePosition == XFA_AttributeEnum::Any) ||
1257             eCurPagePosition == ePreferredPosition) {
1258           pPreferredPageArea = pCurrentNode;
1259           break;
1260         }
1261         if (eCurPagePosition == eFallbackPosition && !pFallbackPageArea) {
1262           pFallbackPageArea = pCurrentNode;
1263         }
1264       } else if (pTargetPageArea && !MatchPageAreaOddOrEven(pTargetPageArea)) {
1265         CXFA_ContainerRecord* pNewRecord = CreateContainerRecord();
1266         AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
1267         AddContentAreaLayoutItem(
1268             pNewRecord, pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1269                             XFA_Element::ContentArea));
1270       }
1271     } else if (pCurrentNode->GetElementType() == XFA_Element::PageSet) {
1272       if (FindPageAreaFromPageSet_SimplexDuplex(
1273               pCurrentNode, nullptr, pTargetPageArea, pTargetContentArea,
1274               bNewPage, bQuery, ePreferredPosition)) {
1275         break;
1276       }
1277     }
1278   }
1279 
1280   CXFA_Node* pCurPageArea = nullptr;
1281   if (pPreferredPageArea)
1282     pCurPageArea = pPreferredPageArea;
1283   else if (pFallbackPageArea)
1284     pCurPageArea = pFallbackPageArea;
1285 
1286   if (!pCurPageArea)
1287     return false;
1288 
1289   if (!bQuery) {
1290     CXFA_ContainerRecord* pNewRecord = CreateContainerRecord();
1291     AddPageAreaLayoutItem(pNewRecord, pCurPageArea);
1292     if (!pTargetContentArea) {
1293       pTargetContentArea = pCurPageArea->GetFirstChildByClass<CXFA_ContentArea>(
1294           XFA_Element::ContentArea);
1295     }
1296     AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
1297   }
1298   m_pCurPageArea = pCurPageArea;
1299   return true;
1300 }
1301 
MatchPageAreaOddOrEven(CXFA_Node * pPageArea)1302 bool CXFA_LayoutPageMgr::MatchPageAreaOddOrEven(CXFA_Node* pPageArea) {
1303   if (m_ePageSetMode != XFA_AttributeEnum::DuplexPaginated)
1304     return true;
1305 
1306   Optional<XFA_AttributeEnum> ret =
1307       pPageArea->JSObject()->TryEnum(XFA_Attribute::OddOrEven, true);
1308   if (!ret || *ret == XFA_AttributeEnum::Any)
1309     return true;
1310 
1311   int32_t iPageLast = GetPageCount() % 2;
1312   return *ret == XFA_AttributeEnum::Odd ? iPageLast == 0 : iPageLast == 1;
1313 }
1314 
GetNextAvailPageArea(CXFA_Node * pTargetPageArea,CXFA_Node * pTargetContentArea,bool bNewPage,bool bQuery)1315 CXFA_Node* CXFA_LayoutPageMgr::GetNextAvailPageArea(
1316     CXFA_Node* pTargetPageArea,
1317     CXFA_Node* pTargetContentArea,
1318     bool bNewPage,
1319     bool bQuery) {
1320   if (!m_pCurPageArea) {
1321     FindPageAreaFromPageSet(m_pTemplatePageSetRoot, nullptr, pTargetPageArea,
1322                             pTargetContentArea, bNewPage, bQuery);
1323     ASSERT(m_pCurPageArea);
1324     return m_pCurPageArea;
1325   }
1326 
1327   if (!pTargetPageArea || pTargetPageArea == m_pCurPageArea) {
1328     if (!bNewPage && GetNextContentArea(pTargetContentArea))
1329       return m_pCurPageArea;
1330 
1331     if (IsPageSetRootOrderedOccurrence()) {
1332       int32_t iMax = -1;
1333       CXFA_Node* pOccurNode =
1334           m_pCurPageArea->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1335       if (pOccurNode) {
1336         Optional<int32_t> ret =
1337             pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
1338         if (ret)
1339           iMax = *ret;
1340       }
1341       if ((iMax < 0 || m_nCurPageCount < iMax)) {
1342         if (!bQuery) {
1343           CXFA_ContainerRecord* pNewRecord =
1344               CreateContainerRecord(m_pCurPageArea);
1345           AddPageAreaLayoutItem(pNewRecord, m_pCurPageArea);
1346           if (!pTargetContentArea) {
1347             pTargetContentArea =
1348                 m_pCurPageArea->GetFirstChildByClass<CXFA_ContentArea>(
1349                     XFA_Element::ContentArea);
1350           }
1351           AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
1352         }
1353         m_nCurPageCount++;
1354         return m_pCurPageArea;
1355       }
1356     }
1357   }
1358 
1359   if (!bQuery && IsPageSetRootOrderedOccurrence())
1360     CreateMinPageRecord(m_pCurPageArea, false, true);
1361   if (FindPageAreaFromPageSet(m_pCurPageArea->GetParent(), m_pCurPageArea,
1362                               pTargetPageArea, pTargetContentArea, bNewPage,
1363                               bQuery)) {
1364     return m_pCurPageArea;
1365   }
1366 
1367   CXFA_Node* pPageSet = m_pCurPageArea->GetParent();
1368   while (true) {
1369     if (FindPageAreaFromPageSet(pPageSet, nullptr, pTargetPageArea,
1370                                 pTargetContentArea, bNewPage, bQuery)) {
1371       return m_pCurPageArea;
1372     }
1373     if (!bQuery && IsPageSetRootOrderedOccurrence())
1374       CreateMinPageSetRecord(pPageSet);
1375     if (FindPageAreaFromPageSet(nullptr, pPageSet, pTargetPageArea,
1376                                 pTargetContentArea, bNewPage, bQuery)) {
1377       return m_pCurPageArea;
1378     }
1379     if (pPageSet == m_pTemplatePageSetRoot)
1380       break;
1381 
1382     pPageSet = pPageSet->GetParent();
1383   }
1384   return nullptr;
1385 }
1386 
GetNextContentArea(CXFA_Node * pContentArea)1387 bool CXFA_LayoutPageMgr::GetNextContentArea(CXFA_Node* pContentArea) {
1388   CXFA_Node* pCurContentNode =
1389       GetCurrentContainerRecord()->pCurContentArea->m_pFormNode;
1390   if (!pContentArea) {
1391     pContentArea = pCurContentNode->GetNextSameClassSibling<CXFA_ContentArea>(
1392         XFA_Element::ContentArea);
1393     if (!pContentArea)
1394       return false;
1395   } else {
1396     if (pContentArea->GetParent() != m_pCurPageArea)
1397       return false;
1398 
1399     CXFA_ContainerLayoutItem* pContentAreaLayout = nullptr;
1400     if (!CheckContentAreaNotUsed(GetCurrentContainerRecord()->pCurPageArea,
1401                                  pContentArea, pContentAreaLayout)) {
1402       return false;
1403     }
1404     if (pContentAreaLayout) {
1405       if (pContentAreaLayout->m_pFormNode != pCurContentNode) {
1406         CXFA_ContainerRecord* pNewRecord = CreateContainerRecord();
1407         pNewRecord->pCurContentArea = pContentAreaLayout;
1408         return true;
1409       }
1410       return false;
1411     }
1412   }
1413 
1414   CXFA_ContainerRecord* pNewRecord = CreateContainerRecord();
1415   AddContentAreaLayoutItem(pNewRecord, pContentArea);
1416   return true;
1417 }
1418 
InitPageSetMap()1419 void CXFA_LayoutPageMgr::InitPageSetMap() {
1420   if (!IsPageSetRootOrderedOccurrence())
1421     return;
1422 
1423   CXFA_NodeIterator sIterator(m_pTemplatePageSetRoot);
1424   for (CXFA_Node* pPageSetNode = sIterator.GetCurrent(); pPageSetNode;
1425        pPageSetNode = sIterator.MoveToNext()) {
1426     if (pPageSetNode->GetElementType() == XFA_Element::PageSet) {
1427       XFA_AttributeEnum eRelation =
1428           pPageSetNode->JSObject()->GetEnum(XFA_Attribute::Relation);
1429       if (eRelation == XFA_AttributeEnum::OrderedOccurrence)
1430         m_pPageSetMap[pPageSetNode] = 0;
1431     }
1432   }
1433 }
1434 
CreateMinPageRecord(CXFA_Node * pPageArea,bool bTargetPageArea,bool bCreateLast)1435 int32_t CXFA_LayoutPageMgr::CreateMinPageRecord(CXFA_Node* pPageArea,
1436                                                 bool bTargetPageArea,
1437                                                 bool bCreateLast) {
1438   if (!pPageArea)
1439     return 0;
1440 
1441   int32_t iMin = 0;
1442   Optional<int32_t> ret;
1443   CXFA_Node* pOccurNode =
1444       pPageArea->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1445   if (pOccurNode) {
1446     ret = pOccurNode->JSObject()->TryInteger(XFA_Attribute::Min, false);
1447     if (ret)
1448       iMin = *ret;
1449   }
1450 
1451   if (!ret && !bTargetPageArea)
1452     return iMin;
1453 
1454   CXFA_Node* pContentArea = pPageArea->GetFirstChildByClass<CXFA_ContentArea>(
1455       XFA_Element::ContentArea);
1456   if (iMin < 1 && bTargetPageArea && !pContentArea)
1457     iMin = 1;
1458 
1459   int32_t i = 0;
1460   if (bCreateLast)
1461     i = m_nCurPageCount;
1462 
1463   for (; i < iMin; i++) {
1464     CXFA_ContainerRecord* pNewRecord = CreateContainerRecord();
1465     AddPageAreaLayoutItem(pNewRecord, pPageArea);
1466     AddContentAreaLayoutItem(pNewRecord, pContentArea);
1467   }
1468   return iMin;
1469 }
1470 
CreateMinPageSetRecord(CXFA_Node * pPageSet,bool bCreateAll)1471 void CXFA_LayoutPageMgr::CreateMinPageSetRecord(CXFA_Node* pPageSet,
1472                                                 bool bCreateAll) {
1473   if (!pPageSet)
1474     return;
1475 
1476   auto it = m_pPageSetMap.find(pPageSet);
1477   if (it == m_pPageSetMap.end())
1478     return;
1479 
1480   int32_t iCurSetCount = it->second;
1481   if (bCreateAll)
1482     iCurSetCount = 0;
1483 
1484   CXFA_Node* pOccurNode =
1485       pPageSet->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1486   if (!pOccurNode)
1487     return;
1488 
1489   Optional<int32_t> iMin =
1490       pOccurNode->JSObject()->TryInteger(XFA_Attribute::Min, false);
1491   if (!iMin || iCurSetCount >= *iMin)
1492     return;
1493 
1494   for (int32_t i = 0; i < *iMin - iCurSetCount; i++) {
1495     for (CXFA_Node* node = pPageSet->GetFirstChild(); node;
1496          node = node->GetNextSibling()) {
1497       if (node->GetElementType() == XFA_Element::PageArea)
1498         CreateMinPageRecord(node, false);
1499       else if (node->GetElementType() == XFA_Element::PageSet)
1500         CreateMinPageSetRecord(node, true);
1501     }
1502   }
1503   m_pPageSetMap[pPageSet] = *iMin;
1504 }
1505 
CreateNextMinRecord(CXFA_Node * pRecordNode)1506 void CXFA_LayoutPageMgr::CreateNextMinRecord(CXFA_Node* pRecordNode) {
1507   if (!pRecordNode)
1508     return;
1509 
1510   for (CXFA_Node* pCurrentNode = pRecordNode->GetNextSibling(); pCurrentNode;
1511        pCurrentNode = pCurrentNode->GetNextSibling()) {
1512     if (pCurrentNode->GetElementType() == XFA_Element::PageArea)
1513       CreateMinPageRecord(pCurrentNode, false);
1514     else if (pCurrentNode->GetElementType() == XFA_Element::PageSet)
1515       CreateMinPageSetRecord(pCurrentNode, true);
1516   }
1517 }
1518 
ProcessLastPageSet()1519 void CXFA_LayoutPageMgr::ProcessLastPageSet() {
1520   CreateMinPageRecord(m_pCurPageArea, false, true);
1521   CreateNextMinRecord(m_pCurPageArea);
1522   CXFA_Node* pPageSet = m_pCurPageArea->GetParent();
1523   while (true) {
1524     CreateMinPageSetRecord(pPageSet);
1525     if (pPageSet == m_pTemplatePageSetRoot)
1526       break;
1527 
1528     CreateNextMinRecord(pPageSet);
1529     pPageSet = pPageSet->GetParent();
1530   }
1531 }
1532 
GetNextAvailContentHeight(float fChildHeight)1533 bool CXFA_LayoutPageMgr::GetNextAvailContentHeight(float fChildHeight) {
1534   CXFA_Node* pCurContentNode =
1535       GetCurrentContainerRecord()->pCurContentArea->m_pFormNode;
1536   if (!pCurContentNode)
1537     return false;
1538 
1539   pCurContentNode = pCurContentNode->GetNextSameClassSibling<CXFA_ContentArea>(
1540       XFA_Element::ContentArea);
1541   if (pCurContentNode) {
1542     float fNextContentHeight = pCurContentNode->JSObject()
1543                                    ->GetMeasure(XFA_Attribute::H)
1544                                    .ToUnit(XFA_Unit::Pt);
1545     return fNextContentHeight > fChildHeight;
1546   }
1547 
1548   CXFA_Node* pPageNode = GetCurrentContainerRecord()->pCurPageArea->m_pFormNode;
1549   CXFA_Node* pOccurNode =
1550       pPageNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1551   int32_t iMax = 0;
1552   Optional<int32_t> ret;
1553   if (pOccurNode) {
1554     ret = pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
1555     if (ret)
1556       iMax = *ret;
1557   }
1558   if (ret) {
1559     if (m_nCurPageCount == iMax) {
1560       CXFA_Node* pSrcPage = m_pCurPageArea;
1561       int32_t nSrcPageCount = m_nCurPageCount;
1562       auto psSrcIter = GetTailPosition();
1563       CXFA_Node* pNextPage =
1564           GetNextAvailPageArea(nullptr, nullptr, false, true);
1565       m_pCurPageArea = pSrcPage;
1566       m_nCurPageCount = nSrcPageCount;
1567       CXFA_ContainerRecord* pPrevRecord = *psSrcIter++;
1568       while (psSrcIter != m_ProposedContainerRecords.end()) {
1569         auto psSaveIter = psSrcIter;
1570         CXFA_ContainerRecord* pInsertRecord = *psSrcIter++;
1571         RemoveLayoutRecord(pInsertRecord, pPrevRecord);
1572         delete pInsertRecord;
1573         m_ProposedContainerRecords.erase(psSaveIter);
1574       }
1575       if (pNextPage) {
1576         CXFA_Node* pContentArea =
1577             pNextPage->GetFirstChildByClass<CXFA_ContentArea>(
1578                 XFA_Element::ContentArea);
1579         if (pContentArea) {
1580           float fNextContentHeight = pContentArea->JSObject()
1581                                          ->GetMeasure(XFA_Attribute::H)
1582                                          .ToUnit(XFA_Unit::Pt);
1583           if (fNextContentHeight > fChildHeight)
1584             return true;
1585         }
1586       }
1587       return false;
1588     }
1589   }
1590 
1591   CXFA_Node* pContentArea = pPageNode->GetFirstChildByClass<CXFA_ContentArea>(
1592       XFA_Element::ContentArea);
1593   float fNextContentHeight = pContentArea->JSObject()
1594                                  ->GetMeasure(XFA_Attribute::H)
1595                                  .ToUnit(XFA_Unit::Pt);
1596   if (fNextContentHeight < XFA_LAYOUT_FLOAT_PERCISION)
1597     return true;
1598   if (fNextContentHeight > fChildHeight)
1599     return true;
1600   return false;
1601 }
1602 
ClearData()1603 void CXFA_LayoutPageMgr::ClearData() {
1604   if (!m_pTemplatePageSetRoot)
1605     return;
1606 
1607   auto sPos = m_ProposedContainerRecords.begin();
1608   while (sPos != m_ProposedContainerRecords.end()) {
1609     CXFA_ContainerRecord* pRecord = *sPos++;
1610     delete pRecord;
1611   }
1612   m_ProposedContainerRecords.clear();
1613   m_CurrentContainerRecordIter = m_ProposedContainerRecords.end();
1614   m_pCurPageArea = nullptr;
1615   m_nCurPageCount = 0;
1616   m_bCreateOverFlowPage = false;
1617   m_pPageSetMap.clear();
1618 }
1619 
SaveLayoutItem(CXFA_LayoutItem * pParentLayoutItem)1620 void CXFA_LayoutPageMgr::SaveLayoutItem(CXFA_LayoutItem* pParentLayoutItem) {
1621   CXFA_LayoutItem* pNextLayoutItem;
1622   CXFA_LayoutItem* pCurLayoutItem = pParentLayoutItem->m_pFirstChild;
1623   while (pCurLayoutItem) {
1624     pNextLayoutItem = pCurLayoutItem->m_pNextSibling;
1625     if (pCurLayoutItem->IsContentLayoutItem()) {
1626       if (pCurLayoutItem->m_pFormNode->HasRemovedChildren()) {
1627         CXFA_FFNotify* pNotify =
1628             m_pTemplatePageSetRoot->GetDocument()->GetNotify();
1629         CXFA_LayoutProcessor* pDocLayout =
1630             m_pTemplatePageSetRoot->GetDocument()->GetDocLayout();
1631         if (pCurLayoutItem->m_pFirstChild)
1632           SyncRemoveLayoutItem(pCurLayoutItem, pNotify, pDocLayout);
1633 
1634         pNotify->OnLayoutItemRemoving(pDocLayout, pCurLayoutItem);
1635         delete pCurLayoutItem;
1636         pCurLayoutItem = pNextLayoutItem;
1637         continue;
1638       }
1639 
1640       if (pCurLayoutItem->m_pFormNode->IsLayoutGeneratedNode()) {
1641         CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
1642             sIterator(pCurLayoutItem->m_pFormNode);
1643         for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
1644              pNode = sIterator.MoveToNext()) {
1645           pNode->SetFlag(XFA_NodeFlag_UnusedNode, false);
1646         }
1647       }
1648     }
1649 
1650     if (pCurLayoutItem->m_pFirstChild)
1651       SaveLayoutItem(pCurLayoutItem);
1652 
1653     pCurLayoutItem->m_pParent = nullptr;
1654     pCurLayoutItem->m_pNextSibling = nullptr;
1655     pCurLayoutItem->m_pFirstChild = nullptr;
1656     if (!pCurLayoutItem->IsContentLayoutItem() &&
1657         pCurLayoutItem->m_pFormNode->GetElementType() !=
1658             XFA_Element::PageArea) {
1659       delete pCurLayoutItem;
1660     }
1661     pCurLayoutItem = pNextLayoutItem;
1662   }
1663 }
1664 
QueryOverflow(CXFA_Node * pFormNode)1665 CXFA_Node* CXFA_LayoutPageMgr::QueryOverflow(CXFA_Node* pFormNode) {
1666   for (CXFA_Node* pCurNode = pFormNode->GetFirstChild(); pCurNode;
1667        pCurNode = pCurNode->GetNextSibling()) {
1668     if (pCurNode->GetElementType() == XFA_Element::Break) {
1669       WideString wsOverflowLeader =
1670           pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowLeader);
1671       WideString wsOverflowTarget =
1672           pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowTarget);
1673       WideString wsOverflowTrailer =
1674           pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowTrailer);
1675 
1676       if (!wsOverflowLeader.IsEmpty() || !wsOverflowTrailer.IsEmpty() ||
1677           !wsOverflowTarget.IsEmpty()) {
1678         return pCurNode;
1679       }
1680       return nullptr;
1681     }
1682     if (pCurNode->GetElementType() == XFA_Element::Overflow)
1683       return pCurNode;
1684   }
1685   return nullptr;
1686 }
1687 
MergePageSetContents()1688 void CXFA_LayoutPageMgr::MergePageSetContents() {
1689   CXFA_Document* pDocument = m_pTemplatePageSetRoot->GetDocument();
1690   CXFA_FFNotify* pNotify = pDocument->GetNotify();
1691   CXFA_LayoutProcessor* pDocLayout = pDocument->GetDocLayout();
1692   CXFA_ContainerLayoutItem* pRootLayout = GetRootLayoutItem();
1693   for (CXFA_Node* pPageNode : pDocument->m_pPendingPageSet) {
1694     CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
1695         sIterator(pPageNode);
1696     for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
1697          pNode = sIterator.MoveToNext()) {
1698       if (pNode->IsContainerNode()) {
1699         CXFA_Node* pBindNode = pNode->GetBindData();
1700         if (pBindNode) {
1701           pBindNode->RemoveBindItem(pNode);
1702           pNode->SetBindingNode(nullptr);
1703         }
1704       }
1705       pNode->SetFlag(XFA_NodeFlag_UnusedNode, true);
1706     }
1707   }
1708 
1709   int32_t iIndex = 0;
1710   for (; pRootLayout; pRootLayout = static_cast<CXFA_ContainerLayoutItem*>(
1711                           pRootLayout->m_pNextSibling)) {
1712     CXFA_Node* pPendingPageSet = nullptr;
1713     CXFA_NodeIteratorTemplate<
1714         CXFA_ContainerLayoutItem,
1715         CXFA_TraverseStrategy_ContentAreaContainerLayoutItem>
1716         iterator(pRootLayout);
1717     CXFA_ContainerLayoutItem* pRootPageSetContainerItem = iterator.GetCurrent();
1718     ASSERT(pRootPageSetContainerItem->m_pFormNode->GetElementType() ==
1719            XFA_Element::PageSet);
1720     if (iIndex <
1721         pdfium::CollectionSize<int32_t>(pDocument->m_pPendingPageSet)) {
1722       pPendingPageSet = pDocument->m_pPendingPageSet[iIndex];
1723       iIndex++;
1724     }
1725     if (!pPendingPageSet) {
1726       if (pRootPageSetContainerItem->m_pFormNode->GetPacketType() ==
1727           XFA_PacketType::Template) {
1728         pPendingPageSet =
1729             pRootPageSetContainerItem->m_pFormNode->CloneTemplateToForm(false);
1730       } else {
1731         pPendingPageSet = pRootPageSetContainerItem->m_pFormNode;
1732       }
1733     }
1734     if (pRootPageSetContainerItem->m_pFormNode->JSObject()->GetLayoutItem() ==
1735         pRootPageSetContainerItem) {
1736       pRootPageSetContainerItem->m_pFormNode->JSObject()->SetLayoutItem(
1737           nullptr);
1738     }
1739     pRootPageSetContainerItem->m_pFormNode = pPendingPageSet;
1740     pPendingPageSet->ClearFlag(XFA_NodeFlag_UnusedNode);
1741     for (CXFA_ContainerLayoutItem* pContainerItem = iterator.MoveToNext();
1742          pContainerItem; pContainerItem = iterator.MoveToNext()) {
1743       CXFA_Node* pNode = pContainerItem->m_pFormNode;
1744       if (pNode->GetPacketType() != XFA_PacketType::Template)
1745         continue;
1746 
1747       switch (pNode->GetElementType()) {
1748         case XFA_Element::PageSet: {
1749           CXFA_Node* pParentNode = pContainerItem->m_pParent->m_pFormNode;
1750           pContainerItem->m_pFormNode = XFA_NodeMerge_CloneOrMergeContainer(
1751               pDocument, pParentNode, pContainerItem->m_pFormNode, true,
1752               nullptr);
1753           break;
1754         }
1755         case XFA_Element::PageArea: {
1756           CXFA_LayoutItem* pFormLayout = pContainerItem;
1757           CXFA_Node* pParentNode = pContainerItem->m_pParent->m_pFormNode;
1758           bool bIsExistForm = true;
1759           for (int32_t iLevel = 0; iLevel < 3; iLevel++) {
1760             pFormLayout = pFormLayout->m_pFirstChild;
1761             if (iLevel == 2) {
1762               while (pFormLayout &&
1763                      !XFA_ItemLayoutProcessor_IsTakingSpace(
1764                          pFormLayout->m_pFormNode)) {
1765                 pFormLayout = pFormLayout->m_pNextSibling;
1766               }
1767             }
1768             if (!pFormLayout) {
1769               bIsExistForm = false;
1770               break;
1771             }
1772           }
1773           if (bIsExistForm) {
1774             CXFA_Node* pNewSubform = pFormLayout->m_pFormNode;
1775             if (pContainerItem->m_pOldSubform &&
1776                 pContainerItem->m_pOldSubform != pNewSubform) {
1777               CXFA_Node* pExistingNode = XFA_DataMerge_FindFormDOMInstance(
1778                   pDocument, pContainerItem->m_pFormNode->GetElementType(),
1779                   pContainerItem->m_pFormNode->GetNameHash(), pParentNode);
1780               CXFA_ContainerIterator sIterator(pExistingNode);
1781               for (CXFA_Node* pIter = sIterator.GetCurrent(); pIter;
1782                    pIter = sIterator.MoveToNext()) {
1783                 if (pIter->GetElementType() != XFA_Element::ContentArea) {
1784                   CXFA_LayoutItem* pLayoutItem =
1785                       pIter->JSObject()->GetLayoutItem();
1786                   if (pLayoutItem) {
1787                     pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
1788                     delete pLayoutItem;
1789                   }
1790                 }
1791               }
1792               if (pExistingNode) {
1793                 pParentNode->RemoveChild(pExistingNode, true);
1794               }
1795             }
1796             pContainerItem->m_pOldSubform = pNewSubform;
1797           }
1798           pContainerItem->m_pFormNode = pDocument->DataMerge_CopyContainer(
1799               pContainerItem->m_pFormNode, pParentNode,
1800               ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Record)), true, true,
1801               true);
1802           break;
1803         }
1804         case XFA_Element::ContentArea: {
1805           CXFA_Node* pParentNode = pContainerItem->m_pParent->m_pFormNode;
1806           for (CXFA_Node* pChildNode = pParentNode->GetFirstChild(); pChildNode;
1807                pChildNode = pChildNode->GetNextSibling()) {
1808             if (pChildNode->GetTemplateNodeIfExists() !=
1809                 pContainerItem->m_pFormNode) {
1810               continue;
1811             }
1812             pContainerItem->m_pFormNode = pChildNode;
1813             break;
1814           }
1815           break;
1816         }
1817         default:
1818           break;
1819       }
1820     }
1821     if (!pPendingPageSet->GetParent()) {
1822       CXFA_Node* pFormToplevelSubform =
1823           pDocument->GetXFAObject(XFA_HASHCODE_Form)
1824               ->AsNode()
1825               ->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
1826       pFormToplevelSubform->InsertChild(pPendingPageSet, nullptr);
1827     }
1828     pDocument->DataMerge_UpdateBindingRelations(pPendingPageSet);
1829     pPendingPageSet->SetFlag(XFA_NodeFlag_Initialized, true);
1830   }
1831 
1832   CXFA_Node* pPageSet = GetRootLayoutItem()->m_pFormNode;
1833   while (pPageSet) {
1834     CXFA_Node* pNextPageSet =
1835         pPageSet->GetNextSameClassSibling<CXFA_PageSet>(XFA_Element::PageSet);
1836     CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
1837         sIterator(pPageSet);
1838     CXFA_Node* pNode = sIterator.GetCurrent();
1839     while (pNode) {
1840       if (pNode->IsUnusedNode()) {
1841         if (pNode->IsContainerNode()) {
1842           XFA_Element eType = pNode->GetElementType();
1843           if (eType == XFA_Element::PageArea || eType == XFA_Element::PageSet) {
1844             CXFA_ContainerIterator iteChild(pNode);
1845             CXFA_Node* pChildNode = iteChild.MoveToNext();
1846             for (; pChildNode; pChildNode = iteChild.MoveToNext()) {
1847               CXFA_LayoutItem* pLayoutItem =
1848                   pChildNode->JSObject()->GetLayoutItem();
1849               if (pLayoutItem) {
1850                 pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
1851                 delete pLayoutItem;
1852               }
1853             }
1854           } else if (eType != XFA_Element::ContentArea) {
1855             CXFA_LayoutItem* pLayoutItem = pNode->JSObject()->GetLayoutItem();
1856             if (pLayoutItem) {
1857               pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
1858               delete pLayoutItem;
1859             }
1860           }
1861           CXFA_Node* pNext = sIterator.SkipChildrenAndMoveToNext();
1862           pNode->GetParent()->RemoveChild(pNode, true);
1863           pNode = pNext;
1864         } else {
1865           pNode->ClearFlag(XFA_NodeFlag_UnusedNode);
1866           pNode->SetFlag(XFA_NodeFlag_Initialized, true);
1867           pNode = sIterator.MoveToNext();
1868         }
1869       } else {
1870         pNode->SetFlag(XFA_NodeFlag_Initialized, true);
1871         pNode = sIterator.MoveToNext();
1872       }
1873     }
1874     pPageSet = pNextPageSet;
1875   }
1876 }
1877 
LayoutPageSetContents()1878 void CXFA_LayoutPageMgr::LayoutPageSetContents() {
1879   CXFA_ContainerLayoutItem* pRootLayoutItem = GetRootLayoutItem();
1880   for (; pRootLayoutItem;
1881        pRootLayoutItem = static_cast<CXFA_ContainerLayoutItem*>(
1882            pRootLayoutItem->m_pNextSibling)) {
1883     CXFA_NodeIteratorTemplate<
1884         CXFA_ContainerLayoutItem,
1885         CXFA_TraverseStrategy_ContentAreaContainerLayoutItem>
1886         iterator(pRootLayoutItem);
1887     for (CXFA_ContainerLayoutItem* pContainerItem = iterator.GetCurrent();
1888          pContainerItem; pContainerItem = iterator.MoveToNext()) {
1889       CXFA_Node* pNode = pContainerItem->m_pFormNode;
1890       switch (pNode->GetElementType()) {
1891         case XFA_Element::PageArea:
1892           m_pLayoutProcessor->GetRootRootItemLayoutProcessor()
1893               ->DoLayoutPageArea(pContainerItem);
1894           break;
1895         default:
1896           break;
1897       }
1898     }
1899   }
1900 }
1901 
SyncLayoutData()1902 void CXFA_LayoutPageMgr::SyncLayoutData() {
1903   MergePageSetContents();
1904   LayoutPageSetContents();
1905   CXFA_FFNotify* pNotify = m_pTemplatePageSetRoot->GetDocument()->GetNotify();
1906   int32_t nPageIdx = -1;
1907   CXFA_ContainerLayoutItem* pRootLayoutItem = GetRootLayoutItem();
1908   for (; pRootLayoutItem;
1909        pRootLayoutItem = static_cast<CXFA_ContainerLayoutItem*>(
1910            pRootLayoutItem->m_pNextSibling)) {
1911     CXFA_NodeIteratorTemplate<
1912         CXFA_ContainerLayoutItem,
1913         CXFA_TraverseStrategy_ContentAreaContainerLayoutItem>
1914         iteratorParent(pRootLayoutItem);
1915     for (CXFA_ContainerLayoutItem* pContainerItem = iteratorParent.GetCurrent();
1916          pContainerItem; pContainerItem = iteratorParent.MoveToNext()) {
1917       switch (pContainerItem->m_pFormNode->GetElementType()) {
1918         case XFA_Element::PageArea: {
1919           nPageIdx++;
1920           uint32_t dwRelevant =
1921               XFA_WidgetStatus_Viewable | XFA_WidgetStatus_Printable;
1922           CXFA_NodeIteratorTemplate<CXFA_LayoutItem,
1923                                     CXFA_TraverseStrategy_LayoutItem>
1924               iterator(pContainerItem);
1925           CXFA_LayoutItem* pChildLayoutItem = iterator.GetCurrent();
1926           while (pChildLayoutItem) {
1927             CXFA_ContentLayoutItem* pContentItem =
1928                 pChildLayoutItem->AsContentLayoutItem();
1929             if (!pContentItem) {
1930               pChildLayoutItem = iterator.MoveToNext();
1931               continue;
1932             }
1933 
1934             XFA_AttributeEnum presence =
1935                 pContentItem->m_pFormNode->JSObject()
1936                     ->TryEnum(XFA_Attribute::Presence, true)
1937                     .value_or(XFA_AttributeEnum::Visible);
1938             bool bVisible = presence == XFA_AttributeEnum::Visible;
1939             uint32_t dwRelevantChild =
1940                 GetRelevant(pContentItem->m_pFormNode, dwRelevant);
1941             SyncContainer(pNotify, m_pLayoutProcessor, pContentItem,
1942                           dwRelevantChild, bVisible, nPageIdx);
1943             pChildLayoutItem = iterator.SkipChildrenAndMoveToNext();
1944           }
1945           break;
1946         }
1947         default:
1948           break;
1949       }
1950     }
1951   }
1952 
1953   int32_t nPage = pdfium::CollectionSize<int32_t>(m_PageArray);
1954   for (int32_t i = nPage - 1; i >= m_nAvailPages; i--) {
1955     CXFA_ContainerLayoutItem* pPage = m_PageArray[i];
1956     m_PageArray.erase(m_PageArray.begin() + i);
1957     pNotify->OnPageEvent(pPage, XFA_PAGEVIEWEVENT_PostRemoved);
1958     delete pPage;
1959   }
1960   ClearData();
1961 }
1962 
XFA_ReleaseLayoutItem_NoPageArea(CXFA_LayoutItem * pLayoutItem)1963 void XFA_ReleaseLayoutItem_NoPageArea(CXFA_LayoutItem* pLayoutItem) {
1964   CXFA_LayoutItem *pNext, *pNode = pLayoutItem->m_pFirstChild;
1965   while (pNode) {
1966     pNext = pNode->m_pNextSibling;
1967     pNode->m_pParent = nullptr;
1968     XFA_ReleaseLayoutItem_NoPageArea(pNode);
1969     pNode = pNext;
1970   }
1971   if (pLayoutItem->m_pFormNode->GetElementType() != XFA_Element::PageArea)
1972     delete pLayoutItem;
1973 }
1974 
PrepareLayout()1975 void CXFA_LayoutPageMgr::PrepareLayout() {
1976   m_pPageSetCurRoot = nullptr;
1977   m_ePageSetMode = XFA_AttributeEnum::OrderedOccurrence;
1978   m_nAvailPages = 0;
1979   ClearData();
1980   if (!m_pPageSetLayoutItemRoot)
1981     return;
1982 
1983   CXFA_ContainerLayoutItem* pRootLayoutItem = m_pPageSetLayoutItemRoot;
1984   if (pRootLayoutItem &&
1985       pRootLayoutItem->m_pFormNode->GetPacketType() == XFA_PacketType::Form) {
1986     CXFA_Node* pPageSetFormNode = pRootLayoutItem->m_pFormNode;
1987     pRootLayoutItem->m_pFormNode->GetDocument()->m_pPendingPageSet.clear();
1988     if (pPageSetFormNode->HasRemovedChildren()) {
1989       XFA_ReleaseLayoutItem(pRootLayoutItem);
1990       m_pPageSetLayoutItemRoot = nullptr;
1991       pRootLayoutItem = nullptr;
1992       pPageSetFormNode = nullptr;
1993       m_PageArray.clear();
1994     }
1995     while (pPageSetFormNode) {
1996       CXFA_Node* pNextPageSet =
1997           pPageSetFormNode->GetNextSameClassSibling<CXFA_PageSet>(
1998               XFA_Element::PageSet);
1999       pPageSetFormNode->GetParent()->RemoveChild(pPageSetFormNode, false);
2000       pRootLayoutItem->m_pFormNode->GetDocument()->m_pPendingPageSet.push_back(
2001           pPageSetFormNode);
2002       pPageSetFormNode = pNextPageSet;
2003     }
2004   }
2005   pRootLayoutItem = m_pPageSetLayoutItemRoot;
2006   CXFA_ContainerLayoutItem* pNextLayout = nullptr;
2007   for (; pRootLayoutItem; pRootLayoutItem = pNextLayout) {
2008     pNextLayout =
2009         static_cast<CXFA_ContainerLayoutItem*>(pRootLayoutItem->m_pNextSibling);
2010     SaveLayoutItem(pRootLayoutItem);
2011     delete pRootLayoutItem;
2012   }
2013   m_pPageSetLayoutItemRoot = nullptr;
2014 }
2015