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