xref: /aosp_15_r20/external/pdfium/xfa/fxfa/layout/cxfa_viewlayoutprocessor.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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/stl_util.h"
12 #include "fxjs/gc/container_trace.h"
13 #include "fxjs/xfa/cfxjse_engine.h"
14 #include "fxjs/xfa/cjx_object.h"
15 #include "third_party/base/check.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->Trim();
175   size_t iSplitIndex = 0;
176   bool bTargetAllFind = true;
177   while (true) {
178     WideString wsExpr;
179     absl::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       absl::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 absl::nullopt.
CheckContentAreaNotUsed(CXFA_ViewLayoutItem * pPageAreaLayoutItem,CXFA_Node * pContentArea)226 absl::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 absl::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::base::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 absl::optional<CXFA_ViewLayoutProcessor::BreakData>
ProcessBreakBefore(const CXFA_Node * pBreakNode)857 CXFA_ViewLayoutProcessor::ProcessBreakBefore(const CXFA_Node* pBreakNode) {
858   return ProcessBreakBeforeOrAfter(pBreakNode, /*before=*/true);
859 }
860 
861 absl::optional<CXFA_ViewLayoutProcessor::BreakData>
ProcessBreakAfter(const CXFA_Node * pBreakNode)862 CXFA_ViewLayoutProcessor::ProcessBreakAfter(const CXFA_Node* pBreakNode) {
863   return ProcessBreakBeforeOrAfter(pBreakNode, /*before=*/false);
864 }
865 
866 absl::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 absl::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 absl::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 absl::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 absl::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 absl::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, /*leader=*/true);
911 }
912 
ProcessBookendTrailer(const CXFA_Node * pBookendNode)913 CXFA_Node* CXFA_ViewLayoutProcessor::ProcessBookendTrailer(
914     const CXFA_Node* pBookendNode) {
915   return ProcessBookendLeaderOrTrailer(pBookendNode, /*leader=*/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)
925     return nullptr;
926 
927   CXFA_Document* pDocument = pBookendNode->GetDocument();
928   CXFA_Node* pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
929   CXFA_Node* pBookendAppendNode = pDocument->DataMerge_CopyContainer(
930       pLeaderTemplate, pFormNode, pDataScope, true, true, true);
931   if (!pBookendAppendNode)
932     return nullptr;
933 
934   pDocument->DataMerge_UpdateBindingRelations(pBookendAppendNode);
935   SetLayoutGeneratedNodeFlag(pBookendAppendNode);
936   return pBookendAppendNode;
937 }
938 
BreakOverflow(const CXFA_Node * pOverflowNode,bool bCreatePage,CXFA_Node ** pLeaderTemplate,CXFA_Node ** pTrailerTemplate)939 bool CXFA_ViewLayoutProcessor::BreakOverflow(const CXFA_Node* pOverflowNode,
940                                              bool bCreatePage,
941                                              CXFA_Node** pLeaderTemplate,
942                                              CXFA_Node** pTrailerTemplate) {
943   CXFA_Node* pContainer =
944       pOverflowNode->GetContainerParent()->GetTemplateNodeIfExists();
945   if (pOverflowNode->GetElementType() == XFA_Element::Break) {
946     WideString wsOverflowLeader =
947         pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowLeader);
948     WideString wsOverflowTarget =
949         pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowTarget);
950     WideString wsOverflowTrailer =
951         pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowTrailer);
952     if (wsOverflowTarget.IsEmpty() && wsOverflowLeader.IsEmpty() &&
953         wsOverflowTrailer.IsEmpty()) {
954       return false;
955     }
956 
957     if (!wsOverflowTarget.IsEmpty() && bCreatePage && !m_bCreateOverFlowPage) {
958       CXFA_Node* pTarget =
959           ResolveBreakTarget(m_pPageSetNode, true, &wsOverflowTarget);
960       if (pTarget) {
961         m_bCreateOverFlowPage = true;
962         switch (pTarget->GetElementType()) {
963           case XFA_Element::PageArea:
964             RunBreak(XFA_Element::Overflow, XFA_AttributeValue::PageArea,
965                      pTarget, true);
966             break;
967           case XFA_Element::ContentArea:
968             RunBreak(XFA_Element::Overflow, XFA_AttributeValue::ContentArea,
969                      pTarget, true);
970             break;
971           default:
972             break;
973         }
974       }
975     }
976     if (!bCreatePage) {
977       *pLeaderTemplate =
978           ResolveBreakTarget(pContainer, true, &wsOverflowLeader);
979       *pTrailerTemplate =
980           ResolveBreakTarget(pContainer, true, &wsOverflowTrailer);
981     }
982     return true;
983   }
984 
985   if (pOverflowNode->GetElementType() != XFA_Element::Overflow)
986     return false;
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_pPageSetNode, true, &wsOverflowTarget);
993     if (pTarget) {
994       m_bCreateOverFlowPage = true;
995       switch (pTarget->GetElementType()) {
996         case XFA_Element::PageArea:
997           RunBreak(XFA_Element::Overflow, XFA_AttributeValue::PageArea, pTarget,
998                    true);
999           break;
1000         case XFA_Element::ContentArea:
1001           RunBreak(XFA_Element::Overflow, XFA_AttributeValue::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 true;
1018 }
1019 
1020 absl::optional<CXFA_ViewLayoutProcessor::OverflowData>
ProcessOverflow(CXFA_Node * pFormNode,bool bCreatePage)1021 CXFA_ViewLayoutProcessor::ProcessOverflow(CXFA_Node* pFormNode,
1022                                           bool bCreatePage) {
1023   if (!pFormNode)
1024     return absl::nullopt;
1025 
1026   CXFA_Node* pLeaderTemplate = nullptr;
1027   CXFA_Node* pTrailerTemplate = nullptr;
1028   bool bIsOverflowNode = pFormNode->GetElementType() == XFA_Element::Overflow ||
1029                          pFormNode->GetElementType() == XFA_Element::Break;
1030   OverflowData overflow_data{nullptr, nullptr};
1031   for (CXFA_Node* pCurNode = bIsOverflowNode ? pFormNode
1032                                              : pFormNode->GetFirstChild();
1033        pCurNode; pCurNode = pCurNode->GetNextSibling()) {
1034     if (BreakOverflow(pCurNode, bCreatePage, &pLeaderTemplate,
1035                       &pTrailerTemplate)) {
1036       if (bIsOverflowNode)
1037         pFormNode = pCurNode->GetParent();
1038 
1039       CXFA_Document* pDocument = pCurNode->GetDocument();
1040       CXFA_Node* pDataScope = nullptr;
1041       if (pLeaderTemplate) {
1042         pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
1043 
1044         overflow_data.pLeader = pDocument->DataMerge_CopyContainer(
1045             pLeaderTemplate, pFormNode, pDataScope, true, true, true);
1046         if (!overflow_data.pLeader)
1047           return absl::nullopt;
1048 
1049         pDocument->DataMerge_UpdateBindingRelations(overflow_data.pLeader);
1050         SetLayoutGeneratedNodeFlag(overflow_data.pLeader);
1051       }
1052       if (pTrailerTemplate) {
1053         if (!pDataScope)
1054           pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
1055 
1056         overflow_data.pTrailer = pDocument->DataMerge_CopyContainer(
1057             pTrailerTemplate, pFormNode, pDataScope, true, true, true);
1058         if (!overflow_data.pTrailer)
1059           return absl::nullopt;
1060 
1061         pDocument->DataMerge_UpdateBindingRelations(overflow_data.pTrailer);
1062         SetLayoutGeneratedNodeFlag(overflow_data.pTrailer);
1063       }
1064       return overflow_data;
1065     }
1066     if (bIsOverflowNode)
1067       break;
1068   }
1069   return absl::nullopt;
1070 }
1071 
ResolveBookendLeaderOrTrailer(const CXFA_Node * pBookendNode,bool bLeader)1072 CXFA_Node* CXFA_ViewLayoutProcessor::ResolveBookendLeaderOrTrailer(
1073     const CXFA_Node* pBookendNode,
1074     bool bLeader) {
1075   CXFA_Node* pContainer =
1076       pBookendNode->GetContainerParent()->GetTemplateNodeIfExists();
1077   if (pBookendNode->GetElementType() == XFA_Element::Break) {
1078     WideString leader = pBookendNode->JSObject()->GetCData(
1079         bLeader ? XFA_Attribute::BookendLeader : XFA_Attribute::BookendTrailer);
1080     if (leader.IsEmpty())
1081       return nullptr;
1082     return ResolveBreakTarget(pContainer, false, &leader);
1083   }
1084 
1085   if (pBookendNode->GetElementType() != XFA_Element::Bookend)
1086     return nullptr;
1087 
1088   WideString leader = pBookendNode->JSObject()->GetCData(
1089       bLeader ? XFA_Attribute::Leader : XFA_Attribute::Trailer);
1090   return ResolveBreakTarget(pContainer, true, &leader);
1091 }
1092 
FindPageAreaFromPageSet(CXFA_Node * pPageSet,CXFA_Node * pStartChild,CXFA_Node * pTargetPageArea,CXFA_Node * pTargetContentArea,bool bNewPage,bool bQuery)1093 bool CXFA_ViewLayoutProcessor::FindPageAreaFromPageSet(
1094     CXFA_Node* pPageSet,
1095     CXFA_Node* pStartChild,
1096     CXFA_Node* pTargetPageArea,
1097     CXFA_Node* pTargetContentArea,
1098     bool bNewPage,
1099     bool bQuery) {
1100   if (!pPageSet && !pStartChild)
1101     return false;
1102 
1103   if (IsPageSetRootOrderedOccurrence()) {
1104     return FindPageAreaFromPageSet_Ordered(pPageSet, pStartChild,
1105                                            pTargetPageArea, pTargetContentArea,
1106                                            bNewPage, bQuery);
1107   }
1108   XFA_AttributeValue ePreferredPosition = HasCurrentViewRecord()
1109                                               ? XFA_AttributeValue::Rest
1110                                               : XFA_AttributeValue::First;
1111   return FindPageAreaFromPageSet_SimplexDuplex(
1112       pPageSet, pStartChild, pTargetPageArea, pTargetContentArea, bNewPage,
1113       bQuery, ePreferredPosition);
1114 }
1115 
FindPageAreaFromPageSet_Ordered(CXFA_Node * pPageSet,CXFA_Node * pStartChild,CXFA_Node * pTargetPageArea,CXFA_Node * pTargetContentArea,bool bNewPage,bool bQuery)1116 bool CXFA_ViewLayoutProcessor::FindPageAreaFromPageSet_Ordered(
1117     CXFA_Node* pPageSet,
1118     CXFA_Node* pStartChild,
1119     CXFA_Node* pTargetPageArea,
1120     CXFA_Node* pTargetContentArea,
1121     bool bNewPage,
1122     bool bQuery) {
1123   int32_t iPageSetCount = 0;
1124   if (!pStartChild && !bQuery) {
1125     auto it = m_pPageSetMap.find(pPageSet);
1126     if (it != m_pPageSetMap.end())
1127       iPageSetCount = it->second;
1128     int32_t iMax = -1;
1129     CXFA_Node* pOccurNode =
1130         pPageSet->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1131     if (pOccurNode) {
1132       absl::optional<int32_t> ret =
1133           pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
1134       if (ret.has_value())
1135         iMax = ret.value();
1136     }
1137     if (iMax >= 0 && iMax <= iPageSetCount)
1138       return false;
1139   }
1140 
1141   bool bRes = false;
1142   CXFA_Node* pCurrentNode =
1143       pStartChild ? pStartChild->GetNextSibling() : pPageSet->GetFirstChild();
1144   for (; pCurrentNode; pCurrentNode = pCurrentNode->GetNextSibling()) {
1145     if (pCurrentNode->GetElementType() == XFA_Element::PageArea) {
1146       if ((pTargetPageArea == pCurrentNode || !pTargetPageArea)) {
1147         if (!pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1148                 XFA_Element::ContentArea)) {
1149           if (pTargetPageArea == pCurrentNode) {
1150             CreateMinPageRecord(pCurrentNode, true, false);
1151             pTargetPageArea = nullptr;
1152           }
1153           continue;
1154         }
1155         if (!bQuery) {
1156           CXFA_ViewRecord* pNewRecord =
1157               CreateViewRecord(pCurrentNode, !pStartChild);
1158           AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
1159           if (!pTargetContentArea) {
1160             pTargetContentArea =
1161                 pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1162                     XFA_Element::ContentArea);
1163           }
1164           AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
1165         }
1166         m_pCurPageArea = pCurrentNode;
1167         m_nCurPageCount = 1;
1168         bRes = true;
1169         break;
1170       }
1171       if (!bQuery)
1172         CreateMinPageRecord(pCurrentNode, false, false);
1173     } else if (pCurrentNode->GetElementType() == XFA_Element::PageSet) {
1174       if (FindPageAreaFromPageSet_Ordered(pCurrentNode, nullptr,
1175                                           pTargetPageArea, pTargetContentArea,
1176                                           bNewPage, bQuery)) {
1177         bRes = true;
1178         break;
1179       }
1180       if (!bQuery)
1181         CreateMinPageSetRecord(pCurrentNode, true);
1182     }
1183   }
1184   if (!pStartChild && bRes && !bQuery)
1185     m_pPageSetMap[pPageSet] = ++iPageSetCount;
1186   return bRes;
1187 }
1188 
FindPageAreaFromPageSet_SimplexDuplex(CXFA_Node * pPageSet,CXFA_Node * pStartChild,CXFA_Node * pTargetPageArea,CXFA_Node * pTargetContentArea,bool bNewPage,bool bQuery,XFA_AttributeValue ePreferredPosition)1189 bool CXFA_ViewLayoutProcessor::FindPageAreaFromPageSet_SimplexDuplex(
1190     CXFA_Node* pPageSet,
1191     CXFA_Node* pStartChild,
1192     CXFA_Node* pTargetPageArea,
1193     CXFA_Node* pTargetContentArea,
1194     bool bNewPage,
1195     bool bQuery,
1196     XFA_AttributeValue ePreferredPosition) {
1197   const XFA_AttributeValue eFallbackPosition = XFA_AttributeValue::Any;
1198   CXFA_Node* pPreferredPageArea = nullptr;
1199   CXFA_Node* pFallbackPageArea = nullptr;
1200   CXFA_Node* pCurrentNode = nullptr;
1201   if (!pStartChild || pStartChild->GetElementType() == XFA_Element::PageArea)
1202     pCurrentNode = pPageSet->GetFirstChild();
1203   else
1204     pCurrentNode = pStartChild->GetNextSibling();
1205 
1206   for (; pCurrentNode; pCurrentNode = pCurrentNode->GetNextSibling()) {
1207     if (pCurrentNode->GetElementType() == XFA_Element::PageArea) {
1208       if (!MatchPageAreaOddOrEven(pCurrentNode))
1209         continue;
1210 
1211       XFA_AttributeValue eCurPagePosition =
1212           pCurrentNode->JSObject()->GetEnum(XFA_Attribute::PagePosition);
1213       if (ePreferredPosition == XFA_AttributeValue::Last) {
1214         if (eCurPagePosition != ePreferredPosition)
1215           continue;
1216         if (m_ePageSetMode == XFA_AttributeValue::SimplexPaginated ||
1217             pCurrentNode->JSObject()->GetEnum(XFA_Attribute::OddOrEven) ==
1218                 XFA_AttributeValue::Any) {
1219           pPreferredPageArea = pCurrentNode;
1220           break;
1221         }
1222         CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
1223         AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
1224         AddContentAreaLayoutItem(
1225             pNewRecord, pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1226                             XFA_Element::ContentArea));
1227         return false;
1228       }
1229       if (ePreferredPosition == XFA_AttributeValue::Only) {
1230         if (eCurPagePosition != ePreferredPosition)
1231           continue;
1232         if (m_ePageSetMode != XFA_AttributeValue::DuplexPaginated ||
1233             pCurrentNode->JSObject()->GetEnum(XFA_Attribute::OddOrEven) ==
1234                 XFA_AttributeValue::Any) {
1235           pPreferredPageArea = pCurrentNode;
1236           break;
1237         }
1238         return false;
1239       }
1240       if ((pTargetPageArea == pCurrentNode || !pTargetPageArea)) {
1241         if (!pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1242                 XFA_Element::ContentArea)) {
1243           if (pTargetPageArea == pCurrentNode) {
1244             CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
1245             AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
1246             pTargetPageArea = nullptr;
1247           }
1248           continue;
1249         }
1250         if ((ePreferredPosition == XFA_AttributeValue::Rest &&
1251              eCurPagePosition == XFA_AttributeValue::Any) ||
1252             eCurPagePosition == ePreferredPosition) {
1253           pPreferredPageArea = pCurrentNode;
1254           break;
1255         }
1256         if (eCurPagePosition == eFallbackPosition && !pFallbackPageArea) {
1257           pFallbackPageArea = pCurrentNode;
1258         }
1259       } else if (pTargetPageArea && !MatchPageAreaOddOrEven(pTargetPageArea)) {
1260         CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
1261         AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
1262         AddContentAreaLayoutItem(
1263             pNewRecord, pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1264                             XFA_Element::ContentArea));
1265       }
1266     } else if (pCurrentNode->GetElementType() == XFA_Element::PageSet) {
1267       if (FindPageAreaFromPageSet_SimplexDuplex(
1268               pCurrentNode, nullptr, pTargetPageArea, pTargetContentArea,
1269               bNewPage, bQuery, ePreferredPosition)) {
1270         break;
1271       }
1272     }
1273   }
1274 
1275   CXFA_Node* pCurPageArea = nullptr;
1276   if (pPreferredPageArea)
1277     pCurPageArea = pPreferredPageArea;
1278   else if (pFallbackPageArea)
1279     pCurPageArea = pFallbackPageArea;
1280 
1281   if (!pCurPageArea)
1282     return false;
1283 
1284   if (!bQuery) {
1285     CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
1286     AddPageAreaLayoutItem(pNewRecord, pCurPageArea);
1287     if (!pTargetContentArea) {
1288       pTargetContentArea = pCurPageArea->GetFirstChildByClass<CXFA_ContentArea>(
1289           XFA_Element::ContentArea);
1290     }
1291     AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
1292   }
1293   m_pCurPageArea = pCurPageArea;
1294   return true;
1295 }
1296 
MatchPageAreaOddOrEven(CXFA_Node * pPageArea)1297 bool CXFA_ViewLayoutProcessor::MatchPageAreaOddOrEven(CXFA_Node* pPageArea) {
1298   if (m_ePageSetMode != XFA_AttributeValue::DuplexPaginated)
1299     return true;
1300 
1301   absl::optional<XFA_AttributeValue> ret =
1302       pPageArea->JSObject()->TryEnum(XFA_Attribute::OddOrEven, true);
1303   if (!ret.has_value() || ret == XFA_AttributeValue::Any)
1304     return true;
1305 
1306   int32_t iPageLast = GetPageCount() % 2;
1307   return ret == XFA_AttributeValue::Odd ? iPageLast == 0 : iPageLast == 1;
1308 }
1309 
GetNextAvailPageArea(CXFA_Node * pTargetPageArea,CXFA_Node * pTargetContentArea,bool bNewPage,bool bQuery)1310 CXFA_Node* CXFA_ViewLayoutProcessor::GetNextAvailPageArea(
1311     CXFA_Node* pTargetPageArea,
1312     CXFA_Node* pTargetContentArea,
1313     bool bNewPage,
1314     bool bQuery) {
1315   if (!m_pCurPageArea) {
1316     FindPageAreaFromPageSet(m_pPageSetNode, nullptr, pTargetPageArea,
1317                             pTargetContentArea, bNewPage, bQuery);
1318     return m_pCurPageArea;
1319   }
1320 
1321   if (!pTargetPageArea || pTargetPageArea == m_pCurPageArea) {
1322     if (!bNewPage && GetNextContentArea(pTargetContentArea))
1323       return m_pCurPageArea;
1324 
1325     if (IsPageSetRootOrderedOccurrence()) {
1326       int32_t iMax = -1;
1327       CXFA_Node* pOccurNode =
1328           m_pCurPageArea->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1329       if (pOccurNode) {
1330         absl::optional<int32_t> ret =
1331             pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
1332         if (ret.has_value())
1333           iMax = ret.value();
1334       }
1335       if ((iMax < 0 || m_nCurPageCount < iMax)) {
1336         if (!bQuery) {
1337           CXFA_ViewRecord* pNewRecord = CreateViewRecord(m_pCurPageArea, false);
1338           AddPageAreaLayoutItem(pNewRecord, m_pCurPageArea);
1339           if (!pTargetContentArea) {
1340             pTargetContentArea =
1341                 m_pCurPageArea->GetFirstChildByClass<CXFA_ContentArea>(
1342                     XFA_Element::ContentArea);
1343           }
1344           AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
1345         }
1346         m_nCurPageCount++;
1347         return m_pCurPageArea;
1348       }
1349     }
1350   }
1351 
1352   if (!bQuery && IsPageSetRootOrderedOccurrence())
1353     CreateMinPageRecord(m_pCurPageArea, false, true);
1354   if (FindPageAreaFromPageSet(m_pCurPageArea->GetParent(), m_pCurPageArea,
1355                               pTargetPageArea, pTargetContentArea, bNewPage,
1356                               bQuery)) {
1357     return m_pCurPageArea;
1358   }
1359 
1360   CXFA_Node* pPageSet = m_pCurPageArea->GetParent();
1361   while (pPageSet) {
1362     if (FindPageAreaFromPageSet(pPageSet, nullptr, pTargetPageArea,
1363                                 pTargetContentArea, bNewPage, bQuery)) {
1364       return m_pCurPageArea;
1365     }
1366     if (!bQuery && IsPageSetRootOrderedOccurrence())
1367       CreateMinPageSetRecord(pPageSet, false);
1368     if (FindPageAreaFromPageSet(nullptr, pPageSet, pTargetPageArea,
1369                                 pTargetContentArea, bNewPage, bQuery)) {
1370       return m_pCurPageArea;
1371     }
1372     if (pPageSet == m_pPageSetNode)
1373       break;
1374 
1375     pPageSet = pPageSet->GetParent();
1376   }
1377   return nullptr;
1378 }
1379 
GetNextContentArea(CXFA_Node * pContentArea)1380 bool CXFA_ViewLayoutProcessor::GetNextContentArea(CXFA_Node* pContentArea) {
1381   CXFA_Node* pCurContentNode =
1382       GetCurrentViewRecord()->pCurContentArea->GetFormNode();
1383   if (!pContentArea) {
1384     pContentArea = pCurContentNode->GetNextSameClassSibling<CXFA_ContentArea>(
1385         XFA_Element::ContentArea);
1386     if (!pContentArea)
1387       return false;
1388   } else {
1389     if (pContentArea->GetParent() != m_pCurPageArea)
1390       return false;
1391 
1392     absl::optional<CXFA_ViewLayoutItem*> pContentAreaLayout =
1393         CheckContentAreaNotUsed(GetCurrentViewRecord()->pCurPageArea.Get(),
1394                                 pContentArea);
1395     if (!pContentAreaLayout.has_value())
1396       return false;
1397     if (pContentAreaLayout.value()) {
1398       if (pContentAreaLayout.value()->GetFormNode() == pCurContentNode)
1399         return false;
1400 
1401       CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
1402       pNewRecord->pCurContentArea = pContentAreaLayout.value();
1403       return true;
1404     }
1405   }
1406 
1407   CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
1408   AddContentAreaLayoutItem(pNewRecord, pContentArea);
1409   return true;
1410 }
1411 
InitPageSetMap()1412 void CXFA_ViewLayoutProcessor::InitPageSetMap() {
1413   if (!IsPageSetRootOrderedOccurrence())
1414     return;
1415 
1416   CXFA_NodeIterator sIterator(m_pPageSetNode);
1417   for (CXFA_Node* pPageSetNode = sIterator.GetCurrent(); pPageSetNode;
1418        pPageSetNode = sIterator.MoveToNext()) {
1419     if (pPageSetNode->GetElementType() == XFA_Element::PageSet) {
1420       XFA_AttributeValue eRelation =
1421           pPageSetNode->JSObject()->GetEnum(XFA_Attribute::Relation);
1422       if (eRelation == XFA_AttributeValue::OrderedOccurrence)
1423         m_pPageSetMap[pPageSetNode] = 0;
1424     }
1425   }
1426 }
1427 
CreateMinPageRecord(CXFA_Node * pPageArea,bool bTargetPageArea,bool bCreateLast)1428 int32_t CXFA_ViewLayoutProcessor::CreateMinPageRecord(CXFA_Node* pPageArea,
1429                                                       bool bTargetPageArea,
1430                                                       bool bCreateLast) {
1431   if (!pPageArea)
1432     return 0;
1433 
1434   int32_t iMin = 0;
1435   absl::optional<int32_t> ret;
1436   CXFA_Node* pOccurNode =
1437       pPageArea->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1438   if (pOccurNode) {
1439     ret = pOccurNode->JSObject()->TryInteger(XFA_Attribute::Min, false);
1440     if (ret.has_value())
1441       iMin = ret.value();
1442   }
1443 
1444   if (!ret.has_value() && !bTargetPageArea)
1445     return iMin;
1446 
1447   CXFA_Node* pContentArea = pPageArea->GetFirstChildByClass<CXFA_ContentArea>(
1448       XFA_Element::ContentArea);
1449   if (iMin < 1 && bTargetPageArea && !pContentArea)
1450     iMin = 1;
1451 
1452   int32_t i = 0;
1453   if (bCreateLast)
1454     i = m_nCurPageCount;
1455 
1456   for (; i < iMin; i++) {
1457     CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
1458     AddPageAreaLayoutItem(pNewRecord, pPageArea);
1459     AddContentAreaLayoutItem(pNewRecord, pContentArea);
1460   }
1461   return iMin;
1462 }
1463 
CreateMinPageSetRecord(CXFA_Node * pPageSet,bool bCreateAll)1464 void CXFA_ViewLayoutProcessor::CreateMinPageSetRecord(CXFA_Node* pPageSet,
1465                                                       bool bCreateAll) {
1466   auto it = m_pPageSetMap.find(pPageSet);
1467   if (it == m_pPageSetMap.end())
1468     return;
1469 
1470   int32_t iCurSetCount = it->second;
1471   if (bCreateAll)
1472     iCurSetCount = 0;
1473 
1474   CXFA_Node* pOccurNode =
1475       pPageSet->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1476   if (!pOccurNode)
1477     return;
1478 
1479   absl::optional<int32_t> iMin =
1480       pOccurNode->JSObject()->TryInteger(XFA_Attribute::Min, false);
1481   if (!iMin.has_value() || iCurSetCount >= iMin.value())
1482     return;
1483 
1484   for (int32_t i = 0; i < iMin.value() - iCurSetCount; i++) {
1485     for (CXFA_Node* node = pPageSet->GetFirstChild(); node;
1486          node = node->GetNextSibling()) {
1487       if (node->GetElementType() == XFA_Element::PageArea)
1488         CreateMinPageRecord(node, false, false);
1489       else if (node->GetElementType() == XFA_Element::PageSet)
1490         CreateMinPageSetRecord(node, true);
1491     }
1492   }
1493   m_pPageSetMap[pPageSet] = iMin.value();
1494 }
1495 
CreateNextMinRecord(CXFA_Node * pRecordNode)1496 void CXFA_ViewLayoutProcessor::CreateNextMinRecord(CXFA_Node* pRecordNode) {
1497   if (!pRecordNode)
1498     return;
1499 
1500   for (CXFA_Node* pCurrentNode = pRecordNode->GetNextSibling(); pCurrentNode;
1501        pCurrentNode = pCurrentNode->GetNextSibling()) {
1502     if (pCurrentNode->GetElementType() == XFA_Element::PageArea)
1503       CreateMinPageRecord(pCurrentNode, false, false);
1504     else if (pCurrentNode->GetElementType() == XFA_Element::PageSet)
1505       CreateMinPageSetRecord(pCurrentNode, true);
1506   }
1507 }
1508 
ProcessLastPageSet()1509 void CXFA_ViewLayoutProcessor::ProcessLastPageSet() {
1510   if (!m_pCurPageArea)
1511     return;
1512 
1513   CreateMinPageRecord(m_pCurPageArea, false, true);
1514   CreateNextMinRecord(m_pCurPageArea);
1515   CXFA_Node* pPageSet = m_pCurPageArea->GetParent();
1516   while (pPageSet) {
1517     CreateMinPageSetRecord(pPageSet, false);
1518     if (pPageSet == m_pPageSetNode)
1519       break;
1520 
1521     CreateNextMinRecord(pPageSet);
1522     pPageSet = pPageSet->GetParent();
1523   }
1524 }
1525 
GetNextAvailContentHeight(float fChildHeight)1526 bool CXFA_ViewLayoutProcessor::GetNextAvailContentHeight(float fChildHeight) {
1527   CXFA_ViewRecord* pViewRecord = GetCurrentViewRecord();
1528   if (!pViewRecord)
1529     return false;
1530 
1531   CXFA_Node* pCurContentNode = pViewRecord->pCurContentArea->GetFormNode();
1532   if (!pCurContentNode)
1533     return false;
1534 
1535   pCurContentNode = pCurContentNode->GetNextSameClassSibling<CXFA_ContentArea>(
1536       XFA_Element::ContentArea);
1537   if (pCurContentNode) {
1538     float fNextContentHeight = pCurContentNode->JSObject()->GetMeasureInUnit(
1539         XFA_Attribute::H, XFA_Unit::Pt);
1540     return fNextContentHeight > fChildHeight;
1541   }
1542 
1543   CXFA_Node* pPageNode = GetCurrentViewRecord()->pCurPageArea->GetFormNode();
1544   CXFA_Node* pOccurNode =
1545       pPageNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1546   int32_t iMax = 0;
1547   absl::optional<int32_t> ret;
1548   if (pOccurNode) {
1549     ret = pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
1550     if (ret.has_value())
1551       iMax = ret.value();
1552   }
1553   if (ret.has_value()) {
1554     if (m_nCurPageCount == iMax) {
1555       CXFA_Node* pSrcPage = m_pCurPageArea;
1556       int32_t nSrcPageCount = m_nCurPageCount;
1557       auto psSrcIter = GetTailPosition();
1558       CXFA_Node* pNextPage =
1559           GetNextAvailPageArea(nullptr, nullptr, false, true);
1560       m_pCurPageArea = pSrcPage;
1561       m_nCurPageCount = nSrcPageCount;
1562       CXFA_ViewRecord* pPrevRecord = psSrcIter->Get();
1563       ++psSrcIter;
1564       while (psSrcIter != m_ProposedViewRecords.end()) {
1565         auto psSaveIter = psSrcIter++;
1566         RemoveLayoutRecord(psSaveIter->Get(), pPrevRecord);
1567         m_ProposedViewRecords.erase(psSaveIter);
1568       }
1569       if (pNextPage) {
1570         CXFA_Node* pContentArea =
1571             pNextPage->GetFirstChildByClass<CXFA_ContentArea>(
1572                 XFA_Element::ContentArea);
1573         if (pContentArea) {
1574           float fNextContentHeight = pContentArea->JSObject()->GetMeasureInUnit(
1575               XFA_Attribute::H, XFA_Unit::Pt);
1576           if (fNextContentHeight > fChildHeight)
1577             return true;
1578         }
1579       }
1580       return false;
1581     }
1582   }
1583 
1584   CXFA_Node* pContentArea = pPageNode->GetFirstChildByClass<CXFA_ContentArea>(
1585       XFA_Element::ContentArea);
1586   if (!pContentArea)
1587     return false;
1588 
1589   float fNextContentHeight = pContentArea->JSObject()->GetMeasureInUnit(
1590       XFA_Attribute::H, XFA_Unit::Pt);
1591   return fNextContentHeight < kXFALayoutPrecision ||
1592          fNextContentHeight > fChildHeight;
1593 }
1594 
ClearData()1595 void CXFA_ViewLayoutProcessor::ClearData() {
1596   if (!m_pPageSetNode)
1597     return;
1598 
1599   m_ProposedViewRecords.clear();
1600   m_CurrentViewRecordIter = m_ProposedViewRecords.end();
1601   m_pCurPageArea = nullptr;
1602   m_nCurPageCount = 0;
1603   m_bCreateOverFlowPage = false;
1604   m_pPageSetMap.clear();
1605 }
1606 
SaveLayoutItemChildren(CXFA_LayoutItem * pParentLayoutItem)1607 void CXFA_ViewLayoutProcessor::SaveLayoutItemChildren(
1608     CXFA_LayoutItem* pParentLayoutItem) {
1609   CXFA_Document* pDocument = m_pPageSetNode->GetDocument();
1610   CXFA_FFNotify* pNotify = pDocument->GetNotify();
1611   auto* pDocLayout = CXFA_LayoutProcessor::FromDocument(pDocument);
1612   CXFA_LayoutItem* pCurLayoutItem = pParentLayoutItem->GetFirstChild();
1613   while (pCurLayoutItem) {
1614     CXFA_LayoutItem* pNextLayoutItem = pCurLayoutItem->GetNextSibling();
1615     if (pCurLayoutItem->IsContentLayoutItem()) {
1616       if (pCurLayoutItem->GetFormNode()->HasRemovedChildren()) {
1617         SyncRemoveLayoutItem(pCurLayoutItem, pNotify, pDocLayout);
1618         pCurLayoutItem = pNextLayoutItem;
1619         continue;
1620       }
1621       if (pCurLayoutItem->GetFormNode()->IsLayoutGeneratedNode())
1622         pCurLayoutItem->GetFormNode()->SetNodeAndDescendantsUnused();
1623     }
1624     SaveLayoutItemChildren(pCurLayoutItem);
1625     pCurLayoutItem = pNextLayoutItem;
1626   }
1627 }
1628 
QueryOverflow(CXFA_Node * pFormNode)1629 CXFA_Node* CXFA_ViewLayoutProcessor::QueryOverflow(CXFA_Node* pFormNode) {
1630   for (CXFA_Node* pCurNode = pFormNode->GetFirstChild(); pCurNode;
1631        pCurNode = pCurNode->GetNextSibling()) {
1632     if (pCurNode->GetElementType() == XFA_Element::Break) {
1633       WideString wsOverflowLeader =
1634           pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowLeader);
1635       WideString wsOverflowTarget =
1636           pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowTarget);
1637       WideString wsOverflowTrailer =
1638           pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowTrailer);
1639 
1640       if (!wsOverflowLeader.IsEmpty() || !wsOverflowTrailer.IsEmpty() ||
1641           !wsOverflowTarget.IsEmpty()) {
1642         return pCurNode;
1643       }
1644       return nullptr;
1645     }
1646     if (pCurNode->GetElementType() == XFA_Element::Overflow)
1647       return pCurNode;
1648   }
1649   return nullptr;
1650 }
1651 
MergePageSetContents()1652 void CXFA_ViewLayoutProcessor::MergePageSetContents() {
1653   CXFA_Document* pDocument = m_pPageSetNode->GetDocument();
1654   pDocument->SetPendingNodesUnusedAndUnbound();
1655 
1656   CXFA_FFNotify* pNotify = pDocument->GetNotify();
1657   auto* pDocLayout = CXFA_LayoutProcessor::FromDocument(pDocument);
1658   CXFA_ViewLayoutItem* pRootLayout = GetRootLayoutItem();
1659 
1660   size_t pending_index = 0;
1661   for (; pRootLayout;
1662        pRootLayout = ToViewLayoutItem(pRootLayout->GetNextSibling())) {
1663     CXFA_Node* pPendingPageSet = nullptr;
1664     ViewLayoutItemIterator iterator(pRootLayout);
1665     CXFA_ViewLayoutItem* pRootPageSetViewItem = iterator.GetCurrent();
1666     DCHECK(pRootPageSetViewItem->GetFormNode()->GetElementType() ==
1667            XFA_Element::PageSet);
1668     if (pending_index < pDocument->GetPendingNodesCount()) {
1669       pPendingPageSet = pDocument->GetPendingNodeAtIndex(pending_index);
1670       ++pending_index;
1671     }
1672     if (!pPendingPageSet) {
1673       if (pRootPageSetViewItem->GetFormNode()->GetPacketType() ==
1674           XFA_PacketType::Template) {
1675         pPendingPageSet =
1676             pRootPageSetViewItem->GetFormNode()->CloneTemplateToForm(false);
1677       } else {
1678         pPendingPageSet = pRootPageSetViewItem->GetFormNode();
1679       }
1680     }
1681     if (pRootPageSetViewItem->GetFormNode()->JSObject()->GetLayoutItem() ==
1682         pRootPageSetViewItem) {
1683       pRootPageSetViewItem->GetFormNode()->JSObject()->SetLayoutItem(nullptr);
1684     }
1685     pRootPageSetViewItem->SetFormNode(pPendingPageSet);
1686     pPendingPageSet->ClearFlag(XFA_NodeFlag::kUnusedNode);
1687     for (CXFA_ViewLayoutItem* pViewItem = iterator.MoveToNext(); pViewItem;
1688          pViewItem = iterator.MoveToNext()) {
1689       CXFA_Node* pNode = pViewItem->GetFormNode();
1690       if (pNode->GetPacketType() != XFA_PacketType::Template)
1691         continue;
1692 
1693       switch (pNode->GetElementType()) {
1694         case XFA_Element::PageSet: {
1695           CXFA_Node* pParentNode = pViewItem->GetParent()->GetFormNode();
1696           CXFA_Node* pOldNode = pViewItem->GetFormNode();
1697           CXFA_Node* pNewNode = XFA_NodeMerge_CloneOrMergeContainer(
1698               pDocument, pParentNode, pOldNode, true, nullptr);
1699           if (pOldNode != pNewNode) {
1700             pOldNode->JSObject()->SetLayoutItem(nullptr);
1701             pViewItem->SetFormNode(pNewNode);
1702           }
1703           break;
1704         }
1705         case XFA_Element::PageArea: {
1706           CXFA_LayoutItem* pFormLayout = pViewItem;
1707           CXFA_Node* pParentNode = pViewItem->GetParent()->GetFormNode();
1708           bool bIsExistForm = true;
1709           for (int32_t iLevel = 0; iLevel < 3; iLevel++) {
1710             pFormLayout = pFormLayout->GetFirstChild();
1711             if (iLevel == 2) {
1712               while (pFormLayout &&
1713                      !pFormLayout->GetFormNode()->PresenceRequiresSpace()) {
1714                 pFormLayout = pFormLayout->GetNextSibling();
1715               }
1716             }
1717             if (!pFormLayout) {
1718               bIsExistForm = false;
1719               break;
1720             }
1721           }
1722           if (bIsExistForm) {
1723             CXFA_Node* pNewSubform = pFormLayout->GetFormNode();
1724             if (pViewItem->GetOldSubform() &&
1725                 pViewItem->GetOldSubform() != pNewSubform) {
1726               CXFA_Node* pExistingNode = XFA_DataMerge_FindFormDOMInstance(
1727                   pDocument, pViewItem->GetFormNode()->GetElementType(),
1728                   pViewItem->GetFormNode()->GetNameHash(), pParentNode);
1729               CXFA_ContainerIterator sIterator(pExistingNode);
1730               for (CXFA_Node* pIter = sIterator.GetCurrent(); pIter;
1731                    pIter = sIterator.MoveToNext()) {
1732                 if (pIter->GetElementType() != XFA_Element::ContentArea) {
1733                   CXFA_LayoutItem* pLayoutItem =
1734                       pIter->JSObject()->GetLayoutItem();
1735                   if (pLayoutItem) {
1736                     pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
1737                     pLayoutItem->RemoveSelfIfParented();
1738                   }
1739                 }
1740               }
1741               if (pExistingNode) {
1742                 pParentNode->RemoveChildAndNotify(pExistingNode, true);
1743               }
1744             }
1745             pViewItem->SetOldSubform(pNewSubform);
1746           }
1747           CXFA_Node* pOldNode = pViewItem->GetFormNode();
1748           CXFA_Node* pNewNode = pDocument->DataMerge_CopyContainer(
1749               pOldNode, pParentNode,
1750               ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Record)), true, true,
1751               true);
1752           if (pOldNode != pNewNode) {
1753             pOldNode->JSObject()->SetLayoutItem(nullptr);
1754             pViewItem->SetFormNode(pNewNode);
1755           }
1756           break;
1757         }
1758         case XFA_Element::ContentArea: {
1759           CXFA_Node* pParentNode = pViewItem->GetParent()->GetFormNode();
1760           for (CXFA_Node* pChildNode = pParentNode->GetFirstChild(); pChildNode;
1761                pChildNode = pChildNode->GetNextSibling()) {
1762             if (pChildNode->GetTemplateNodeIfExists() !=
1763                 pViewItem->GetFormNode()) {
1764               continue;
1765             }
1766             pViewItem->SetFormNode(pChildNode);
1767             break;
1768           }
1769           break;
1770         }
1771         default:
1772           break;
1773       }
1774     }
1775     if (!pPendingPageSet->GetParent()) {
1776       CXFA_Node* pNode = ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Form));
1777       if (pNode) {
1778         CXFA_Node* pFormToplevelSubform =
1779             pNode->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
1780         if (pFormToplevelSubform)
1781           pFormToplevelSubform->InsertChildAndNotify(pPendingPageSet, nullptr);
1782       }
1783     }
1784     pDocument->DataMerge_UpdateBindingRelations(pPendingPageSet);
1785     pPendingPageSet->SetInitializedFlagAndNotify();
1786   }
1787 
1788   CXFA_Node* pPageSet = GetRootLayoutItem()->GetFormNode();
1789   while (pPageSet) {
1790     CXFA_Node* pNextPageSet =
1791         pPageSet->GetNextSameClassSibling<CXFA_PageSet>(XFA_Element::PageSet);
1792     CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
1793         sIterator(pPageSet);
1794     CXFA_Node* pNode = sIterator.GetCurrent();
1795     while (pNode) {
1796       if (pNode->IsUnusedNode()) {
1797         if (pNode->IsContainerNode()) {
1798           XFA_Element eType = pNode->GetElementType();
1799           if (eType == XFA_Element::PageArea || eType == XFA_Element::PageSet) {
1800             CXFA_ContainerIterator iteChild(pNode);
1801             CXFA_Node* pChildNode = iteChild.MoveToNext();
1802             for (; pChildNode; pChildNode = iteChild.MoveToNext()) {
1803               CXFA_LayoutItem* pLayoutItem =
1804                   pChildNode->JSObject()->GetLayoutItem();
1805               if (pLayoutItem) {
1806                 pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
1807                 pLayoutItem->RemoveSelfIfParented();
1808               }
1809             }
1810           } else if (eType != XFA_Element::ContentArea) {
1811             CXFA_LayoutItem* pLayoutItem = pNode->JSObject()->GetLayoutItem();
1812             if (pLayoutItem) {
1813               pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
1814               pLayoutItem->RemoveSelfIfParented();
1815             }
1816           }
1817           CXFA_Node* pNext = sIterator.SkipChildrenAndMoveToNext();
1818           pNode->GetParent()->RemoveChildAndNotify(pNode, true);
1819           pNode = pNext;
1820         } else {
1821           pNode->ClearFlag(XFA_NodeFlag::kUnusedNode);
1822           pNode->SetInitializedFlagAndNotify();
1823           pNode = sIterator.MoveToNext();
1824         }
1825       } else {
1826         pNode->SetInitializedFlagAndNotify();
1827         pNode = sIterator.MoveToNext();
1828       }
1829     }
1830     pPageSet = pNextPageSet;
1831   }
1832 }
1833 
LayoutPageSetContents()1834 void CXFA_ViewLayoutProcessor::LayoutPageSetContents() {
1835   for (CXFA_ViewLayoutItem* pRootLayoutItem = GetRootLayoutItem();
1836        pRootLayoutItem;
1837        pRootLayoutItem = ToViewLayoutItem(pRootLayoutItem->GetNextSibling())) {
1838     ViewLayoutItemIterator iterator(pRootLayoutItem);
1839     for (CXFA_ViewLayoutItem* pViewItem = iterator.GetCurrent(); pViewItem;
1840          pViewItem = iterator.MoveToNext()) {
1841       XFA_Element type = pViewItem->GetFormNode()->GetElementType();
1842       if (type != XFA_Element::PageArea)
1843         continue;
1844 
1845       m_pLayoutProcessor->GetRootContentLayoutProcessor()->DoLayoutPageArea(
1846           pViewItem);
1847     }
1848   }
1849 }
1850 
SyncLayoutData()1851 void CXFA_ViewLayoutProcessor::SyncLayoutData() {
1852   MergePageSetContents();
1853   LayoutPageSetContents();
1854   CXFA_FFNotify* pNotify = m_pPageSetNode->GetDocument()->GetNotify();
1855   int32_t nPageIdx = -1;
1856   for (CXFA_ViewLayoutItem* pRootLayoutItem = GetRootLayoutItem();
1857        pRootLayoutItem;
1858        pRootLayoutItem = ToViewLayoutItem(pRootLayoutItem->GetNextSibling())) {
1859     ViewLayoutItemIterator iteratorParent(pRootLayoutItem);
1860     for (CXFA_ViewLayoutItem* pViewItem = iteratorParent.GetCurrent();
1861          pViewItem; pViewItem = iteratorParent.MoveToNext()) {
1862       XFA_Element type = pViewItem->GetFormNode()->GetElementType();
1863       if (type != XFA_Element::PageArea)
1864         continue;
1865 
1866       nPageIdx++;
1867       Mask<XFA_WidgetStatus> dwRelevant = {XFA_WidgetStatus::kViewable,
1868                                            XFA_WidgetStatus::kPrintable};
1869       CXFA_LayoutItemIterator iterator(pViewItem);
1870       CXFA_LayoutItem* pChildLayoutItem = iterator.GetCurrent();
1871       while (pChildLayoutItem) {
1872         CXFA_ContentLayoutItem* pContentItem =
1873             pChildLayoutItem->AsContentLayoutItem();
1874         if (!pContentItem) {
1875           pChildLayoutItem = iterator.MoveToNext();
1876           continue;
1877         }
1878 
1879         XFA_AttributeValue presence =
1880             pContentItem->GetFormNode()
1881                 ->JSObject()
1882                 ->TryEnum(XFA_Attribute::Presence, true)
1883                 .value_or(XFA_AttributeValue::Visible);
1884         bool bVisible = presence == XFA_AttributeValue::Visible;
1885         Mask<XFA_WidgetStatus> dwRelevantChild =
1886             GetRelevant(pContentItem->GetFormNode(), dwRelevant);
1887         SyncContainer(pNotify, m_pLayoutProcessor, pContentItem,
1888                       dwRelevantChild, bVisible, nPageIdx);
1889         pChildLayoutItem = iterator.SkipChildrenAndMoveToNext();
1890       }
1891     }
1892   }
1893 
1894   int32_t nPage = fxcrt::CollectionSize<int32_t>(m_PageArray);
1895   for (int32_t i = nPage - 1; i >= m_nAvailPages; i--) {
1896     CXFA_ViewLayoutItem* pPage = m_PageArray[i];
1897     m_PageArray.erase(m_PageArray.begin() + i);
1898     pNotify->OnPageViewEvent(pPage, CXFA_FFDoc::PageViewEvent::kPostRemoved);
1899   }
1900   ClearData();
1901 }
1902 
PrepareLayout()1903 void CXFA_ViewLayoutProcessor::PrepareLayout() {
1904   m_pPageSetCurLayoutItem = nullptr;
1905   m_ePageSetMode = XFA_AttributeValue::OrderedOccurrence;
1906   m_nAvailPages = 0;
1907   ClearData();
1908   if (!m_pPageSetRootLayoutItem)
1909     return;
1910 
1911   CXFA_ViewLayoutItem* pRootLayoutItem = m_pPageSetRootLayoutItem;
1912   if (pRootLayoutItem &&
1913       pRootLayoutItem->GetFormNode()->GetPacketType() == XFA_PacketType::Form) {
1914     CXFA_Document* const pRootDocument =
1915         pRootLayoutItem->GetFormNode()->GetDocument();
1916     CXFA_Node* pPageSetFormNode = pRootLayoutItem->GetFormNode();
1917     pRootDocument->ClearPendingNodes();
1918     if (pPageSetFormNode->HasRemovedChildren()) {
1919       XFA_ReleaseLayoutItem(pRootLayoutItem);
1920       m_pPageSetRootLayoutItem = nullptr;
1921       pRootLayoutItem = nullptr;
1922       pPageSetFormNode = nullptr;
1923       m_PageArray.clear();
1924     }
1925     while (pPageSetFormNode) {
1926       CXFA_Node* pNextPageSet =
1927           pPageSetFormNode->GetNextSameClassSibling<CXFA_PageSet>(
1928               XFA_Element::PageSet);
1929       pPageSetFormNode->GetParent()->RemoveChildAndNotify(pPageSetFormNode,
1930                                                           false);
1931       pRootDocument->AppendPendingNode(pPageSetFormNode);
1932       pPageSetFormNode = pNextPageSet;
1933     }
1934   }
1935   pRootLayoutItem = m_pPageSetRootLayoutItem;
1936   CXFA_ViewLayoutItem* pNextLayout = nullptr;
1937   for (; pRootLayoutItem; pRootLayoutItem = pNextLayout) {
1938     pNextLayout = ToViewLayoutItem(pRootLayoutItem->GetNextSibling());
1939     SaveLayoutItemChildren(pRootLayoutItem);
1940     pRootLayoutItem->RemoveSelfIfParented();
1941   }
1942   m_pPageSetRootLayoutItem = nullptr;
1943 }
1944 
ProcessSimplexOrDuplexPageSets(CXFA_ViewLayoutItem * pPageSetLayoutItem,bool bIsSimplex)1945 void CXFA_ViewLayoutProcessor::ProcessSimplexOrDuplexPageSets(
1946     CXFA_ViewLayoutItem* pPageSetLayoutItem,
1947     bool bIsSimplex) {
1948   size_t nPageAreaCount;
1949   CXFA_LayoutItem* pLastPageAreaLayoutItem;
1950   std::tie(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