Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
cxfa_viewlayoutprocessor.cpp
Go to the documentation of this file.
1// Copyright 2014 The PDFium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "xfa/fxfa/layout/cxfa_viewlayoutprocessor.h"
8
9#include <utility>
10
11#include "core/fxcrt/stl_util.h"
12#include "fxjs/gc/container_trace.h"
13#include "fxjs/xfa/cfxjse_engine.h"
14#include "fxjs/xfa/cjx_object.h"
15#include "third_party/base/check.h"
16#include "xfa/fxfa/cxfa_ffnotify.h"
17#include "xfa/fxfa/cxfa_ffpageview.h"
18#include "xfa/fxfa/layout/cxfa_contentlayoutitem.h"
19#include "xfa/fxfa/layout/cxfa_contentlayoutprocessor.h"
20#include "xfa/fxfa/layout/cxfa_layoutprocessor.h"
21#include "xfa/fxfa/layout/cxfa_traversestrategy_layoutitem.h"
22#include "xfa/fxfa/layout/cxfa_viewlayoutitem.h"
23#include "xfa/fxfa/parser/cxfa_contentarea.h"
24#include "xfa/fxfa/parser/cxfa_document.h"
25#include "xfa/fxfa/parser/cxfa_localemgr.h"
26#include "xfa/fxfa/parser/cxfa_measurement.h"
27#include "xfa/fxfa/parser/cxfa_medium.h"
28#include "xfa/fxfa/parser/cxfa_node.h"
29#include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
30#include "xfa/fxfa/parser/cxfa_object.h"
31#include "xfa/fxfa/parser/cxfa_occur.h"
32#include "xfa/fxfa/parser/cxfa_pageset.h"
33#include "xfa/fxfa/parser/cxfa_subform.h"
34#include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
35#include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
36#include "xfa/fxfa/parser/xfa_document_datamerger_imp.h"
37
38namespace {
39
40class TraverseStrategy_ViewLayoutItem {
41 public:
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
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
62 static CXFA_ViewLayoutItem* GetParent(CXFA_ViewLayoutItem* pLayoutItem) {
63 return ToViewLayoutItem(pLayoutItem->GetParent());
64 }
65};
66
67using ViewLayoutItemIterator =
68 CXFA_NodeIteratorTemplate<CXFA_ViewLayoutItem,
69 TraverseStrategy_ViewLayoutItem>;
70
71class TraverseStrategy_PageSet {
72 public:
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
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
100 static CXFA_ViewLayoutItem* GetParent(CXFA_ViewLayoutItem* pLayoutItem) {
101 return ToViewLayoutItem(pLayoutItem->GetParent());
102 }
103};
104
105using PageSetIterator =
106 CXFA_NodeIteratorTemplate<CXFA_ViewLayoutItem, TraverseStrategy_PageSet>;
107
108Mask<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
131void 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
164CXFA_Node* ResolveBreakTarget(CXFA_Node* pPageSetRoot,
165 bool bNewExprStyle,
166 WideString* pTargetAll) {
167 if (!pPageSetRoot)
168 return nullptr;
169
170 CXFA_Document* pDocument = pPageSetRoot->GetDocument();
171 if (pTargetAll->IsEmpty())
172 return nullptr;
173
174 pTargetAll->Trim();
175 size_t iSplitIndex = 0;
176 bool bTargetAllFind = true;
177 while (true) {
178 WideString wsExpr;
179 absl::optional<size_t> iSplitNextIndex = 0;
180 if (!bTargetAllFind) {
181 iSplitNextIndex = pTargetAll->Find(' ', iSplitIndex);
182 if (!iSplitNextIndex.has_value())
183 return nullptr;
184 wsExpr = pTargetAll->Substr(iSplitIndex,
185 iSplitNextIndex.value() - iSplitIndex);
186 } else {
187 wsExpr = *pTargetAll;
188 }
189 if (wsExpr.IsEmpty())
190 return nullptr;
191
192 bTargetAllFind = false;
193 if (wsExpr[0] == '#') {
194 CXFA_Node* pNode = pDocument->GetNodeByID(
196 wsExpr.Last(wsExpr.GetLength() - 1).AsStringView());
197 if (pNode)
198 return pNode;
199 } else if (bNewExprStyle) {
200 WideString wsProcessedTarget = wsExpr;
201 if (wsExpr.First(4).EqualsASCII("som(") && wsExpr.Back() == L')')
202 wsProcessedTarget = wsExpr.Substr(4, wsExpr.GetLength() - 5);
203
204 absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
205 pDocument->GetScriptContext()->ResolveObjects(
206 pPageSetRoot, wsProcessedTarget.AsStringView(),
207 Mask<XFA_ResolveFlag>{
208 XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kProperties,
209 XFA_ResolveFlag::kAttributes, XFA_ResolveFlag::kSiblings,
210 XFA_ResolveFlag::kParent});
211 if (maybeResult.has_value() &&
212 maybeResult.value().objects.front()->IsNode()) {
213 return maybeResult.value().objects.front()->AsNode();
214 }
215 }
216 iSplitIndex = iSplitNextIndex.value();
217 }
218}
219
220void SetLayoutGeneratedNodeFlag(CXFA_Node* pNode) {
223}
224
225// Note: Returning nullptr is not the same as returning absl::nullopt.
226absl::optional<CXFA_ViewLayoutItem*> CheckContentAreaNotUsed(
227 CXFA_ViewLayoutItem* pPageAreaLayoutItem,
228 CXFA_Node* pContentArea) {
229 for (CXFA_LayoutItem* pChild = pPageAreaLayoutItem->GetFirstChild(); pChild;
230 pChild = pChild->GetNextSibling()) {
231 CXFA_ViewLayoutItem* pLayoutItem = pChild->AsViewLayoutItem();
232 if (pLayoutItem && pLayoutItem->GetFormNode() == pContentArea) {
233 if (!pLayoutItem->GetFirstChild())
234 return pLayoutItem;
235 return absl::nullopt;
236 }
237 }
238 return nullptr;
239}
240
241void 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
254bool 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
262float 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
273std::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
283std::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
301bool 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(
316 if (rgUsedHeights[iCurContentAreaIndex] > fHeight)
317 return false;
318
319 ++iCurContentAreaIndex;
320 }
321 return true;
322}
323
324} // namespace
325
326CXFA_ViewLayoutProcessor::CXFA_ViewRecord::CXFA_ViewRecord() = default;
327
328CXFA_ViewLayoutProcessor::CXFA_ViewRecord::~CXFA_ViewRecord() = default;
329
330void CXFA_ViewLayoutProcessor::CXFA_ViewRecord::Trace(
331 cppgc::Visitor* visitor) const {
332 visitor->Trace(pCurPageSet);
333 visitor->Trace(pCurPageArea);
334 visitor->Trace(pCurContentArea);
335}
336
337CXFA_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
345
347 ClearData();
349 while (pLayoutItem) {
350 CXFA_LayoutItem* pNextLayout = pLayoutItem->GetNextSibling();
351 XFA_ReleaseLayoutItem(pLayoutItem);
352 pLayoutItem = pNextLayout;
353 }
354}
355
356void 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
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);
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(
436 pContentArea->JSObject()->SetMeasure(
438 pContentArea->JSObject()->SetMeasure(
440 pContentArea->JSObject()->SetMeasure(
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);
453 pMedium->JSObject()->SetMeasure(
455 pMedium->JSObject()->SetMeasure(
457 }
458 return true;
459}
460
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
498bool 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
511void 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
531 CXFA_ContentLayoutItem* pContentLayoutItem,
533 if (pContentLayoutItem) {
534 CXFA_ViewRecord* pViewRecord = GetCurrentViewRecord();
535 if (!pViewRecord)
536 return;
537
538 pViewRecord->pCurContentArea->AppendLastChild(pContentLayoutItem);
539 m_bCreateOverFlowPage = false;
540 }
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
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(
562 if (fAvailHeight >= kXFALayoutPrecision)
563 return fAvailHeight;
564 if (m_CurrentViewRecordIter == m_ProposedViewRecords.begin())
565 return 0.0f;
566 return FLT_MAX;
567}
568
569void CXFA_ViewLayoutProcessor::AppendNewRecord(CXFA_ViewRecord* pNewRecord) {
570 m_ProposedViewRecords.emplace_back(pNewRecord);
571}
572
573CXFA_ViewLayoutProcessor::CXFA_ViewRecord*
574CXFA_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
644CXFA_ViewLayoutProcessor::CXFA_ViewRecord*
645CXFA_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
657void 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,
675 pNewPageAreaLayoutItem = pViewItem;
676 }
677 pNewRecord->pCurPageSet->AppendLastChild(pNewPageAreaLayoutItem);
678 pNewRecord->pCurPageArea = pNewPageAreaLayoutItem;
679 pNewRecord->pCurContentArea = nullptr;
680}
681
682void 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
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
722 return fxcrt::CollectionSize<int32_t>(m_PageArray);
723}
724
725CXFA_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
732 const CXFA_ViewLayoutItem* pPage) const {
733 auto it = std::find(m_PageArray.begin(), m_PageArray.end(), pPage);
734 return it != m_PageArray.end()
735 ? pdfium::base::checked_cast<int32_t>(it - m_PageArray.begin())
736 : -1;
737}
738
739bool 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
781bool CXFA_ViewLayoutProcessor::ShouldGetNextPageArea(CXFA_Node* pTarget,
782 bool bStartNew) const {
783 return bStartNew || !pTarget || !HasCurrentViewRecord() ||
784 pTarget != GetCurrentViewRecord()->pCurPageArea->GetFormNode();
785}
786
788CXFA_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
858 return ProcessBreakBeforeOrAfter(pBreakNode, /*bBefore=*/true);
859}
860
863 return ProcessBreakBeforeOrAfter(pBreakNode, /*bBefore=*/false);
864}
865
866absl::optional<CXFA_ViewLayoutProcessor::BreakData>
867CXFA_ViewLayoutProcessor::ProcessBreakBeforeOrAfter(const CXFA_Node* pBreakNode,
868 bool bBefore) {
869 CXFA_Node* pFormNode = pBreakNode->GetContainerParent();
870 if (!pFormNode->PresenceRequiresSpace())
871 return absl::nullopt;
872
873 BreakData break_data = ExecuteBreakBeforeOrAfter(pBreakNode, bBefore);
874 CXFA_Document* pDocument = pBreakNode->GetDocument();
875 CXFA_Node* pDataScope = nullptr;
876 pFormNode = pFormNode->GetContainerParent();
877 if (break_data.pLeader) {
878 if (!break_data.pLeader->IsContainerNode())
879 return absl::nullopt;
880
881 pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
882 break_data.pLeader = pDocument->DataMerge_CopyContainer(
883 break_data.pLeader, pFormNode, pDataScope, true, true, true);
884 if (!break_data.pLeader)
885 return absl::nullopt;
886
888 SetLayoutGeneratedNodeFlag(break_data.pLeader);
889 }
890 if (break_data.pTrailer) {
891 if (!break_data.pTrailer->IsContainerNode())
892 return absl::nullopt;
893
894 if (!pDataScope)
895 pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
896
897 break_data.pTrailer = pDocument->DataMerge_CopyContainer(
898 break_data.pTrailer, pFormNode, pDataScope, true, true, true);
899 if (!break_data.pTrailer)
900 return absl::nullopt;
901
903 SetLayoutGeneratedNodeFlag(break_data.pTrailer);
904 }
905 return break_data;
906}
907
909 const CXFA_Node* pBookendNode) {
910 return ProcessBookendLeaderOrTrailer(pBookendNode, /*bLeader=*/true);
911}
912
914 const CXFA_Node* pBookendNode) {
915 return ProcessBookendLeaderOrTrailer(pBookendNode, /*bLeader=*/false);
916}
917
918CXFA_Node* CXFA_ViewLayoutProcessor::ProcessBookendLeaderOrTrailer(
919 const CXFA_Node* pBookendNode,
920 bool bLeader) {
921 CXFA_Node* pFormNode = pBookendNode->GetContainerParent();
922 CXFA_Node* pLeaderTemplate =
923 ResolveBookendLeaderOrTrailer(pBookendNode, bLeader);
924 if (!pLeaderTemplate)
925 return nullptr;
926
927 CXFA_Document* pDocument = pBookendNode->GetDocument();
928 CXFA_Node* pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
929 CXFA_Node* pBookendAppendNode = pDocument->DataMerge_CopyContainer(
930 pLeaderTemplate, pFormNode, pDataScope, true, true, true);
931 if (!pBookendAppendNode)
932 return nullptr;
933
934 pDocument->DataMerge_UpdateBindingRelations(pBookendAppendNode);
935 SetLayoutGeneratedNodeFlag(pBookendAppendNode);
936 return pBookendAppendNode;
937}
938
939bool CXFA_ViewLayoutProcessor::BreakOverflow(const CXFA_Node* pOverflowNode,
940 bool bCreatePage,
941 CXFA_Node** pLeaderTemplate,
942 CXFA_Node** pTrailerTemplate) {
943 CXFA_Node* pContainer =
945 if (pOverflowNode->GetElementType() == XFA_Element::Break) {
946 WideString wsOverflowLeader =
947 pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowLeader);
948 WideString wsOverflowTarget =
949 pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowTarget);
950 WideString wsOverflowTrailer =
951 pOverflowNode->JSObject()->GetCData(XFA_Attribute::OverflowTrailer);
952 if (wsOverflowTarget.IsEmpty() && wsOverflowLeader.IsEmpty() &&
953 wsOverflowTrailer.IsEmpty()) {
954 return false;
955 }
956
957 if (!wsOverflowTarget.IsEmpty() && bCreatePage && !m_bCreateOverFlowPage) {
958 CXFA_Node* pTarget =
959 ResolveBreakTarget(m_pPageSetNode, true, &wsOverflowTarget);
960 if (pTarget) {
961 m_bCreateOverFlowPage = true;
962 switch (pTarget->GetElementType()) {
963 case XFA_Element::PageArea:
964 RunBreak(XFA_Element::Overflow, XFA_AttributeValue::PageArea,
965 pTarget, true);
966 break;
967 case XFA_Element::ContentArea:
968 RunBreak(XFA_Element::Overflow, XFA_AttributeValue::ContentArea,
969 pTarget, true);
970 break;
971 default:
972 break;
973 }
974 }
975 }
976 if (!bCreatePage) {
977 *pLeaderTemplate =
978 ResolveBreakTarget(pContainer, true, &wsOverflowLeader);
979 *pTrailerTemplate =
980 ResolveBreakTarget(pContainer, true, &wsOverflowTrailer);
981 }
982 return true;
983 }
984
985 if (pOverflowNode->GetElementType() != XFA_Element::Overflow)
986 return false;
987
988 WideString wsOverflowTarget =
989 pOverflowNode->JSObject()->GetCData(XFA_Attribute::Target);
990 if (!wsOverflowTarget.IsEmpty() && bCreatePage && !m_bCreateOverFlowPage) {
991 CXFA_Node* pTarget =
992 ResolveBreakTarget(m_pPageSetNode, true, &wsOverflowTarget);
993 if (pTarget) {
994 m_bCreateOverFlowPage = true;
995 switch (pTarget->GetElementType()) {
996 case XFA_Element::PageArea:
997 RunBreak(XFA_Element::Overflow, XFA_AttributeValue::PageArea, pTarget,
998 true);
999 break;
1000 case XFA_Element::ContentArea:
1001 RunBreak(XFA_Element::Overflow, XFA_AttributeValue::ContentArea,
1002 pTarget, true);
1003 break;
1004 default:
1005 break;
1006 }
1007 }
1008 }
1009 if (!bCreatePage) {
1010 WideString wsLeader =
1011 pOverflowNode->JSObject()->GetCData(XFA_Attribute::Leader);
1012 WideString wsTrailer =
1013 pOverflowNode->JSObject()->GetCData(XFA_Attribute::Trailer);
1014 *pLeaderTemplate = ResolveBreakTarget(pContainer, true, &wsLeader);
1015 *pTrailerTemplate = ResolveBreakTarget(pContainer, true, &wsTrailer);
1016 }
1017 return true;
1018}
1019
1022 bool bCreatePage) {
1023 if (!pFormNode)
1024 return absl::nullopt;
1025
1026 CXFA_Node* pLeaderTemplate = nullptr;
1027 CXFA_Node* pTrailerTemplate = nullptr;
1028 bool bIsOverflowNode = pFormNode->GetElementType() == XFA_Element::Overflow ||
1029 pFormNode->GetElementType() == XFA_Element::Break;
1030 OverflowData overflow_data{nullptr, nullptr};
1031 for (CXFA_Node* pCurNode = bIsOverflowNode ? pFormNode
1032 : pFormNode->GetFirstChild();
1033 pCurNode; pCurNode = pCurNode->GetNextSibling()) {
1034 if (BreakOverflow(pCurNode, bCreatePage, &pLeaderTemplate,
1035 &pTrailerTemplate)) {
1036 if (bIsOverflowNode)
1037 pFormNode = pCurNode->GetParent();
1038
1039 CXFA_Document* pDocument = pCurNode->GetDocument();
1040 CXFA_Node* pDataScope = nullptr;
1041 if (pLeaderTemplate) {
1042 pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
1043
1044 overflow_data.pLeader = pDocument->DataMerge_CopyContainer(
1045 pLeaderTemplate, pFormNode, pDataScope, true, true, true);
1046 if (!overflow_data.pLeader)
1047 return absl::nullopt;
1048
1050 SetLayoutGeneratedNodeFlag(overflow_data.pLeader);
1051 }
1052 if (pTrailerTemplate) {
1053 if (!pDataScope)
1054 pDataScope = XFA_DataMerge_FindDataScope(pFormNode);
1055
1056 overflow_data.pTrailer = pDocument->DataMerge_CopyContainer(
1057 pTrailerTemplate, pFormNode, pDataScope, true, true, true);
1058 if (!overflow_data.pTrailer)
1059 return absl::nullopt;
1060
1062 SetLayoutGeneratedNodeFlag(overflow_data.pTrailer);
1063 }
1064 return overflow_data;
1065 }
1066 if (bIsOverflowNode)
1067 break;
1068 }
1069 return absl::nullopt;
1070}
1071
1072CXFA_Node* CXFA_ViewLayoutProcessor::ResolveBookendLeaderOrTrailer(
1073 const CXFA_Node* pBookendNode,
1074 bool bLeader) {
1075 CXFA_Node* pContainer =
1077 if (pBookendNode->GetElementType() == XFA_Element::Break) {
1078 WideString leader = pBookendNode->JSObject()->GetCData(
1079 bLeader ? XFA_Attribute::BookendLeader : XFA_Attribute::BookendTrailer);
1080 if (leader.IsEmpty())
1081 return nullptr;
1082 return ResolveBreakTarget(pContainer, false, &leader);
1083 }
1084
1085 if (pBookendNode->GetElementType() != XFA_Element::Bookend)
1086 return nullptr;
1087
1088 WideString leader = pBookendNode->JSObject()->GetCData(
1089 bLeader ? XFA_Attribute::Leader : XFA_Attribute::Trailer);
1090 return ResolveBreakTarget(pContainer, true, &leader);
1091}
1092
1093bool CXFA_ViewLayoutProcessor::FindPageAreaFromPageSet(
1094 CXFA_Node* pPageSet,
1095 CXFA_Node* pStartChild,
1096 CXFA_Node* pTargetPageArea,
1097 CXFA_Node* pTargetContentArea,
1098 bool bNewPage,
1099 bool bQuery) {
1100 if (!pPageSet && !pStartChild)
1101 return false;
1102
1103 if (IsPageSetRootOrderedOccurrence()) {
1104 return FindPageAreaFromPageSet_Ordered(pPageSet, pStartChild,
1105 pTargetPageArea, pTargetContentArea,
1106 bNewPage, bQuery);
1107 }
1108 XFA_AttributeValue ePreferredPosition = HasCurrentViewRecord()
1109 ? XFA_AttributeValue::Rest
1110 : XFA_AttributeValue::First;
1111 return FindPageAreaFromPageSet_SimplexDuplex(
1112 pPageSet, pStartChild, pTargetPageArea, pTargetContentArea, bNewPage,
1113 bQuery, ePreferredPosition);
1114}
1115
1116bool CXFA_ViewLayoutProcessor::FindPageAreaFromPageSet_Ordered(
1117 CXFA_Node* pPageSet,
1118 CXFA_Node* pStartChild,
1119 CXFA_Node* pTargetPageArea,
1120 CXFA_Node* pTargetContentArea,
1121 bool bNewPage,
1122 bool bQuery) {
1123 int32_t iPageSetCount = 0;
1124 if (!pStartChild && !bQuery) {
1125 auto it = m_pPageSetMap.find(pPageSet);
1126 if (it != m_pPageSetMap.end())
1127 iPageSetCount = it->second;
1128 int32_t iMax = -1;
1129 CXFA_Node* pOccurNode =
1130 pPageSet->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1131 if (pOccurNode) {
1132 absl::optional<int32_t> ret =
1133 pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
1134 if (ret.has_value())
1135 iMax = ret.value();
1136 }
1137 if (iMax >= 0 && iMax <= iPageSetCount)
1138 return false;
1139 }
1140
1141 bool bRes = false;
1142 CXFA_Node* pCurrentNode =
1143 pStartChild ? pStartChild->GetNextSibling() : pPageSet->GetFirstChild();
1144 for (; pCurrentNode; pCurrentNode = pCurrentNode->GetNextSibling()) {
1145 if (pCurrentNode->GetElementType() == XFA_Element::PageArea) {
1146 if ((pTargetPageArea == pCurrentNode || !pTargetPageArea)) {
1147 if (!pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1148 XFA_Element::ContentArea)) {
1149 if (pTargetPageArea == pCurrentNode) {
1150 CreateMinPageRecord(pCurrentNode, true, false);
1151 pTargetPageArea = nullptr;
1152 }
1153 continue;
1154 }
1155 if (!bQuery) {
1156 CXFA_ViewRecord* pNewRecord =
1157 CreateViewRecord(pCurrentNode, !pStartChild);
1158 AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
1159 if (!pTargetContentArea) {
1160 pTargetContentArea =
1161 pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1162 XFA_Element::ContentArea);
1163 }
1164 AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
1165 }
1166 m_pCurPageArea = pCurrentNode;
1167 m_nCurPageCount = 1;
1168 bRes = true;
1169 break;
1170 }
1171 if (!bQuery)
1172 CreateMinPageRecord(pCurrentNode, false, false);
1173 } else if (pCurrentNode->GetElementType() == XFA_Element::PageSet) {
1174 if (FindPageAreaFromPageSet_Ordered(pCurrentNode, nullptr,
1175 pTargetPageArea, pTargetContentArea,
1176 bNewPage, bQuery)) {
1177 bRes = true;
1178 break;
1179 }
1180 if (!bQuery)
1181 CreateMinPageSetRecord(pCurrentNode, true);
1182 }
1183 }
1184 if (!pStartChild && bRes && !bQuery)
1185 m_pPageSetMap[pPageSet] = ++iPageSetCount;
1186 return bRes;
1187}
1188
1189bool CXFA_ViewLayoutProcessor::FindPageAreaFromPageSet_SimplexDuplex(
1190 CXFA_Node* pPageSet,
1191 CXFA_Node* pStartChild,
1192 CXFA_Node* pTargetPageArea,
1193 CXFA_Node* pTargetContentArea,
1194 bool bNewPage,
1195 bool bQuery,
1196 XFA_AttributeValue ePreferredPosition) {
1197 const XFA_AttributeValue eFallbackPosition = XFA_AttributeValue::Any;
1198 CXFA_Node* pPreferredPageArea = nullptr;
1199 CXFA_Node* pFallbackPageArea = nullptr;
1200 CXFA_Node* pCurrentNode = nullptr;
1201 if (!pStartChild || pStartChild->GetElementType() == XFA_Element::PageArea)
1202 pCurrentNode = pPageSet->GetFirstChild();
1203 else
1204 pCurrentNode = pStartChild->GetNextSibling();
1205
1206 for (; pCurrentNode; pCurrentNode = pCurrentNode->GetNextSibling()) {
1207 if (pCurrentNode->GetElementType() == XFA_Element::PageArea) {
1208 if (!MatchPageAreaOddOrEven(pCurrentNode))
1209 continue;
1210
1211 XFA_AttributeValue eCurPagePosition =
1212 pCurrentNode->JSObject()->GetEnum(XFA_Attribute::PagePosition);
1213 if (ePreferredPosition == XFA_AttributeValue::Last) {
1214 if (eCurPagePosition != ePreferredPosition)
1215 continue;
1216 if (m_ePageSetMode == XFA_AttributeValue::SimplexPaginated ||
1217 pCurrentNode->JSObject()->GetEnum(XFA_Attribute::OddOrEven) ==
1218 XFA_AttributeValue::Any) {
1219 pPreferredPageArea = pCurrentNode;
1220 break;
1221 }
1222 CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
1223 AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
1224 AddContentAreaLayoutItem(
1225 pNewRecord, pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1226 XFA_Element::ContentArea));
1227 return false;
1228 }
1229 if (ePreferredPosition == XFA_AttributeValue::Only) {
1230 if (eCurPagePosition != ePreferredPosition)
1231 continue;
1232 if (m_ePageSetMode != XFA_AttributeValue::DuplexPaginated ||
1233 pCurrentNode->JSObject()->GetEnum(XFA_Attribute::OddOrEven) ==
1234 XFA_AttributeValue::Any) {
1235 pPreferredPageArea = pCurrentNode;
1236 break;
1237 }
1238 return false;
1239 }
1240 if ((pTargetPageArea == pCurrentNode || !pTargetPageArea)) {
1241 if (!pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1242 XFA_Element::ContentArea)) {
1243 if (pTargetPageArea == pCurrentNode) {
1244 CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
1245 AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
1246 pTargetPageArea = nullptr;
1247 }
1248 continue;
1249 }
1250 if ((ePreferredPosition == XFA_AttributeValue::Rest &&
1251 eCurPagePosition == XFA_AttributeValue::Any) ||
1252 eCurPagePosition == ePreferredPosition) {
1253 pPreferredPageArea = pCurrentNode;
1254 break;
1255 }
1256 if (eCurPagePosition == eFallbackPosition && !pFallbackPageArea) {
1257 pFallbackPageArea = pCurrentNode;
1258 }
1259 } else if (pTargetPageArea && !MatchPageAreaOddOrEven(pTargetPageArea)) {
1260 CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
1261 AddPageAreaLayoutItem(pNewRecord, pCurrentNode);
1262 AddContentAreaLayoutItem(
1263 pNewRecord, pCurrentNode->GetFirstChildByClass<CXFA_ContentArea>(
1264 XFA_Element::ContentArea));
1265 }
1266 } else if (pCurrentNode->GetElementType() == XFA_Element::PageSet) {
1267 if (FindPageAreaFromPageSet_SimplexDuplex(
1268 pCurrentNode, nullptr, pTargetPageArea, pTargetContentArea,
1269 bNewPage, bQuery, ePreferredPosition)) {
1270 break;
1271 }
1272 }
1273 }
1274
1275 CXFA_Node* pCurPageArea = nullptr;
1276 if (pPreferredPageArea)
1277 pCurPageArea = pPreferredPageArea;
1278 else if (pFallbackPageArea)
1279 pCurPageArea = pFallbackPageArea;
1280
1281 if (!pCurPageArea)
1282 return false;
1283
1284 if (!bQuery) {
1285 CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
1286 AddPageAreaLayoutItem(pNewRecord, pCurPageArea);
1287 if (!pTargetContentArea) {
1288 pTargetContentArea = pCurPageArea->GetFirstChildByClass<CXFA_ContentArea>(
1289 XFA_Element::ContentArea);
1290 }
1291 AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
1292 }
1293 m_pCurPageArea = pCurPageArea;
1294 return true;
1295}
1296
1297bool CXFA_ViewLayoutProcessor::MatchPageAreaOddOrEven(CXFA_Node* pPageArea) {
1298 if (m_ePageSetMode != XFA_AttributeValue::DuplexPaginated)
1299 return true;
1300
1301 absl::optional<XFA_AttributeValue> ret =
1302 pPageArea->JSObject()->TryEnum(XFA_Attribute::OddOrEven, true);
1303 if (!ret.has_value() || ret == XFA_AttributeValue::Any)
1304 return true;
1305
1306 int32_t iPageLast = GetPageCount() % 2;
1307 return ret == XFA_AttributeValue::Odd ? iPageLast == 0 : iPageLast == 1;
1308}
1309
1310CXFA_Node* CXFA_ViewLayoutProcessor::GetNextAvailPageArea(
1311 CXFA_Node* pTargetPageArea,
1312 CXFA_Node* pTargetContentArea,
1313 bool bNewPage,
1314 bool bQuery) {
1315 if (!m_pCurPageArea) {
1316 FindPageAreaFromPageSet(m_pPageSetNode, nullptr, pTargetPageArea,
1317 pTargetContentArea, bNewPage, bQuery);
1318 return m_pCurPageArea;
1319 }
1320
1321 if (!pTargetPageArea || pTargetPageArea == m_pCurPageArea) {
1322 if (!bNewPage && GetNextContentArea(pTargetContentArea))
1323 return m_pCurPageArea;
1324
1325 if (IsPageSetRootOrderedOccurrence()) {
1326 int32_t iMax = -1;
1327 CXFA_Node* pOccurNode =
1328 m_pCurPageArea->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1329 if (pOccurNode) {
1330 absl::optional<int32_t> ret =
1331 pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
1332 if (ret.has_value())
1333 iMax = ret.value();
1334 }
1335 if ((iMax < 0 || m_nCurPageCount < iMax)) {
1336 if (!bQuery) {
1337 CXFA_ViewRecord* pNewRecord = CreateViewRecord(m_pCurPageArea, false);
1338 AddPageAreaLayoutItem(pNewRecord, m_pCurPageArea);
1339 if (!pTargetContentArea) {
1340 pTargetContentArea =
1341 m_pCurPageArea->GetFirstChildByClass<CXFA_ContentArea>(
1342 XFA_Element::ContentArea);
1343 }
1344 AddContentAreaLayoutItem(pNewRecord, pTargetContentArea);
1345 }
1346 m_nCurPageCount++;
1347 return m_pCurPageArea;
1348 }
1349 }
1350 }
1351
1352 if (!bQuery && IsPageSetRootOrderedOccurrence())
1353 CreateMinPageRecord(m_pCurPageArea, false, true);
1354 if (FindPageAreaFromPageSet(m_pCurPageArea->GetParent(), m_pCurPageArea,
1355 pTargetPageArea, pTargetContentArea, bNewPage,
1356 bQuery)) {
1357 return m_pCurPageArea;
1358 }
1359
1360 CXFA_Node* pPageSet = m_pCurPageArea->GetParent();
1361 while (pPageSet) {
1362 if (FindPageAreaFromPageSet(pPageSet, nullptr, pTargetPageArea,
1363 pTargetContentArea, bNewPage, bQuery)) {
1364 return m_pCurPageArea;
1365 }
1366 if (!bQuery && IsPageSetRootOrderedOccurrence())
1367 CreateMinPageSetRecord(pPageSet, false);
1368 if (FindPageAreaFromPageSet(nullptr, pPageSet, pTargetPageArea,
1369 pTargetContentArea, bNewPage, bQuery)) {
1370 return m_pCurPageArea;
1371 }
1372 if (pPageSet == m_pPageSetNode)
1373 break;
1374
1375 pPageSet = pPageSet->GetParent();
1376 }
1377 return nullptr;
1378}
1379
1380bool CXFA_ViewLayoutProcessor::GetNextContentArea(CXFA_Node* pContentArea) {
1381 CXFA_Node* pCurContentNode =
1382 GetCurrentViewRecord()->pCurContentArea->GetFormNode();
1383 if (!pContentArea) {
1384 pContentArea = pCurContentNode->GetNextSameClassSibling<CXFA_ContentArea>(
1385 XFA_Element::ContentArea);
1386 if (!pContentArea)
1387 return false;
1388 } else {
1389 if (pContentArea->GetParent() != m_pCurPageArea)
1390 return false;
1391
1392 absl::optional<CXFA_ViewLayoutItem*> pContentAreaLayout =
1393 CheckContentAreaNotUsed(GetCurrentViewRecord()->pCurPageArea.Get(),
1394 pContentArea);
1395 if (!pContentAreaLayout.has_value())
1396 return false;
1397 if (pContentAreaLayout.value()) {
1398 if (pContentAreaLayout.value()->GetFormNode() == pCurContentNode)
1399 return false;
1400
1401 CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
1402 pNewRecord->pCurContentArea = pContentAreaLayout.value();
1403 return true;
1404 }
1405 }
1406
1407 CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
1408 AddContentAreaLayoutItem(pNewRecord, pContentArea);
1409 return true;
1410}
1411
1412void CXFA_ViewLayoutProcessor::InitPageSetMap() {
1413 if (!IsPageSetRootOrderedOccurrence())
1414 return;
1415
1416 CXFA_NodeIterator sIterator(m_pPageSetNode);
1417 for (CXFA_Node* pPageSetNode = sIterator.GetCurrent(); pPageSetNode;
1418 pPageSetNode = sIterator.MoveToNext()) {
1419 if (pPageSetNode->GetElementType() == XFA_Element::PageSet) {
1420 XFA_AttributeValue eRelation =
1421 pPageSetNode->JSObject()->GetEnum(XFA_Attribute::Relation);
1422 if (eRelation == XFA_AttributeValue::OrderedOccurrence)
1423 m_pPageSetMap[pPageSetNode] = 0;
1424 }
1425 }
1426}
1427
1428int32_t CXFA_ViewLayoutProcessor::CreateMinPageRecord(CXFA_Node* pPageArea,
1429 bool bTargetPageArea,
1430 bool bCreateLast) {
1431 if (!pPageArea)
1432 return 0;
1433
1434 int32_t iMin = 0;
1435 absl::optional<int32_t> ret;
1436 CXFA_Node* pOccurNode =
1437 pPageArea->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1438 if (pOccurNode) {
1439 ret = pOccurNode->JSObject()->TryInteger(XFA_Attribute::Min, false);
1440 if (ret.has_value())
1441 iMin = ret.value();
1442 }
1443
1444 if (!ret.has_value() && !bTargetPageArea)
1445 return iMin;
1446
1447 CXFA_Node* pContentArea = pPageArea->GetFirstChildByClass<CXFA_ContentArea>(
1448 XFA_Element::ContentArea);
1449 if (iMin < 1 && bTargetPageArea && !pContentArea)
1450 iMin = 1;
1451
1452 int32_t i = 0;
1453 if (bCreateLast)
1454 i = m_nCurPageCount;
1455
1456 for (; i < iMin; i++) {
1457 CXFA_ViewRecord* pNewRecord = CreateViewRecordSimple();
1458 AddPageAreaLayoutItem(pNewRecord, pPageArea);
1459 AddContentAreaLayoutItem(pNewRecord, pContentArea);
1460 }
1461 return iMin;
1462}
1463
1464void CXFA_ViewLayoutProcessor::CreateMinPageSetRecord(CXFA_Node* pPageSet,
1465 bool bCreateAll) {
1466 auto it = m_pPageSetMap.find(pPageSet);
1467 if (it == m_pPageSetMap.end())
1468 return;
1469
1470 int32_t iCurSetCount = it->second;
1471 if (bCreateAll)
1472 iCurSetCount = 0;
1473
1474 CXFA_Node* pOccurNode =
1475 pPageSet->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1476 if (!pOccurNode)
1477 return;
1478
1479 absl::optional<int32_t> iMin =
1480 pOccurNode->JSObject()->TryInteger(XFA_Attribute::Min, false);
1481 if (!iMin.has_value() || iCurSetCount >= iMin.value())
1482 return;
1483
1484 for (int32_t i = 0; i < iMin.value() - iCurSetCount; i++) {
1485 for (CXFA_Node* node = pPageSet->GetFirstChild(); node;
1486 node = node->GetNextSibling()) {
1487 if (node->GetElementType() == XFA_Element::PageArea)
1488 CreateMinPageRecord(node, false, false);
1489 else if (node->GetElementType() == XFA_Element::PageSet)
1490 CreateMinPageSetRecord(node, true);
1491 }
1492 }
1493 m_pPageSetMap[pPageSet] = iMin.value();
1494}
1495
1496void CXFA_ViewLayoutProcessor::CreateNextMinRecord(CXFA_Node* pRecordNode) {
1497 if (!pRecordNode)
1498 return;
1499
1500 for (CXFA_Node* pCurrentNode = pRecordNode->GetNextSibling(); pCurrentNode;
1501 pCurrentNode = pCurrentNode->GetNextSibling()) {
1502 if (pCurrentNode->GetElementType() == XFA_Element::PageArea)
1503 CreateMinPageRecord(pCurrentNode, false, false);
1504 else if (pCurrentNode->GetElementType() == XFA_Element::PageSet)
1505 CreateMinPageSetRecord(pCurrentNode, true);
1506 }
1507}
1508
1509void CXFA_ViewLayoutProcessor::ProcessLastPageSet() {
1510 if (!m_pCurPageArea)
1511 return;
1512
1513 CreateMinPageRecord(m_pCurPageArea, false, true);
1514 CreateNextMinRecord(m_pCurPageArea);
1515 CXFA_Node* pPageSet = m_pCurPageArea->GetParent();
1516 while (pPageSet) {
1517 CreateMinPageSetRecord(pPageSet, false);
1518 if (pPageSet == m_pPageSetNode)
1519 break;
1520
1521 CreateNextMinRecord(pPageSet);
1522 pPageSet = pPageSet->GetParent();
1523 }
1524}
1525
1527 CXFA_ViewRecord* pViewRecord = GetCurrentViewRecord();
1528 if (!pViewRecord)
1529 return false;
1530
1531 CXFA_Node* pCurContentNode = pViewRecord->pCurContentArea->GetFormNode();
1532 if (!pCurContentNode)
1533 return false;
1534
1535 pCurContentNode = pCurContentNode->GetNextSameClassSibling<CXFA_ContentArea>(
1536 XFA_Element::ContentArea);
1537 if (pCurContentNode) {
1538 float fNextContentHeight = pCurContentNode->JSObject()->GetMeasureInUnit(
1540 return fNextContentHeight > fChildHeight;
1541 }
1542
1543 CXFA_Node* pPageNode = GetCurrentViewRecord()->pCurPageArea->GetFormNode();
1544 CXFA_Node* pOccurNode =
1545 pPageNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
1546 int32_t iMax = 0;
1547 absl::optional<int32_t> ret;
1548 if (pOccurNode) {
1549 ret = pOccurNode->JSObject()->TryInteger(XFA_Attribute::Max, false);
1550 if (ret.has_value())
1551 iMax = ret.value();
1552 }
1553 if (ret.has_value()) {
1554 if (m_nCurPageCount == iMax) {
1555 CXFA_Node* pSrcPage = m_pCurPageArea;
1556 int32_t nSrcPageCount = m_nCurPageCount;
1557 auto psSrcIter = GetTailPosition();
1558 CXFA_Node* pNextPage =
1559 GetNextAvailPageArea(nullptr, nullptr, false, true);
1560 m_pCurPageArea = pSrcPage;
1561 m_nCurPageCount = nSrcPageCount;
1562 CXFA_ViewRecord* pPrevRecord = psSrcIter->Get();
1563 ++psSrcIter;
1564 while (psSrcIter != m_ProposedViewRecords.end()) {
1565 auto psSaveIter = psSrcIter++;
1566 RemoveLayoutRecord(psSaveIter->Get(), pPrevRecord);
1567 m_ProposedViewRecords.erase(psSaveIter);
1568 }
1569 if (pNextPage) {
1570 CXFA_Node* pContentArea =
1571 pNextPage->GetFirstChildByClass<CXFA_ContentArea>(
1572 XFA_Element::ContentArea);
1573 if (pContentArea) {
1574 float fNextContentHeight = pContentArea->JSObject()->GetMeasureInUnit(
1576 if (fNextContentHeight > fChildHeight)
1577 return true;
1578 }
1579 }
1580 return false;
1581 }
1582 }
1583
1584 CXFA_Node* pContentArea = pPageNode->GetFirstChildByClass<CXFA_ContentArea>(
1585 XFA_Element::ContentArea);
1586 if (!pContentArea)
1587 return false;
1588
1589 float fNextContentHeight = pContentArea->JSObject()->GetMeasureInUnit(
1591 return fNextContentHeight < kXFALayoutPrecision ||
1592 fNextContentHeight > fChildHeight;
1593}
1594
1595void CXFA_ViewLayoutProcessor::ClearData() {
1596 if (!m_pPageSetNode)
1597 return;
1598
1599 m_ProposedViewRecords.clear();
1600 m_CurrentViewRecordIter = m_ProposedViewRecords.end();
1601 m_pCurPageArea = nullptr;
1602 m_nCurPageCount = 0;
1603 m_bCreateOverFlowPage = false;
1604 m_pPageSetMap.clear();
1605}
1606
1607void CXFA_ViewLayoutProcessor::SaveLayoutItemChildren(
1608 CXFA_LayoutItem* pParentLayoutItem) {
1609 CXFA_Document* pDocument = m_pPageSetNode->GetDocument();
1610 CXFA_FFNotify* pNotify = pDocument->GetNotify();
1611 auto* pDocLayout = CXFA_LayoutProcessor::FromDocument(pDocument);
1612 CXFA_LayoutItem* pCurLayoutItem = pParentLayoutItem->GetFirstChild();
1613 while (pCurLayoutItem) {
1614 CXFA_LayoutItem* pNextLayoutItem = pCurLayoutItem->GetNextSibling();
1615 if (pCurLayoutItem->IsContentLayoutItem()) {
1616 if (pCurLayoutItem->GetFormNode()->HasRemovedChildren()) {
1617 SyncRemoveLayoutItem(pCurLayoutItem, pNotify, pDocLayout);
1618 pCurLayoutItem = pNextLayoutItem;
1619 continue;
1620 }
1623 }
1624 SaveLayoutItemChildren(pCurLayoutItem);
1625 pCurLayoutItem = pNextLayoutItem;
1626 }
1627}
1628
1630 for (CXFA_Node* pCurNode = pFormNode->GetFirstChild(); pCurNode;
1631 pCurNode = pCurNode->GetNextSibling()) {
1632 if (pCurNode->GetElementType() == XFA_Element::Break) {
1633 WideString wsOverflowLeader =
1634 pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowLeader);
1635 WideString wsOverflowTarget =
1636 pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowTarget);
1637 WideString wsOverflowTrailer =
1638 pCurNode->JSObject()->GetCData(XFA_Attribute::OverflowTrailer);
1639
1640 if (!wsOverflowLeader.IsEmpty() || !wsOverflowTrailer.IsEmpty() ||
1641 !wsOverflowTarget.IsEmpty()) {
1642 return pCurNode;
1643 }
1644 return nullptr;
1645 }
1646 if (pCurNode->GetElementType() == XFA_Element::Overflow)
1647 return pCurNode;
1648 }
1649 return nullptr;
1650}
1651
1652void CXFA_ViewLayoutProcessor::MergePageSetContents() {
1653 CXFA_Document* pDocument = m_pPageSetNode->GetDocument();
1655
1656 CXFA_FFNotify* pNotify = pDocument->GetNotify();
1657 auto* pDocLayout = CXFA_LayoutProcessor::FromDocument(pDocument);
1658 CXFA_ViewLayoutItem* pRootLayout = GetRootLayoutItem();
1659
1660 size_t pending_index = 0;
1661 for (; pRootLayout;
1662 pRootLayout = ToViewLayoutItem(pRootLayout->GetNextSibling())) {
1663 CXFA_Node* pPendingPageSet = nullptr;
1664 ViewLayoutItemIterator iterator(pRootLayout);
1665 CXFA_ViewLayoutItem* pRootPageSetViewItem = iterator.GetCurrent();
1666 DCHECK(pRootPageSetViewItem->GetFormNode()->GetElementType() ==
1667 XFA_Element::PageSet);
1668 if (pending_index < pDocument->GetPendingNodesCount()) {
1669 pPendingPageSet = pDocument->GetPendingNodeAtIndex(pending_index);
1670 ++pending_index;
1671 }
1672 if (!pPendingPageSet) {
1673 if (pRootPageSetViewItem->GetFormNode()->GetPacketType() ==
1674 XFA_PacketType::Template) {
1675 pPendingPageSet =
1676 pRootPageSetViewItem->GetFormNode()->CloneTemplateToForm(false);
1677 } else {
1678 pPendingPageSet = pRootPageSetViewItem->GetFormNode();
1679 }
1680 }
1681 if (pRootPageSetViewItem->GetFormNode()->JSObject()->GetLayoutItem() ==
1682 pRootPageSetViewItem) {
1683 pRootPageSetViewItem->GetFormNode()->JSObject()->SetLayoutItem(nullptr);
1684 }
1685 pRootPageSetViewItem->SetFormNode(pPendingPageSet);
1687 for (CXFA_ViewLayoutItem* pViewItem = iterator.MoveToNext(); pViewItem;
1688 pViewItem = iterator.MoveToNext()) {
1689 CXFA_Node* pNode = pViewItem->GetFormNode();
1690 if (pNode->GetPacketType() != XFA_PacketType::Template)
1691 continue;
1692
1693 switch (pNode->GetElementType()) {
1694 case XFA_Element::PageSet: {
1695 CXFA_Node* pParentNode = pViewItem->GetParent()->GetFormNode();
1696 CXFA_Node* pOldNode = pViewItem->GetFormNode();
1697 CXFA_Node* pNewNode = XFA_NodeMerge_CloneOrMergeContainer(
1698 pDocument, pParentNode, pOldNode, true, nullptr);
1699 if (pOldNode != pNewNode) {
1700 pOldNode->JSObject()->SetLayoutItem(nullptr);
1701 pViewItem->SetFormNode(pNewNode);
1702 }
1703 break;
1704 }
1705 case XFA_Element::PageArea: {
1706 CXFA_LayoutItem* pFormLayout = pViewItem;
1707 CXFA_Node* pParentNode = pViewItem->GetParent()->GetFormNode();
1708 bool bIsExistForm = true;
1709 for (int32_t iLevel = 0; iLevel < 3; iLevel++) {
1710 pFormLayout = pFormLayout->GetFirstChild();
1711 if (iLevel == 2) {
1712 while (pFormLayout &&
1714 pFormLayout = pFormLayout->GetNextSibling();
1715 }
1716 }
1717 if (!pFormLayout) {
1718 bIsExistForm = false;
1719 break;
1720 }
1721 }
1722 if (bIsExistForm) {
1723 CXFA_Node* pNewSubform = pFormLayout->GetFormNode();
1724 if (pViewItem->GetOldSubform() &&
1725 pViewItem->GetOldSubform() != pNewSubform) {
1726 CXFA_Node* pExistingNode = XFA_DataMerge_FindFormDOMInstance(
1727 pDocument, pViewItem->GetFormNode()->GetElementType(),
1728 pViewItem->GetFormNode()->GetNameHash(), pParentNode);
1729 CXFA_ContainerIterator sIterator(pExistingNode);
1730 for (CXFA_Node* pIter = sIterator.GetCurrent(); pIter;
1731 pIter = sIterator.MoveToNext()) {
1732 if (pIter->GetElementType() != XFA_Element::ContentArea) {
1733 CXFA_LayoutItem* pLayoutItem =
1734 pIter->JSObject()->GetLayoutItem();
1735 if (pLayoutItem) {
1736 pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
1737 pLayoutItem->RemoveSelfIfParented();
1738 }
1739 }
1740 }
1741 if (pExistingNode) {
1742 pParentNode->RemoveChildAndNotify(pExistingNode, true);
1743 }
1744 }
1745 pViewItem->SetOldSubform(pNewSubform);
1746 }
1747 CXFA_Node* pOldNode = pViewItem->GetFormNode();
1748 CXFA_Node* pNewNode = pDocument->DataMerge_CopyContainer(
1749 pOldNode, pParentNode,
1751 true);
1752 if (pOldNode != pNewNode) {
1753 pOldNode->JSObject()->SetLayoutItem(nullptr);
1754 pViewItem->SetFormNode(pNewNode);
1755 }
1756 break;
1757 }
1758 case XFA_Element::ContentArea: {
1759 CXFA_Node* pParentNode = pViewItem->GetParent()->GetFormNode();
1760 for (CXFA_Node* pChildNode = pParentNode->GetFirstChild(); pChildNode;
1761 pChildNode = pChildNode->GetNextSibling()) {
1762 if (pChildNode->GetTemplateNodeIfExists() !=
1763 pViewItem->GetFormNode()) {
1764 continue;
1765 }
1766 pViewItem->SetFormNode(pChildNode);
1767 break;
1768 }
1769 break;
1770 }
1771 default:
1772 break;
1773 }
1774 }
1775 if (!pPendingPageSet->GetParent()) {
1777 if (pNode) {
1778 CXFA_Node* pFormToplevelSubform =
1779 pNode->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
1780 if (pFormToplevelSubform)
1781 pFormToplevelSubform->InsertChildAndNotify(pPendingPageSet, nullptr);
1782 }
1783 }
1784 pDocument->DataMerge_UpdateBindingRelations(pPendingPageSet);
1785 pPendingPageSet->SetInitializedFlagAndNotify();
1786 }
1787
1789 while (pPageSet) {
1790 CXFA_Node* pNextPageSet =
1791 pPageSet->GetNextSameClassSibling<CXFA_PageSet>(XFA_Element::PageSet);
1792 CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
1793 sIterator(pPageSet);
1794 CXFA_Node* pNode = sIterator.GetCurrent();
1795 while (pNode) {
1796 if (pNode->IsUnusedNode()) {
1797 if (pNode->IsContainerNode()) {
1798 XFA_Element eType = pNode->GetElementType();
1799 if (eType == XFA_Element::PageArea || eType == XFA_Element::PageSet) {
1800 CXFA_ContainerIterator iteChild(pNode);
1801 CXFA_Node* pChildNode = iteChild.MoveToNext();
1802 for (; pChildNode; pChildNode = iteChild.MoveToNext()) {
1803 CXFA_LayoutItem* pLayoutItem =
1804 pChildNode->JSObject()->GetLayoutItem();
1805 if (pLayoutItem) {
1806 pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
1807 pLayoutItem->RemoveSelfIfParented();
1808 }
1809 }
1810 } else if (eType != XFA_Element::ContentArea) {
1811 CXFA_LayoutItem* pLayoutItem = pNode->JSObject()->GetLayoutItem();
1812 if (pLayoutItem) {
1813 pNotify->OnLayoutItemRemoving(pDocLayout, pLayoutItem);
1814 pLayoutItem->RemoveSelfIfParented();
1815 }
1816 }
1817 CXFA_Node* pNext = sIterator.SkipChildrenAndMoveToNext();
1818 pNode->GetParent()->RemoveChildAndNotify(pNode, true);
1819 pNode = pNext;
1820 } else {
1823 pNode = sIterator.MoveToNext();
1824 }
1825 } else {
1827 pNode = sIterator.MoveToNext();
1828 }
1829 }
1830 pPageSet = pNextPageSet;
1831 }
1832}
1833
1834void CXFA_ViewLayoutProcessor::LayoutPageSetContents() {
1835 for (CXFA_ViewLayoutItem* pRootLayoutItem = GetRootLayoutItem();
1836 pRootLayoutItem;
1837 pRootLayoutItem = ToViewLayoutItem(pRootLayoutItem->GetNextSibling())) {
1838 ViewLayoutItemIterator iterator(pRootLayoutItem);
1839 for (CXFA_ViewLayoutItem* pViewItem = iterator.GetCurrent(); pViewItem;
1840 pViewItem = iterator.MoveToNext()) {
1841 XFA_Element type = pViewItem->GetFormNode()->GetElementType();
1842 if (type != XFA_Element::PageArea)
1843 continue;
1844
1845 m_pLayoutProcessor->GetRootContentLayoutProcessor()->DoLayoutPageArea(
1846 pViewItem);
1847 }
1848 }
1849}
1850
1852 MergePageSetContents();
1853 LayoutPageSetContents();
1854 CXFA_FFNotify* pNotify = m_pPageSetNode->GetDocument()->GetNotify();
1855 int32_t nPageIdx = -1;
1856 for (CXFA_ViewLayoutItem* pRootLayoutItem = GetRootLayoutItem();
1857 pRootLayoutItem;
1858 pRootLayoutItem = ToViewLayoutItem(pRootLayoutItem->GetNextSibling())) {
1859 ViewLayoutItemIterator iteratorParent(pRootLayoutItem);
1860 for (CXFA_ViewLayoutItem* pViewItem = iteratorParent.GetCurrent();
1861 pViewItem; pViewItem = iteratorParent.MoveToNext()) {
1862 XFA_Element type = pViewItem->GetFormNode()->GetElementType();
1863 if (type != XFA_Element::PageArea)
1864 continue;
1865
1866 nPageIdx++;
1867 Mask<XFA_WidgetStatus> dwRelevant = {XFA_WidgetStatus::kViewable,
1868 XFA_WidgetStatus::kPrintable};
1869 CXFA_LayoutItemIterator iterator(pViewItem);
1870 CXFA_LayoutItem* pChildLayoutItem = iterator.GetCurrent();
1871 while (pChildLayoutItem) {
1872 CXFA_ContentLayoutItem* pContentItem =
1873 pChildLayoutItem->AsContentLayoutItem();
1874 if (!pContentItem) {
1875 pChildLayoutItem = iterator.MoveToNext();
1876 continue;
1877 }
1878
1879 XFA_AttributeValue presence =
1880 pContentItem->GetFormNode()
1881 ->JSObject()
1882 ->TryEnum(XFA_Attribute::Presence, true)
1883 .value_or(XFA_AttributeValue::Visible);
1884 bool bVisible = presence == XFA_AttributeValue::Visible;
1885 Mask<XFA_WidgetStatus> dwRelevantChild =
1886 GetRelevant(pContentItem->GetFormNode(), dwRelevant);
1887 SyncContainer(pNotify, m_pLayoutProcessor, pContentItem,
1888 dwRelevantChild, bVisible, nPageIdx);
1889 pChildLayoutItem = iterator.SkipChildrenAndMoveToNext();
1890 }
1891 }
1892 }
1893
1894 int32_t nPage = fxcrt::CollectionSize<int32_t>(m_PageArray);
1895 for (int32_t i = nPage - 1; i >= m_nAvailPages; i--) {
1896 CXFA_ViewLayoutItem* pPage = m_PageArray[i];
1897 m_PageArray.erase(m_PageArray.begin() + i);
1899 }
1900 ClearData();
1901}
1902
1903void CXFA_ViewLayoutProcessor::PrepareLayout() {
1904 m_pPageSetCurLayoutItem = nullptr;
1905 m_ePageSetMode = XFA_AttributeValue::OrderedOccurrence;
1906 m_nAvailPages = 0;
1907 ClearData();
1908 if (!m_pPageSetRootLayoutItem)
1909 return;
1910
1911 CXFA_ViewLayoutItem* pRootLayoutItem = m_pPageSetRootLayoutItem;
1912 if (pRootLayoutItem &&
1913 pRootLayoutItem->GetFormNode()->GetPacketType() == XFA_PacketType::Form) {
1914 CXFA_Document* const pRootDocument =
1915 pRootLayoutItem->GetFormNode()->GetDocument();
1916 CXFA_Node* pPageSetFormNode = pRootLayoutItem->GetFormNode();
1917 pRootDocument->ClearPendingNodes();
1918 if (pPageSetFormNode->HasRemovedChildren()) {
1919 XFA_ReleaseLayoutItem(pRootLayoutItem);
1920 m_pPageSetRootLayoutItem = nullptr;
1921 pRootLayoutItem = nullptr;
1922 pPageSetFormNode = nullptr;
1923 m_PageArray.clear();
1924 }
1925 while (pPageSetFormNode) {
1926 CXFA_Node* pNextPageSet =
1927 pPageSetFormNode->GetNextSameClassSibling<CXFA_PageSet>(
1928 XFA_Element::PageSet);
1929 pPageSetFormNode->GetParent()->RemoveChildAndNotify(pPageSetFormNode,
1930 false);
1931 pRootDocument->AppendPendingNode(pPageSetFormNode);
1932 pPageSetFormNode = pNextPageSet;
1933 }
1934 }
1935 pRootLayoutItem = m_pPageSetRootLayoutItem;
1936 CXFA_ViewLayoutItem* pNextLayout = nullptr;
1937 for (; pRootLayoutItem; pRootLayoutItem = pNextLayout) {
1938 pNextLayout = ToViewLayoutItem(pRootLayoutItem->GetNextSibling());
1939 SaveLayoutItemChildren(pRootLayoutItem);
1940 pRootLayoutItem->RemoveSelfIfParented();
1941 }
1942 m_pPageSetRootLayoutItem = nullptr;
1943}
1944
1945void CXFA_ViewLayoutProcessor::ProcessSimplexOrDuplexPageSets(
1946 CXFA_ViewLayoutItem* pPageSetLayoutItem,
1947 bool bIsSimplex) {
1948 size_t nPageAreaCount;
1949 CXFA_LayoutItem* pLastPageAreaLayoutItem;
1950 std::tie(nPageAreaCount, pLastPageAreaLayoutItem) =
1951 GetPageAreaCountAndLastPageAreaFromPageSet(pPageSetLayoutItem);
1952 if (!pLastPageAreaLayoutItem)
1953 return;
1954
1955 if (!FindPageAreaFromPageSet_SimplexDuplex(
1956 pPageSetLayoutItem->GetFormNode(), nullptr, nullptr, nullptr, true,
1957 true,
1958 nPageAreaCount == 1 ? XFA_AttributeValue::Only
1959 : XFA_AttributeValue::Last) &&
1960 (nPageAreaCount == 1 &&
1961 !FindPageAreaFromPageSet_SimplexDuplex(
1962 pPageSetLayoutItem->GetFormNode(), nullptr, nullptr, nullptr, true,
1963 true, XFA_AttributeValue::Last))) {
1964 return;
1965 }
1966
1967 CXFA_Node* pNode = m_pCurPageArea;
1968 XFA_AttributeValue eCurChoice =
1969 pNode->JSObject()->GetEnum(XFA_Attribute::PagePosition);
1970 if (eCurChoice == XFA_AttributeValue::Last) {
1971 XFA_AttributeValue eOddOrEven =
1972 pNode->JSObject()->GetEnum(XFA_Attribute::OddOrEven);
1973 XFA_AttributeValue eLastChoice =
1974 pLastPageAreaLayoutItem->GetFormNode()->JSObject()->GetEnum(
1975 XFA_Attribute::PagePosition);
1976 if (eLastChoice == XFA_AttributeValue::First &&
1977 (bIsSimplex || eOddOrEven != XFA_AttributeValue::Odd)) {
1978 CXFA_ViewRecord* pRecord = CreateViewRecordSimple();
1979 AddPageAreaLayoutItem(pRecord, pNode);
1980 return;
1981 }
1982 }
1983
1984 std::vector<float> rgUsedHeights =
1985 GetHeightsForContentAreas(pLastPageAreaLayoutItem);
1986 if (ContentAreasFitInPageAreas(pNode, rgUsedHeights)) {
1987 CXFA_LayoutItem* pChildLayoutItem =
1988 pLastPageAreaLayoutItem->GetFirstChild();
1989 CXFA_Node* pContentAreaNode = pNode->GetFirstChild();
1990 pLastPageAreaLayoutItem->SetFormNode(pNode);
1991 while (pChildLayoutItem && pContentAreaNode) {
1992 if (pChildLayoutItem->GetFormNode()->GetElementType() !=
1993 XFA_Element::ContentArea) {
1994 pChildLayoutItem = pChildLayoutItem->GetNextSibling();
1995 continue;
1996 }
1997 if (pContentAreaNode->GetElementType() != XFA_Element::ContentArea) {
1998 pContentAreaNode = pContentAreaNode->GetNextSibling();
1999 continue;
2000 }
2001 pChildLayoutItem->SetFormNode(pContentAreaNode);
2002 pChildLayoutItem = pChildLayoutItem->GetNextSibling();
2003 pContentAreaNode = pContentAreaNode->GetNextSibling();
2004 }
2005 return;
2006 }
2007
2008 if (pNode->JSObject()->GetEnum(XFA_Attribute::PagePosition) ==
2009 XFA_AttributeValue::Last) {
2010 CXFA_ViewRecord* pRecord = CreateViewRecordSimple();
2011 AddPageAreaLayoutItem(pRecord, pNode);
2012 }
2013}
CXFA_Node * GetNodeByID(CXFA_Node *pRoot, WideStringView wsID) const
CXFA_FFNotify * GetNotify() const
CXFA_Node * DataMerge_CopyContainer(CXFA_Node *pTemplateNode, CXFA_Node *pFormNode, CXFA_Node *pDataScope, bool bOneInstance, bool bDataMerge, bool bUpLevel)
void AppendPendingNode(CXFA_Node *node)
void DataMerge_UpdateBindingRelations(CXFA_Node *pFormUpdateRoot)
CXFA_Node * CreateNode(XFA_PacketType packet, XFA_Element eElement)
CXFA_Object * GetXFAObject(XFA_HashCode wsNodeNameHash)
void SetPendingNodesUnusedAndUnbound()
void OnLayoutItemAdded(CXFA_LayoutProcessor *pLayout, CXFA_LayoutItem *pSender, int32_t iPageIdx, Mask< XFA_WidgetStatus > dwStatus)
void OnPageViewEvent(CXFA_ViewLayoutItem *pSender, CXFA_FFDoc::PageViewEvent eEvent)
void OnLayoutItemRemoving(CXFA_LayoutProcessor *pLayout, CXFA_LayoutItem *pSender)
bool IsContentLayoutItem() const
CXFA_ViewLayoutItem * AsViewLayoutItem()
void SetFormNode(CXFA_Node *pNode)
CXFA_ContentLayoutItem * AsContentLayoutItem()
CXFA_Node * GetFormNode() const
const CXFA_ContentLayoutItem * AsContentLayoutItem() const
static CXFA_LayoutProcessor * FromDocument(const CXFA_Document *pXFADoc)
CXFA_Measurement(float fValue, XFA_Unit eUnit)
void RemoveChildAndNotify(CXFA_Node *pNode, bool bNotify)
CXFA_Node * GetFirstContainerChild() const
void SetNodeAndDescendantsUnused()
CXFA_Node * GetContainerParent() const
void InsertChildAndNotify(CXFA_Node *pNode, CXFA_Node *pBeforeNode)
bool IsLayoutGeneratedNode() const
Definition cxfa_node.h:166
void SetFlag(XFA_NodeFlag dwFlag)
void ClearFlag(XFA_NodeFlag dwFlag)
CXFA_Node * GetTemplateNodeIfExists() const
bool IsUnusedNode() const
Definition cxfa_node.h:165
XFA_PacketType GetPacketType() const
Definition cxfa_node.h:146
bool PresenceRequiresSpace() const
void SetInitializedFlagAndNotify()
bool HasRemovedChildren() const
Definition cxfa_node.h:174
XFA_Element GetElementType() const
Definition cxfa_object.h:91
CXFA_Document * GetDocument() const
Definition cxfa_object.h:48
bool IsContainerNode() const
Definition cxfa_object.h:69
void SetOldSubform(CXFA_Node *pSubform)
CXFA_Node * GetOldSubform() const
int32_t GetPageIndex(const CXFA_ViewLayoutItem *pPage) const
CXFA_ViewLayoutItem * GetPage(int32_t index) const
CXFA_Node * QueryOverflow(CXFA_Node *pFormNode)
absl::optional< BreakData > ProcessBreakAfter(const CXFA_Node *pBreakNode)
absl::optional< OverflowData > ProcessOverflow(CXFA_Node *pFormNode, bool bCreatePage)
bool PrepareFirstPage(CXFA_Node *pRootSubform)
bool InitLayoutPage(CXFA_Node *pFormNode)
CXFA_Node * ProcessBookendTrailer(const CXFA_Node *pBookendNode)
CXFA_ViewLayoutItem * GetRootLayoutItem() const
CXFA_Node * ProcessBookendLeader(const CXFA_Node *pBookendNode)
absl::optional< BreakData > ProcessBreakBefore(const CXFA_Node *pBreakNode)
void SubmitContentItem(CXFA_ContentLayoutItem *pContentLayoutItem, CXFA_ContentLayoutProcessor::Result eStatus)
bool GetNextAvailContentHeight(float fChildHeight)
CharType operator[](const size_t index) const
Definition widestring.h:146
bool IsEmpty() const
Definition widestring.h:118
WideString & operator=(const WideString &that)
CharType Back() const
Definition widestring.h:152
bool EqualsASCII(ByteStringView that) const
Definition widestring.h:216
constexpr float kXFALayoutPrecision
void XFA_ReleaseLayoutItem(CXFA_LayoutItem *pLayoutItem)
XFA_NodeFlag
Definition cxfa_node.h:77
CXFA_Node * ToNode(CXFA_Object *pObj)
XFA_WidgetStatus
Definition fxfa.h:61
XFA_Unit
Definition fxfa_basic.h:91
XFA_Attribute
Definition fxfa_basic.h:67
@ XFA_HASHCODE_Template
Definition fxfa_basic.h:35
@ XFA_HASHCODE_Form
Definition fxfa_basic.h:22
@ XFA_HASHCODE_Record
Definition fxfa_basic.h:31
XFA_Element
Definition fxfa_basic.h:75
XFA_AttributeValue
Definition fxfa_basic.h:60
XFA_PacketType
Definition fxfa_basic.h:44
Definition heap.h:12
UNOWNED_PTR_EXCLUSION CXFA_Node * pTrailer
UNOWNED_PTR_EXCLUSION CXFA_Node * pLeader
UNOWNED_PTR_EXCLUSION CXFA_Node * pTrailer
UNOWNED_PTR_EXCLUSION CXFA_Node * pLeader
CXFA_Node * XFA_DataMerge_FindDataScope(CXFA_Node *pParentFormNode)