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