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