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