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/parser/xfa_layout_itemlayout.h"
8
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 #include <vector>
13
14 #include "third_party/base/ptr_util.h"
15 #include "third_party/base/stl_util.h"
16 #include "xfa/fxfa/app/xfa_ffnotify.h"
17 #include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
18 #include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
19 #include "xfa/fxfa/parser/cxfa_document.h"
20 #include "xfa/fxfa/parser/cxfa_layoutpagemgr.h"
21 #include "xfa/fxfa/parser/cxfa_measurement.h"
22 #include "xfa/fxfa/parser/cxfa_occur.h"
23 #include "xfa/fxfa/parser/xfa_localemgr.h"
24 #include "xfa/fxfa/parser/xfa_object.h"
25 #include "xfa/fxfa/parser/xfa_utils.h"
26
27 namespace {
28
SeparateStringW(const FX_WCHAR * pStr,int32_t iStrLen,FX_WCHAR delimiter)29 std::vector<CFX_WideString> SeparateStringW(const FX_WCHAR* pStr,
30 int32_t iStrLen,
31 FX_WCHAR delimiter) {
32 std::vector<CFX_WideString> ret;
33 if (!pStr)
34 return ret;
35 if (iStrLen < 0)
36 iStrLen = FXSYS_wcslen(pStr);
37
38 const FX_WCHAR* pToken = pStr;
39 const FX_WCHAR* pEnd = pStr + iStrLen;
40 while (true) {
41 if (pStr >= pEnd || delimiter == *pStr) {
42 ret.push_back(CFX_WideString(pToken, pStr - pToken));
43 pToken = pStr + 1;
44 if (pStr >= pEnd)
45 break;
46 }
47 pStr++;
48 }
49 return ret;
50 }
51
UpdateWidgetSize(CXFA_ContentLayoutItem * pLayoutItem,FX_FLOAT * fWidth,FX_FLOAT * fHeight)52 void UpdateWidgetSize(CXFA_ContentLayoutItem* pLayoutItem,
53 FX_FLOAT* fWidth,
54 FX_FLOAT* fHeight) {
55 CXFA_Node* pNode = pLayoutItem->m_pFormNode;
56 switch (pNode->GetElementType()) {
57 case XFA_Element::Subform:
58 case XFA_Element::Area:
59 case XFA_Element::ExclGroup:
60 case XFA_Element::SubformSet: {
61 if (*fWidth < -XFA_LAYOUT_FLOAT_PERCISION)
62 *fWidth = pLayoutItem->m_sSize.width;
63 if (*fHeight < -XFA_LAYOUT_FLOAT_PERCISION)
64 *fHeight = pLayoutItem->m_sSize.height;
65 break;
66 }
67 case XFA_Element::Draw:
68 case XFA_Element::Field: {
69 pNode->GetDocument()->GetNotify()->StartFieldDrawLayout(pNode, *fWidth,
70 *fHeight);
71 break;
72 }
73 default:
74 ASSERT(false);
75 }
76 }
77
CalculateContainerSpecifiedSize(CXFA_Node * pFormNode,bool * bContainerWidthAutoSize,bool * bContainerHeightAutoSize)78 CFX_SizeF CalculateContainerSpecifiedSize(CXFA_Node* pFormNode,
79 bool* bContainerWidthAutoSize,
80 bool* bContainerHeightAutoSize) {
81 *bContainerWidthAutoSize = true;
82 *bContainerHeightAutoSize = true;
83
84 XFA_Element eType = pFormNode->GetElementType();
85 CXFA_Measurement mTmpValue;
86 CFX_SizeF containerSize;
87 if ((eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup) &&
88 pFormNode->TryMeasure(XFA_ATTRIBUTE_W, mTmpValue, false) &&
89 mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
90 containerSize.width = mTmpValue.ToUnit(XFA_UNIT_Pt);
91 *bContainerWidthAutoSize = false;
92 }
93 if ((eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup) &&
94 pFormNode->TryMeasure(XFA_ATTRIBUTE_H, mTmpValue, false) &&
95 mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
96 containerSize.height = mTmpValue.ToUnit(XFA_UNIT_Pt);
97 *bContainerHeightAutoSize = false;
98 }
99 if (*bContainerWidthAutoSize && eType == XFA_Element::Subform &&
100 pFormNode->TryMeasure(XFA_ATTRIBUTE_MaxW, mTmpValue, false) &&
101 mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
102 containerSize.width = mTmpValue.ToUnit(XFA_UNIT_Pt);
103 *bContainerWidthAutoSize = false;
104 }
105 if (*bContainerHeightAutoSize && eType == XFA_Element::Subform &&
106 pFormNode->TryMeasure(XFA_ATTRIBUTE_MaxH, mTmpValue, false) &&
107 mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
108 containerSize.height = mTmpValue.ToUnit(XFA_UNIT_Pt);
109 *bContainerHeightAutoSize = false;
110 }
111 return containerSize;
112 }
113
CalculateContainerComponentSizeFromContentSize(CXFA_Node * pFormNode,bool bContainerWidthAutoSize,FX_FLOAT fContentCalculatedWidth,bool bContainerHeightAutoSize,FX_FLOAT fContentCalculatedHeight,const CFX_SizeF & currentContainerSize)114 CFX_SizeF CalculateContainerComponentSizeFromContentSize(
115 CXFA_Node* pFormNode,
116 bool bContainerWidthAutoSize,
117 FX_FLOAT fContentCalculatedWidth,
118 bool bContainerHeightAutoSize,
119 FX_FLOAT fContentCalculatedHeight,
120 const CFX_SizeF& currentContainerSize) {
121 CFX_SizeF componentSize = currentContainerSize;
122 CXFA_Node* pMarginNode = pFormNode->GetFirstChildByClass(XFA_Element::Margin);
123 CXFA_Measurement mTmpValue;
124 if (bContainerWidthAutoSize) {
125 componentSize.width = fContentCalculatedWidth;
126 if (pMarginNode) {
127 if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_LeftInset, mTmpValue, false))
128 componentSize.width += mTmpValue.ToUnit(XFA_UNIT_Pt);
129 if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_RightInset, mTmpValue, false))
130 componentSize.width += mTmpValue.ToUnit(XFA_UNIT_Pt);
131 }
132 }
133
134 if (bContainerHeightAutoSize) {
135 componentSize.height = fContentCalculatedHeight;
136 if (pMarginNode) {
137 if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_TopInset, mTmpValue, false))
138 componentSize.height += mTmpValue.ToUnit(XFA_UNIT_Pt);
139 if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_BottomInset, mTmpValue,
140 false)) {
141 componentSize.height += mTmpValue.ToUnit(XFA_UNIT_Pt);
142 }
143 }
144 }
145 return componentSize;
146 }
147
RelocateTableRowCells(CXFA_ContentLayoutItem * pLayoutRow,const CFX_ArrayTemplate<FX_FLOAT> & rgSpecifiedColumnWidths,XFA_ATTRIBUTEENUM eLayout)148 void RelocateTableRowCells(
149 CXFA_ContentLayoutItem* pLayoutRow,
150 const CFX_ArrayTemplate<FX_FLOAT>& rgSpecifiedColumnWidths,
151 XFA_ATTRIBUTEENUM eLayout) {
152 bool bContainerWidthAutoSize = true;
153 bool bContainerHeightAutoSize = true;
154 CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
155 pLayoutRow->m_pFormNode, &bContainerWidthAutoSize,
156 &bContainerHeightAutoSize);
157 CXFA_Node* pMarginNode =
158 pLayoutRow->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
159 FX_FLOAT fLeftInset = 0;
160 FX_FLOAT fTopInset = 0;
161 FX_FLOAT fRightInset = 0;
162 FX_FLOAT fBottomInset = 0;
163 if (pMarginNode) {
164 fLeftInset =
165 pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
166 fTopInset =
167 pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
168 fRightInset =
169 pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
170 fBottomInset =
171 pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset).ToUnit(XFA_UNIT_Pt);
172 }
173
174 FX_FLOAT fContentWidthLimit =
175 bContainerWidthAutoSize ? FLT_MAX
176 : containerSize.width - fLeftInset - fRightInset;
177 FX_FLOAT fContentCurrentHeight =
178 pLayoutRow->m_sSize.height - fTopInset - fBottomInset;
179 FX_FLOAT fContentCalculatedWidth = 0;
180 FX_FLOAT fContentCalculatedHeight = 0;
181 FX_FLOAT fCurrentColX = 0;
182 int32_t nCurrentColIdx = 0;
183 bool bMetWholeRowCell = false;
184
185 for (auto pLayoutChild =
186 static_cast<CXFA_ContentLayoutItem*>(pLayoutRow->m_pFirstChild);
187 pLayoutChild; pLayoutChild = static_cast<CXFA_ContentLayoutItem*>(
188 pLayoutChild->m_pNextSibling)) {
189 int32_t nOriginalColSpan =
190 pLayoutChild->m_pFormNode->GetInteger(XFA_ATTRIBUTE_ColSpan);
191 int32_t nColSpan = nOriginalColSpan;
192 FX_FLOAT fColSpanWidth = 0;
193 if (nColSpan == -1 ||
194 nCurrentColIdx + nColSpan > rgSpecifiedColumnWidths.GetSize()) {
195 nColSpan = rgSpecifiedColumnWidths.GetSize() - nCurrentColIdx;
196 }
197 for (int32_t i = 0; i < nColSpan; i++)
198 fColSpanWidth += rgSpecifiedColumnWidths[nCurrentColIdx + i];
199
200 if (nColSpan != nOriginalColSpan) {
201 fColSpanWidth =
202 bMetWholeRowCell ? 0 : std::max(fColSpanWidth,
203 pLayoutChild->m_sSize.height);
204 }
205 if (nOriginalColSpan == -1)
206 bMetWholeRowCell = true;
207
208 pLayoutChild->m_sPos = CFX_PointF(fCurrentColX, 0);
209 pLayoutChild->m_sSize.width = fColSpanWidth;
210 if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode))
211 continue;
212
213 fCurrentColX += fColSpanWidth;
214 nCurrentColIdx += nColSpan;
215 FX_FLOAT fNewHeight = bContainerHeightAutoSize ? -1 : fContentCurrentHeight;
216 UpdateWidgetSize(pLayoutChild, &fColSpanWidth, &fNewHeight);
217 pLayoutChild->m_sSize.height = fNewHeight;
218 if (bContainerHeightAutoSize) {
219 fContentCalculatedHeight =
220 std::max(fContentCalculatedHeight, pLayoutChild->m_sSize.height);
221 }
222 }
223
224 if (bContainerHeightAutoSize) {
225 for (CXFA_ContentLayoutItem* pLayoutChild =
226 (CXFA_ContentLayoutItem*)pLayoutRow->m_pFirstChild;
227 pLayoutChild;
228 pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
229 UpdateWidgetSize(pLayoutChild, &pLayoutChild->m_sSize.width,
230 &fContentCalculatedHeight);
231 FX_FLOAT fOldChildHeight = pLayoutChild->m_sSize.height;
232 pLayoutChild->m_sSize.height = fContentCalculatedHeight;
233 CXFA_Node* pParaNode =
234 pLayoutChild->m_pFormNode->GetFirstChildByClass(XFA_Element::Para);
235 if (pParaNode && pLayoutChild->m_pFirstChild) {
236 FX_FLOAT fOffHeight = fContentCalculatedHeight - fOldChildHeight;
237 XFA_ATTRIBUTEENUM eVType = pParaNode->GetEnum(XFA_ATTRIBUTE_VAlign);
238 switch (eVType) {
239 case XFA_ATTRIBUTEENUM_Middle:
240 fOffHeight = fOffHeight / 2;
241 break;
242 case XFA_ATTRIBUTEENUM_Bottom:
243 break;
244 case XFA_ATTRIBUTEENUM_Top:
245 default:
246 fOffHeight = 0;
247 break;
248 }
249 if (fOffHeight > 0) {
250 for (CXFA_ContentLayoutItem* pInnerLayoutChild =
251 (CXFA_ContentLayoutItem*)pLayoutChild->m_pFirstChild;
252 pInnerLayoutChild;
253 pInnerLayoutChild =
254 (CXFA_ContentLayoutItem*)pInnerLayoutChild->m_pNextSibling) {
255 pInnerLayoutChild->m_sPos.y += fOffHeight;
256 }
257 }
258 }
259 }
260 }
261
262 if (bContainerWidthAutoSize) {
263 FX_FLOAT fChildSuppliedWidth = fCurrentColX;
264 if (fContentWidthLimit < FLT_MAX &&
265 fContentWidthLimit > fChildSuppliedWidth) {
266 fChildSuppliedWidth = fContentWidthLimit;
267 }
268 fContentCalculatedWidth =
269 std::max(fContentCalculatedWidth, fChildSuppliedWidth);
270 } else {
271 fContentCalculatedWidth = containerSize.width - fLeftInset - fRightInset;
272 }
273
274 if (pLayoutRow->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout) ==
275 XFA_ATTRIBUTEENUM_Rl_row) {
276 for (CXFA_ContentLayoutItem* pLayoutChild =
277 (CXFA_ContentLayoutItem*)pLayoutRow->m_pFirstChild;
278 pLayoutChild;
279 pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
280 pLayoutChild->m_sPos.x = fContentCalculatedWidth -
281 pLayoutChild->m_sPos.x -
282 pLayoutChild->m_sSize.width;
283 }
284 }
285 pLayoutRow->m_sSize = CalculateContainerComponentSizeFromContentSize(
286 pLayoutRow->m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
287 bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
288 }
289
UpdatePendingItemLayout(CXFA_ItemLayoutProcessor * pProcessor,CXFA_ContentLayoutItem * pLayoutItem)290 void UpdatePendingItemLayout(CXFA_ItemLayoutProcessor* pProcessor,
291 CXFA_ContentLayoutItem* pLayoutItem) {
292 XFA_ATTRIBUTEENUM eLayout =
293 pLayoutItem->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
294 switch (eLayout) {
295 case XFA_ATTRIBUTEENUM_Row:
296 case XFA_ATTRIBUTEENUM_Rl_row:
297 RelocateTableRowCells(pLayoutItem, pProcessor->m_rgSpecifiedColumnWidths,
298 eLayout);
299 break;
300 default:
301 break;
302 }
303 }
304
AddTrailerBeforeSplit(CXFA_ItemLayoutProcessor * pProcessor,FX_FLOAT fSplitPos,CXFA_ContentLayoutItem * pTrailerLayoutItem,bool bUseInherited)305 void AddTrailerBeforeSplit(CXFA_ItemLayoutProcessor* pProcessor,
306 FX_FLOAT fSplitPos,
307 CXFA_ContentLayoutItem* pTrailerLayoutItem,
308 bool bUseInherited) {
309 if (!pTrailerLayoutItem)
310 return;
311
312 FX_FLOAT fHeight = pTrailerLayoutItem->m_sSize.height;
313 if (bUseInherited) {
314 FX_FLOAT fNewSplitPos = 0;
315 if (fSplitPos - fHeight > XFA_LAYOUT_FLOAT_PERCISION)
316 fNewSplitPos = pProcessor->FindSplitPos(fSplitPos - fHeight);
317 if (fNewSplitPos > XFA_LAYOUT_FLOAT_PERCISION)
318 pProcessor->SplitLayoutItem(fNewSplitPos);
319 return;
320 }
321
322 UpdatePendingItemLayout(pProcessor, pTrailerLayoutItem);
323 CXFA_Node* pMarginNode =
324 pProcessor->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
325 FX_FLOAT fLeftInset = 0;
326 FX_FLOAT fTopInset = 0;
327 FX_FLOAT fRightInset = 0;
328 FX_FLOAT fBottomInset = 0;
329 if (pMarginNode) {
330 fLeftInset =
331 pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
332 fTopInset =
333 pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
334 fRightInset =
335 pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
336 fBottomInset =
337 pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset).ToUnit(XFA_UNIT_Pt);
338 }
339
340 if (!pProcessor->IsAddNewRowForTrailer(pTrailerLayoutItem)) {
341 pTrailerLayoutItem->m_sPos.y = pProcessor->m_fLastRowY;
342 pTrailerLayoutItem->m_sPos.x = pProcessor->m_fLastRowWidth;
343 pProcessor->m_pLayoutItem->m_sSize.width +=
344 pTrailerLayoutItem->m_sSize.width;
345 pProcessor->m_pLayoutItem->AddChild(pTrailerLayoutItem);
346 return;
347 }
348
349 FX_FLOAT fNewSplitPos = 0;
350 if (fSplitPos - fHeight > XFA_LAYOUT_FLOAT_PERCISION)
351 fNewSplitPos = pProcessor->FindSplitPos(fSplitPos - fHeight);
352
353 if (fNewSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
354 pProcessor->SplitLayoutItem(fNewSplitPos);
355 pTrailerLayoutItem->m_sPos.y = fNewSplitPos - fTopInset - fBottomInset;
356 } else {
357 pTrailerLayoutItem->m_sPos.y = fSplitPos - fTopInset - fBottomInset;
358 }
359
360 switch (pTrailerLayoutItem->m_pFormNode->GetEnum(XFA_ATTRIBUTE_HAlign)) {
361 case XFA_ATTRIBUTEENUM_Right:
362 pTrailerLayoutItem->m_sPos.x = pProcessor->m_pLayoutItem->m_sSize.width -
363 fRightInset -
364 pTrailerLayoutItem->m_sSize.width;
365 break;
366 case XFA_ATTRIBUTEENUM_Center:
367 pTrailerLayoutItem->m_sPos.x =
368 (pProcessor->m_pLayoutItem->m_sSize.width - fLeftInset - fRightInset -
369 pTrailerLayoutItem->m_sSize.width) /
370 2;
371 break;
372 case XFA_ATTRIBUTEENUM_Left:
373 default:
374 pTrailerLayoutItem->m_sPos.x = fLeftInset;
375 break;
376 }
377 pProcessor->m_pLayoutItem->m_sSize.height += fHeight;
378 pProcessor->m_pLayoutItem->AddChild(pTrailerLayoutItem);
379 }
380
AddLeaderAfterSplit(CXFA_ItemLayoutProcessor * pProcessor,CXFA_ContentLayoutItem * pLeaderLayoutItem)381 void AddLeaderAfterSplit(CXFA_ItemLayoutProcessor* pProcessor,
382 CXFA_ContentLayoutItem* pLeaderLayoutItem) {
383 UpdatePendingItemLayout(pProcessor, pLeaderLayoutItem);
384
385 CXFA_Node* pMarginNode =
386 pProcessor->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
387 FX_FLOAT fLeftInset = 0;
388 FX_FLOAT fRightInset = 0;
389 if (pMarginNode) {
390 fLeftInset =
391 pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
392 fRightInset =
393 pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
394 }
395
396 FX_FLOAT fHeight = pLeaderLayoutItem->m_sSize.height;
397 for (CXFA_ContentLayoutItem* pChildItem =
398 (CXFA_ContentLayoutItem*)pProcessor->m_pLayoutItem->m_pFirstChild;
399 pChildItem;
400 pChildItem = (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling) {
401 pChildItem->m_sPos.y += fHeight;
402 }
403 pLeaderLayoutItem->m_sPos.y = 0;
404
405 switch (pLeaderLayoutItem->m_pFormNode->GetEnum(XFA_ATTRIBUTE_HAlign)) {
406 case XFA_ATTRIBUTEENUM_Right:
407 pLeaderLayoutItem->m_sPos.x = pProcessor->m_pLayoutItem->m_sSize.width -
408 fRightInset -
409 pLeaderLayoutItem->m_sSize.width;
410 break;
411 case XFA_ATTRIBUTEENUM_Center:
412 pLeaderLayoutItem->m_sPos.x =
413 (pProcessor->m_pLayoutItem->m_sSize.width - fLeftInset - fRightInset -
414 pLeaderLayoutItem->m_sSize.width) /
415 2;
416 break;
417 case XFA_ATTRIBUTEENUM_Left:
418 default:
419 pLeaderLayoutItem->m_sPos.x = fLeftInset;
420 break;
421 }
422 pProcessor->m_pLayoutItem->m_sSize.height += fHeight;
423 pProcessor->m_pLayoutItem->AddChild(pLeaderLayoutItem);
424 }
425
AddPendingNode(CXFA_ItemLayoutProcessor * pProcessor,CXFA_Node * pPendingNode,bool bBreakPending)426 void AddPendingNode(CXFA_ItemLayoutProcessor* pProcessor,
427 CXFA_Node* pPendingNode,
428 bool bBreakPending) {
429 pProcessor->m_PendingNodes.push_back(pPendingNode);
430 pProcessor->m_bBreakPending = bBreakPending;
431 }
432
InsertPendingItems(CXFA_ItemLayoutProcessor * pProcessor,CXFA_Node * pCurChildNode)433 FX_FLOAT InsertPendingItems(CXFA_ItemLayoutProcessor* pProcessor,
434 CXFA_Node* pCurChildNode) {
435 FX_FLOAT fTotalHeight = 0;
436 if (pProcessor->m_PendingNodes.empty())
437 return fTotalHeight;
438
439 if (!pProcessor->m_pLayoutItem) {
440 pProcessor->m_pLayoutItem =
441 pProcessor->CreateContentLayoutItem(pCurChildNode);
442 pProcessor->m_pLayoutItem->m_sSize.clear();
443 }
444
445 while (!pProcessor->m_PendingNodes.empty()) {
446 auto pPendingProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
447 pProcessor->m_PendingNodes.front(), nullptr);
448 pProcessor->m_PendingNodes.pop_front();
449 pPendingProcessor->DoLayout(false, FLT_MAX, FLT_MAX, nullptr);
450 CXFA_ContentLayoutItem* pPendingLayoutItem =
451 pPendingProcessor->HasLayoutItem()
452 ? pPendingProcessor->ExtractLayoutItem()
453 : nullptr;
454 if (pPendingLayoutItem) {
455 AddLeaderAfterSplit(pProcessor, pPendingLayoutItem);
456 if (pProcessor->m_bBreakPending)
457 fTotalHeight += pPendingLayoutItem->m_sSize.height;
458 }
459 }
460 return fTotalHeight;
461 }
462
GetLayout(CXFA_Node * pFormNode,bool * bRootForceTb)463 XFA_ATTRIBUTEENUM GetLayout(CXFA_Node* pFormNode, bool* bRootForceTb) {
464 *bRootForceTb = false;
465 XFA_ATTRIBUTEENUM eLayoutMode;
466 if (pFormNode->TryEnum(XFA_ATTRIBUTE_Layout, eLayoutMode, false))
467 return eLayoutMode;
468
469 CXFA_Node* pParentNode = pFormNode->GetNodeItem(XFA_NODEITEM_Parent);
470 if (pParentNode && pParentNode->GetElementType() == XFA_Element::Form) {
471 *bRootForceTb = true;
472 return XFA_ATTRIBUTEENUM_Tb;
473 }
474 return XFA_ATTRIBUTEENUM_Position;
475 }
476
ExistContainerKeep(CXFA_Node * pCurNode,bool bPreFind)477 bool ExistContainerKeep(CXFA_Node* pCurNode, bool bPreFind) {
478 if (!pCurNode || !XFA_ItemLayoutProcessor_IsTakingSpace(pCurNode))
479 return false;
480
481 XFA_NODEITEM eItemType = XFA_NODEITEM_PrevSibling;
482 if (!bPreFind)
483 eItemType = XFA_NODEITEM_NextSibling;
484
485 CXFA_Node* pPreContainer =
486 pCurNode->GetNodeItem(eItemType, XFA_ObjectType::ContainerNode);
487 if (!pPreContainer)
488 return false;
489
490 CXFA_Node* pKeep = pCurNode->GetFirstChildByClass(XFA_Element::Keep);
491 if (pKeep) {
492 XFA_ATTRIBUTEENUM ePrevious;
493 XFA_ATTRIBUTE eKeepType = XFA_ATTRIBUTE_Previous;
494 if (!bPreFind)
495 eKeepType = XFA_ATTRIBUTE_Next;
496
497 if (pKeep->TryEnum(eKeepType, ePrevious, false)) {
498 if (ePrevious == XFA_ATTRIBUTEENUM_ContentArea ||
499 ePrevious == XFA_ATTRIBUTEENUM_PageArea) {
500 return true;
501 }
502 }
503 }
504
505 pKeep = pPreContainer->GetFirstChildByClass(XFA_Element::Keep);
506 if (!pKeep)
507 return false;
508
509 XFA_ATTRIBUTE eKeepType = XFA_ATTRIBUTE_Next;
510 if (!bPreFind)
511 eKeepType = XFA_ATTRIBUTE_Previous;
512
513 XFA_ATTRIBUTEENUM eNext;
514 if (!pKeep->TryEnum(eKeepType, eNext, false))
515 return false;
516 if (eNext == XFA_ATTRIBUTEENUM_ContentArea ||
517 eNext == XFA_ATTRIBUTEENUM_PageArea) {
518 return true;
519 }
520 return false;
521 }
522
FindBreakNode(CXFA_Node * pContainerNode,CXFA_Node * & pCurActionNode,XFA_ItemLayoutProcessorStages * nCurStage,bool bBreakBefore)523 bool FindBreakNode(CXFA_Node* pContainerNode,
524 CXFA_Node*& pCurActionNode,
525 XFA_ItemLayoutProcessorStages* nCurStage,
526 bool bBreakBefore) {
527 bool bFindRs = false;
528 for (CXFA_Node* pBreakNode = pContainerNode; pBreakNode;
529 pBreakNode = pBreakNode->GetNodeItem(XFA_NODEITEM_NextSibling)) {
530 XFA_ATTRIBUTE eAttributeType = XFA_ATTRIBUTE_Before;
531 if (!bBreakBefore)
532 eAttributeType = XFA_ATTRIBUTE_After;
533
534 switch (pBreakNode->GetElementType()) {
535 case XFA_Element::BreakBefore: {
536 if (bBreakBefore) {
537 pCurActionNode = pBreakNode;
538 *nCurStage = XFA_ItemLayoutProcessorStages::BreakBefore;
539 bFindRs = true;
540 }
541 break;
542 }
543 case XFA_Element::BreakAfter: {
544 if (!bBreakBefore) {
545 pCurActionNode = pBreakNode;
546 *nCurStage = XFA_ItemLayoutProcessorStages::BreakAfter;
547 bFindRs = true;
548 }
549 break;
550 }
551 case XFA_Element::Break:
552 if (pBreakNode->GetEnum(eAttributeType) != XFA_ATTRIBUTEENUM_Auto) {
553 pCurActionNode = pBreakNode;
554 *nCurStage = XFA_ItemLayoutProcessorStages::BreakBefore;
555 if (!bBreakBefore)
556 *nCurStage = XFA_ItemLayoutProcessorStages::BreakAfter;
557
558 bFindRs = true;
559 }
560 break;
561 default:
562 break;
563 }
564 if (bFindRs)
565 break;
566 }
567 return bFindRs;
568 }
569
DeleteLayoutGeneratedNode(CXFA_Node * pGenerateNode)570 void DeleteLayoutGeneratedNode(CXFA_Node* pGenerateNode) {
571 CXFA_FFNotify* pNotify = pGenerateNode->GetDocument()->GetNotify();
572 CXFA_LayoutProcessor* pDocLayout =
573 pGenerateNode->GetDocument()->GetDocLayout();
574 CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
575 pGenerateNode);
576 for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
577 pNode = sIterator.MoveToNext()) {
578 CXFA_ContentLayoutItem* pCurLayoutItem =
579 (CXFA_ContentLayoutItem*)pNode->GetUserData(XFA_LAYOUTITEMKEY);
580 CXFA_ContentLayoutItem* pNextLayoutItem = nullptr;
581 while (pCurLayoutItem) {
582 pNextLayoutItem = pCurLayoutItem->m_pNext;
583 pNotify->OnLayoutItemRemoving(pDocLayout, pCurLayoutItem);
584 delete pCurLayoutItem;
585 pCurLayoutItem = pNextLayoutItem;
586 }
587 }
588 pGenerateNode->GetNodeItem(XFA_NODEITEM_Parent)->RemoveChild(pGenerateNode);
589 }
590
HAlignEnumToInt(XFA_ATTRIBUTEENUM eHAlign)591 uint8_t HAlignEnumToInt(XFA_ATTRIBUTEENUM eHAlign) {
592 switch (eHAlign) {
593 case XFA_ATTRIBUTEENUM_Center:
594 return 1;
595 case XFA_ATTRIBUTEENUM_Right:
596 return 2;
597 case XFA_ATTRIBUTEENUM_Left:
598 default:
599 return 0;
600 }
601 }
602
InsertFlowedItem(CXFA_ItemLayoutProcessor * pThis,CXFA_ItemLayoutProcessor * pProcessor,bool bContainerWidthAutoSize,bool bContainerHeightAutoSize,FX_FLOAT fContainerHeight,XFA_ATTRIBUTEENUM eFlowStrategy,uint8_t * uCurHAlignState,CFX_ArrayTemplate<CXFA_ContentLayoutItem * > (& rgCurLineLayoutItems)[3],bool bUseBreakControl,FX_FLOAT fAvailHeight,FX_FLOAT fRealHeight,FX_FLOAT fContentWidthLimit,FX_FLOAT * fContentCurRowY,FX_FLOAT * fContentCurRowAvailWidth,FX_FLOAT * fContentCurRowHeight,bool * bAddedItemInRow,bool * bForceEndPage,CXFA_LayoutContext * pLayoutContext,bool bNewRow)603 XFA_ItemLayoutProcessorResult InsertFlowedItem(
604 CXFA_ItemLayoutProcessor* pThis,
605 CXFA_ItemLayoutProcessor* pProcessor,
606 bool bContainerWidthAutoSize,
607 bool bContainerHeightAutoSize,
608 FX_FLOAT fContainerHeight,
609 XFA_ATTRIBUTEENUM eFlowStrategy,
610 uint8_t* uCurHAlignState,
611 CFX_ArrayTemplate<CXFA_ContentLayoutItem*> (&rgCurLineLayoutItems)[3],
612 bool bUseBreakControl,
613 FX_FLOAT fAvailHeight,
614 FX_FLOAT fRealHeight,
615 FX_FLOAT fContentWidthLimit,
616 FX_FLOAT* fContentCurRowY,
617 FX_FLOAT* fContentCurRowAvailWidth,
618 FX_FLOAT* fContentCurRowHeight,
619 bool* bAddedItemInRow,
620 bool* bForceEndPage,
621 CXFA_LayoutContext* pLayoutContext,
622 bool bNewRow) {
623 bool bTakeSpace =
624 XFA_ItemLayoutProcessor_IsTakingSpace(pProcessor->m_pFormNode);
625 uint8_t uHAlign =
626 HAlignEnumToInt(pThis->m_pCurChildNode->GetEnum(XFA_ATTRIBUTE_HAlign));
627 if (bContainerWidthAutoSize)
628 uHAlign = 0;
629
630 if ((eFlowStrategy != XFA_ATTRIBUTEENUM_Rl_tb &&
631 uHAlign < *uCurHAlignState) ||
632 (eFlowStrategy == XFA_ATTRIBUTEENUM_Rl_tb &&
633 uHAlign > *uCurHAlignState)) {
634 return XFA_ItemLayoutProcessorResult::RowFullBreak;
635 }
636
637 *uCurHAlignState = uHAlign;
638 bool bIsOwnSplit =
639 pProcessor->m_pFormNode->GetIntact() == XFA_ATTRIBUTEENUM_None;
640 bool bUseRealHeight =
641 bTakeSpace && bContainerHeightAutoSize && bIsOwnSplit &&
642 pProcessor->m_pFormNode->GetNodeItem(XFA_NODEITEM_Parent)->GetIntact() ==
643 XFA_ATTRIBUTEENUM_None;
644 bool bIsTransHeight = bTakeSpace;
645 if (bIsTransHeight && !bIsOwnSplit) {
646 bool bRootForceTb = false;
647 XFA_ATTRIBUTEENUM eLayoutStrategy =
648 GetLayout(pProcessor->m_pFormNode, &bRootForceTb);
649 if (eLayoutStrategy == XFA_ATTRIBUTEENUM_Lr_tb ||
650 eLayoutStrategy == XFA_ATTRIBUTEENUM_Rl_tb) {
651 bIsTransHeight = false;
652 }
653 }
654
655 bool bUseInherited = false;
656 CXFA_LayoutContext layoutContext;
657 if (pThis->m_pPageMgr) {
658 CXFA_Node* pOverflowNode =
659 pThis->m_pPageMgr->QueryOverflow(pThis->m_pFormNode);
660 if (pOverflowNode) {
661 layoutContext.m_pOverflowNode = pOverflowNode;
662 layoutContext.m_pOverflowProcessor = pThis;
663 pLayoutContext = &layoutContext;
664 }
665 }
666
667 XFA_ItemLayoutProcessorResult eRetValue = XFA_ItemLayoutProcessorResult::Done;
668 if (!bNewRow ||
669 pProcessor->m_ePreProcessRs == XFA_ItemLayoutProcessorResult::Done) {
670 eRetValue = pProcessor->DoLayout(
671 bTakeSpace ? bUseBreakControl : false,
672 bUseRealHeight ? fRealHeight - *fContentCurRowY : FLT_MAX,
673 bIsTransHeight ? fRealHeight - *fContentCurRowY : FLT_MAX,
674 pLayoutContext);
675 pProcessor->m_ePreProcessRs = eRetValue;
676 } else {
677 eRetValue = pProcessor->m_ePreProcessRs;
678 pProcessor->m_ePreProcessRs = XFA_ItemLayoutProcessorResult::Done;
679 }
680 if (pProcessor->HasLayoutItem() == false)
681 return eRetValue;
682
683 CFX_SizeF childSize = pProcessor->GetCurrentComponentSize();
684 if (bUseRealHeight && fRealHeight < XFA_LAYOUT_FLOAT_PERCISION) {
685 fRealHeight = FLT_MAX;
686 fAvailHeight = FLT_MAX;
687 }
688 if (bTakeSpace && (childSize.width >
689 *fContentCurRowAvailWidth + XFA_LAYOUT_FLOAT_PERCISION) &&
690 (fContentWidthLimit - *fContentCurRowAvailWidth >
691 XFA_LAYOUT_FLOAT_PERCISION)) {
692 return XFA_ItemLayoutProcessorResult::RowFullBreak;
693 }
694
695 CXFA_Node* pOverflowLeaderNode = nullptr;
696 CXFA_Node* pOverflowTrailerNode = nullptr;
697 CXFA_Node* pFormNode = nullptr;
698 CXFA_ContentLayoutItem* pTrailerLayoutItem = nullptr;
699 bool bIsAddTrailerHeight = false;
700 if (pThis->m_pPageMgr &&
701 pProcessor->m_pFormNode->GetIntact() == XFA_ATTRIBUTEENUM_None) {
702 pFormNode = pThis->m_pPageMgr->QueryOverflow(pProcessor->m_pFormNode);
703 if (!pFormNode && pLayoutContext && pLayoutContext->m_pOverflowProcessor) {
704 pFormNode = pLayoutContext->m_pOverflowNode;
705 bUseInherited = true;
706 }
707 if (pThis->m_pPageMgr->ProcessOverflow(pFormNode, pOverflowLeaderNode,
708 pOverflowTrailerNode, false,
709 false)) {
710 if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowTrailerNode)) {
711 if (pOverflowTrailerNode) {
712 auto pOverflowLeaderProcessor =
713 pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pOverflowTrailerNode,
714 nullptr);
715 pOverflowLeaderProcessor->DoLayout(false, FLT_MAX, FLT_MAX, nullptr);
716 pTrailerLayoutItem =
717 pOverflowLeaderProcessor->HasLayoutItem()
718 ? pOverflowLeaderProcessor->ExtractLayoutItem()
719 : nullptr;
720 }
721
722 bIsAddTrailerHeight =
723 bUseInherited
724 ? pThis->IsAddNewRowForTrailer(pTrailerLayoutItem)
725 : pProcessor->IsAddNewRowForTrailer(pTrailerLayoutItem);
726 if (bIsAddTrailerHeight) {
727 childSize.height += pTrailerLayoutItem->m_sSize.height;
728 bIsAddTrailerHeight = true;
729 }
730 }
731 }
732 }
733
734 if (!bTakeSpace ||
735 *fContentCurRowY + childSize.height <=
736 fAvailHeight + XFA_LAYOUT_FLOAT_PERCISION ||
737 (!bContainerHeightAutoSize &&
738 pThis->m_fUsedSize + fAvailHeight + XFA_LAYOUT_FLOAT_PERCISION >=
739 fContainerHeight)) {
740 if (!bTakeSpace || eRetValue == XFA_ItemLayoutProcessorResult::Done) {
741 if (pProcessor->m_bUseInheriated) {
742 if (pTrailerLayoutItem)
743 AddTrailerBeforeSplit(pProcessor, childSize.height,
744 pTrailerLayoutItem, false);
745 if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode))
746 AddPendingNode(pProcessor, pOverflowLeaderNode, false);
747
748 pProcessor->m_bUseInheriated = false;
749 } else {
750 if (bIsAddTrailerHeight)
751 childSize.height -= pTrailerLayoutItem->m_sSize.height;
752
753 pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
754 pOverflowTrailerNode,
755 pTrailerLayoutItem, pFormNode);
756 }
757
758 CXFA_ContentLayoutItem* pChildLayoutItem =
759 pProcessor->ExtractLayoutItem();
760 if (ExistContainerKeep(pProcessor->m_pFormNode, false) &&
761 pProcessor->m_pFormNode->GetIntact() == XFA_ATTRIBUTEENUM_None) {
762 pThis->m_arrayKeepItems.push_back(pChildLayoutItem);
763 } else {
764 pThis->m_arrayKeepItems.clear();
765 }
766 rgCurLineLayoutItems[uHAlign].Add(pChildLayoutItem);
767 *bAddedItemInRow = true;
768 if (bTakeSpace) {
769 *fContentCurRowAvailWidth -= childSize.width;
770 *fContentCurRowHeight =
771 std::max(*fContentCurRowHeight, childSize.height);
772 }
773 return XFA_ItemLayoutProcessorResult::Done;
774 }
775
776 if (eRetValue == XFA_ItemLayoutProcessorResult::PageFullBreak) {
777 if (pProcessor->m_bUseInheriated) {
778 if (pTrailerLayoutItem) {
779 AddTrailerBeforeSplit(pProcessor, childSize.height,
780 pTrailerLayoutItem, false);
781 }
782 if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode))
783 AddPendingNode(pProcessor, pOverflowLeaderNode, false);
784
785 pProcessor->m_bUseInheriated = false;
786 } else {
787 if (bIsAddTrailerHeight)
788 childSize.height -= pTrailerLayoutItem->m_sSize.height;
789
790 pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
791 pOverflowTrailerNode,
792 pTrailerLayoutItem, pFormNode);
793 }
794 }
795 rgCurLineLayoutItems[uHAlign].Add(pProcessor->ExtractLayoutItem());
796 *bAddedItemInRow = true;
797 *fContentCurRowAvailWidth -= childSize.width;
798 *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height);
799 return eRetValue;
800 }
801
802 XFA_ItemLayoutProcessorResult eResult;
803 if (pThis->ProcessKeepForSplit(
804 pThis, pProcessor, eRetValue, &rgCurLineLayoutItems[uHAlign],
805 fContentCurRowAvailWidth, fContentCurRowHeight, fContentCurRowY,
806 bAddedItemInRow, bForceEndPage, &eResult)) {
807 return eResult;
808 }
809
810 *bForceEndPage = true;
811 FX_FLOAT fSplitPos =
812 pProcessor->FindSplitPos(fAvailHeight - *fContentCurRowY);
813 if (fSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
814 XFA_ATTRIBUTEENUM eLayout =
815 pProcessor->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
816 if (eLayout == XFA_ATTRIBUTEENUM_Tb &&
817 eRetValue == XFA_ItemLayoutProcessorResult::Done) {
818 pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
819 pOverflowTrailerNode, pTrailerLayoutItem,
820 pFormNode);
821 rgCurLineLayoutItems[uHAlign].Add(pProcessor->ExtractLayoutItem());
822 *bAddedItemInRow = true;
823 if (bTakeSpace) {
824 *fContentCurRowAvailWidth -= childSize.width;
825 *fContentCurRowHeight =
826 std::max(*fContentCurRowHeight, childSize.height);
827 }
828 return XFA_ItemLayoutProcessorResult::PageFullBreak;
829 }
830
831 CXFA_Node* pTempLeaderNode = nullptr;
832 CXFA_Node* pTempTrailerNode = nullptr;
833 if (pThis->m_pPageMgr && !pProcessor->m_bUseInheriated &&
834 eRetValue != XFA_ItemLayoutProcessorResult::PageFullBreak) {
835 pThis->m_pPageMgr->ProcessOverflow(pFormNode, pTempLeaderNode,
836 pTempTrailerNode, false, true);
837 }
838 if (pTrailerLayoutItem && bIsAddTrailerHeight) {
839 AddTrailerBeforeSplit(pProcessor, fSplitPos, pTrailerLayoutItem,
840 bUseInherited);
841 } else {
842 pProcessor->SplitLayoutItem(fSplitPos);
843 }
844
845 if (bUseInherited) {
846 pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
847 pOverflowTrailerNode, pTrailerLayoutItem,
848 pFormNode);
849 pThis->m_bUseInheriated = true;
850 } else {
851 CXFA_LayoutItem* firstChild = pProcessor->m_pLayoutItem->m_pFirstChild;
852 if (firstChild && !firstChild->m_pNextSibling &&
853 firstChild->m_pFormNode->IsLayoutGeneratedNode()) {
854 pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
855 pOverflowTrailerNode,
856 pTrailerLayoutItem, pFormNode);
857 } else if (pProcessor->JudgeLeaderOrTrailerForOccur(
858 pOverflowLeaderNode)) {
859 AddPendingNode(pProcessor, pOverflowLeaderNode, false);
860 }
861 }
862
863 if (pProcessor->m_pLayoutItem->m_pNextSibling) {
864 childSize = pProcessor->GetCurrentComponentSize();
865 rgCurLineLayoutItems[uHAlign].Add(pProcessor->ExtractLayoutItem());
866 *bAddedItemInRow = true;
867 if (bTakeSpace) {
868 *fContentCurRowAvailWidth -= childSize.width;
869 *fContentCurRowHeight =
870 std::max(*fContentCurRowHeight, childSize.height);
871 }
872 }
873 return XFA_ItemLayoutProcessorResult::PageFullBreak;
874 }
875
876 if (*fContentCurRowY <= XFA_LAYOUT_FLOAT_PERCISION) {
877 childSize = pProcessor->GetCurrentComponentSize();
878 if (pProcessor->m_pPageMgr->GetNextAvailContentHeight(childSize.height)) {
879 CXFA_Node* pTempLeaderNode = nullptr;
880 CXFA_Node* pTempTrailerNode = nullptr;
881 if (pThis->m_pPageMgr) {
882 if (!pFormNode && pLayoutContext)
883 pFormNode = pLayoutContext->m_pOverflowProcessor->m_pFormNode;
884
885 pThis->m_pPageMgr->ProcessOverflow(pFormNode, pTempLeaderNode,
886 pTempTrailerNode, false, true);
887 }
888 if (bUseInherited) {
889 pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
890 pOverflowTrailerNode,
891 pTrailerLayoutItem, pFormNode);
892 pThis->m_bUseInheriated = true;
893 }
894 return XFA_ItemLayoutProcessorResult::PageFullBreak;
895 }
896
897 rgCurLineLayoutItems[uHAlign].Add(pProcessor->ExtractLayoutItem());
898 *bAddedItemInRow = true;
899 if (bTakeSpace) {
900 *fContentCurRowAvailWidth -= childSize.width;
901 *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height);
902 }
903 if (eRetValue == XFA_ItemLayoutProcessorResult::Done)
904 *bForceEndPage = false;
905
906 return eRetValue;
907 }
908
909 XFA_ATTRIBUTEENUM eLayout =
910 pProcessor->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
911 if (pProcessor->m_pFormNode->GetIntact() == XFA_ATTRIBUTEENUM_None &&
912 eLayout == XFA_ATTRIBUTEENUM_Tb) {
913 if (pThis->m_pPageMgr) {
914 pThis->m_pPageMgr->ProcessOverflow(pFormNode, pOverflowLeaderNode,
915 pOverflowTrailerNode, false, true);
916 }
917 if (pTrailerLayoutItem)
918 AddTrailerBeforeSplit(pProcessor, fSplitPos, pTrailerLayoutItem, false);
919 if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode))
920 AddPendingNode(pProcessor, pOverflowLeaderNode, false);
921
922 return XFA_ItemLayoutProcessorResult::PageFullBreak;
923 }
924
925 if (eRetValue != XFA_ItemLayoutProcessorResult::Done)
926 return XFA_ItemLayoutProcessorResult::PageFullBreak;
927
928 if (!pFormNode && pLayoutContext)
929 pFormNode = pLayoutContext->m_pOverflowProcessor->m_pFormNode;
930 if (pThis->m_pPageMgr) {
931 pThis->m_pPageMgr->ProcessOverflow(pFormNode, pOverflowLeaderNode,
932 pOverflowTrailerNode, false, true);
933 }
934 if (bUseInherited) {
935 pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode, pOverflowTrailerNode,
936 pTrailerLayoutItem, pFormNode);
937 pThis->m_bUseInheriated = true;
938 }
939 return XFA_ItemLayoutProcessorResult::PageFullBreak;
940 }
941
FindLayoutItemSplitPos(CXFA_ContentLayoutItem * pLayoutItem,FX_FLOAT fCurVerticalOffset,FX_FLOAT * fProposedSplitPos,bool * bAppChange,bool bCalculateMargin)942 bool FindLayoutItemSplitPos(CXFA_ContentLayoutItem* pLayoutItem,
943 FX_FLOAT fCurVerticalOffset,
944 FX_FLOAT* fProposedSplitPos,
945 bool* bAppChange,
946 bool bCalculateMargin) {
947 CXFA_Node* pFormNode = pLayoutItem->m_pFormNode;
948 if (*fProposedSplitPos <= fCurVerticalOffset + XFA_LAYOUT_FLOAT_PERCISION ||
949 *fProposedSplitPos > fCurVerticalOffset + pLayoutItem->m_sSize.height -
950 XFA_LAYOUT_FLOAT_PERCISION) {
951 return false;
952 }
953
954 switch (pFormNode->GetIntact()) {
955 case XFA_ATTRIBUTEENUM_None: {
956 bool bAnyChanged = false;
957 CXFA_Document* pDocument = pFormNode->GetDocument();
958 CXFA_FFNotify* pNotify = pDocument->GetNotify();
959 FX_FLOAT fCurTopMargin = 0, fCurBottomMargin = 0;
960 CXFA_Node* pMarginNode =
961 pFormNode->GetFirstChildByClass(XFA_Element::Margin);
962 if (pMarginNode && bCalculateMargin) {
963 fCurTopMargin =
964 pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
965 fCurBottomMargin = pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset)
966 .ToUnit(XFA_UNIT_Pt);
967 }
968 bool bChanged = true;
969 while (bChanged) {
970 bChanged = false;
971 {
972 FX_FLOAT fRelSplitPos = *fProposedSplitPos - fCurVerticalOffset;
973 if (pNotify->FindSplitPos(pFormNode, pLayoutItem->GetIndex(),
974 fRelSplitPos)) {
975 bAnyChanged = true;
976 bChanged = true;
977 *fProposedSplitPos = fCurVerticalOffset + fRelSplitPos;
978 *bAppChange = true;
979 if (*fProposedSplitPos <=
980 fCurVerticalOffset + XFA_LAYOUT_FLOAT_PERCISION) {
981 return true;
982 }
983 }
984 }
985 FX_FLOAT fRelSplitPos = *fProposedSplitPos - fCurBottomMargin;
986 for (CXFA_ContentLayoutItem* pChildItem =
987 (CXFA_ContentLayoutItem*)pLayoutItem->m_pFirstChild;
988 pChildItem;
989 pChildItem = (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling) {
990 FX_FLOAT fChildOffset =
991 fCurVerticalOffset + fCurTopMargin + pChildItem->m_sPos.y;
992 bool bChange = false;
993 if (FindLayoutItemSplitPos(pChildItem, fChildOffset, &fRelSplitPos,
994 &bChange, bCalculateMargin)) {
995 if (fRelSplitPos - fChildOffset < XFA_LAYOUT_FLOAT_PERCISION &&
996 bChange) {
997 *fProposedSplitPos = fRelSplitPos - fCurTopMargin;
998 } else {
999 *fProposedSplitPos = fRelSplitPos + fCurBottomMargin;
1000 }
1001 bAnyChanged = true;
1002 bChanged = true;
1003 if (*fProposedSplitPos <=
1004 fCurVerticalOffset + XFA_LAYOUT_FLOAT_PERCISION) {
1005 return true;
1006 }
1007 if (bAnyChanged)
1008 break;
1009 }
1010 }
1011 }
1012 return bAnyChanged;
1013 }
1014 case XFA_ATTRIBUTEENUM_ContentArea:
1015 case XFA_ATTRIBUTEENUM_PageArea: {
1016 *fProposedSplitPos = fCurVerticalOffset;
1017 return true;
1018 }
1019 default:
1020 return false;
1021 }
1022 }
1023
CalculatePositionedContainerPos(CXFA_Node * pNode,const CFX_SizeF & size)1024 CFX_PointF CalculatePositionedContainerPos(CXFA_Node* pNode,
1025 const CFX_SizeF& size) {
1026 XFA_ATTRIBUTEENUM eAnchorType = pNode->GetEnum(XFA_ATTRIBUTE_AnchorType);
1027 int32_t nAnchorType = 0;
1028 switch (eAnchorType) {
1029 case XFA_ATTRIBUTEENUM_TopLeft:
1030 nAnchorType = 0;
1031 break;
1032 case XFA_ATTRIBUTEENUM_TopCenter:
1033 nAnchorType = 1;
1034 break;
1035 case XFA_ATTRIBUTEENUM_TopRight:
1036 nAnchorType = 2;
1037 break;
1038 case XFA_ATTRIBUTEENUM_MiddleLeft:
1039 nAnchorType = 3;
1040 break;
1041 case XFA_ATTRIBUTEENUM_MiddleCenter:
1042 nAnchorType = 4;
1043 break;
1044 case XFA_ATTRIBUTEENUM_MiddleRight:
1045 nAnchorType = 5;
1046 break;
1047 case XFA_ATTRIBUTEENUM_BottomLeft:
1048 nAnchorType = 6;
1049 break;
1050 case XFA_ATTRIBUTEENUM_BottomCenter:
1051 nAnchorType = 7;
1052 break;
1053 case XFA_ATTRIBUTEENUM_BottomRight:
1054 nAnchorType = 8;
1055 break;
1056 default:
1057 break;
1058 }
1059 static const uint8_t nNextPos[4][9] = {{0, 1, 2, 3, 4, 5, 6, 7, 8},
1060 {6, 3, 0, 7, 4, 1, 8, 5, 2},
1061 {8, 7, 6, 5, 4, 3, 2, 1, 0},
1062 {2, 5, 8, 1, 4, 7, 0, 3, 6}};
1063
1064 CFX_PointF pos(pNode->GetMeasure(XFA_ATTRIBUTE_X).ToUnit(XFA_UNIT_Pt),
1065 pNode->GetMeasure(XFA_ATTRIBUTE_Y).ToUnit(XFA_UNIT_Pt));
1066 int32_t nRotate =
1067 FXSYS_round(pNode->GetMeasure(XFA_ATTRIBUTE_Rotate).GetValue());
1068 nRotate = XFA_MapRotation(nRotate) / 90;
1069 int32_t nAbsoluteAnchorType = nNextPos[nRotate][nAnchorType];
1070 switch (nAbsoluteAnchorType / 3) {
1071 case 1:
1072 pos.y -= size.height / 2;
1073 break;
1074 case 2:
1075 pos.y -= size.height;
1076 break;
1077 default:
1078 break;
1079 }
1080 switch (nAbsoluteAnchorType % 3) {
1081 case 1:
1082 pos.x -= size.width / 2;
1083 break;
1084 case 2:
1085 pos.x -= size.width;
1086 break;
1087 default:
1088 break;
1089 }
1090 return pos;
1091 }
1092
1093 } // namespace
1094
CXFA_ItemLayoutProcessor(CXFA_Node * pNode,CXFA_LayoutPageMgr * pPageMgr)1095 CXFA_ItemLayoutProcessor::CXFA_ItemLayoutProcessor(CXFA_Node* pNode,
1096 CXFA_LayoutPageMgr* pPageMgr)
1097 : m_pFormNode(pNode),
1098 m_pLayoutItem(nullptr),
1099 m_pCurChildNode(XFA_LAYOUT_INVALIDNODE),
1100 m_fUsedSize(0),
1101 m_pPageMgr(pPageMgr),
1102 m_bBreakPending(true),
1103 m_fLastRowWidth(0),
1104 m_fLastRowY(0),
1105 m_bUseInheriated(false),
1106 m_ePreProcessRs(XFA_ItemLayoutProcessorResult::Done),
1107 m_bKeepBreakFinish(false),
1108 m_bIsProcessKeep(false),
1109 m_pKeepHeadNode(nullptr),
1110 m_pKeepTailNode(nullptr),
1111 m_pOldLayoutItem(nullptr),
1112 m_pCurChildPreprocessor(nullptr),
1113 m_nCurChildNodeStage(XFA_ItemLayoutProcessorStages::None),
1114 m_fWidthLimite(0),
1115 m_bHasAvailHeight(true) {
1116 ASSERT(m_pFormNode && (m_pFormNode->IsContainerNode() ||
1117 m_pFormNode->GetElementType() == XFA_Element::Form));
1118 m_pOldLayoutItem =
1119 (CXFA_ContentLayoutItem*)m_pFormNode->GetUserData(XFA_LAYOUTITEMKEY);
1120 }
1121
~CXFA_ItemLayoutProcessor()1122 CXFA_ItemLayoutProcessor::~CXFA_ItemLayoutProcessor() {}
1123
CreateContentLayoutItem(CXFA_Node * pFormNode)1124 CXFA_ContentLayoutItem* CXFA_ItemLayoutProcessor::CreateContentLayoutItem(
1125 CXFA_Node* pFormNode) {
1126 if (!pFormNode)
1127 return nullptr;
1128
1129 CXFA_ContentLayoutItem* pLayoutItem = nullptr;
1130 if (m_pOldLayoutItem) {
1131 pLayoutItem = m_pOldLayoutItem;
1132 m_pOldLayoutItem = m_pOldLayoutItem->m_pNext;
1133 return pLayoutItem;
1134 }
1135 pLayoutItem = (CXFA_ContentLayoutItem*)pFormNode->GetDocument()
1136 ->GetNotify()
1137 ->OnCreateLayoutItem(pFormNode);
1138 CXFA_ContentLayoutItem* pPrevLayoutItem =
1139 (CXFA_ContentLayoutItem*)pFormNode->GetUserData(XFA_LAYOUTITEMKEY);
1140 if (pPrevLayoutItem) {
1141 while (pPrevLayoutItem->m_pNext)
1142 pPrevLayoutItem = pPrevLayoutItem->m_pNext;
1143
1144 pPrevLayoutItem->m_pNext = pLayoutItem;
1145 pLayoutItem->m_pPrev = pPrevLayoutItem;
1146 } else {
1147 pFormNode->SetUserData(XFA_LAYOUTITEMKEY, pLayoutItem);
1148 }
1149 return pLayoutItem;
1150 }
1151
FindSplitPos(FX_FLOAT fProposedSplitPos)1152 FX_FLOAT CXFA_ItemLayoutProcessor::FindSplitPos(FX_FLOAT fProposedSplitPos) {
1153 ASSERT(m_pLayoutItem);
1154 XFA_ATTRIBUTEENUM eLayout = m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
1155 bool bCalculateMargin = eLayout != XFA_ATTRIBUTEENUM_Position;
1156 while (fProposedSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
1157 bool bAppChange = false;
1158 if (!FindLayoutItemSplitPos(m_pLayoutItem, 0, &fProposedSplitPos,
1159 &bAppChange, bCalculateMargin)) {
1160 break;
1161 }
1162 }
1163 return fProposedSplitPos;
1164 }
1165
SplitLayoutItem(CXFA_ContentLayoutItem * pLayoutItem,CXFA_ContentLayoutItem * pSecondParent,FX_FLOAT fSplitPos)1166 void CXFA_ItemLayoutProcessor::SplitLayoutItem(
1167 CXFA_ContentLayoutItem* pLayoutItem,
1168 CXFA_ContentLayoutItem* pSecondParent,
1169 FX_FLOAT fSplitPos) {
1170 FX_FLOAT fCurTopMargin = 0, fCurBottomMargin = 0;
1171 XFA_ATTRIBUTEENUM eLayout = m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
1172 bool bCalculateMargin = true;
1173 if (eLayout == XFA_ATTRIBUTEENUM_Position)
1174 bCalculateMargin = false;
1175
1176 CXFA_Node* pMarginNode =
1177 pLayoutItem->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
1178 if (pMarginNode && bCalculateMargin) {
1179 fCurTopMargin =
1180 pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
1181 fCurBottomMargin =
1182 pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset).ToUnit(XFA_UNIT_Pt);
1183 }
1184
1185 CXFA_ContentLayoutItem* pSecondLayoutItem = nullptr;
1186 if (m_pCurChildPreprocessor &&
1187 m_pCurChildPreprocessor->m_pFormNode == pLayoutItem->m_pFormNode) {
1188 pSecondLayoutItem = m_pCurChildPreprocessor->CreateContentLayoutItem(
1189 pLayoutItem->m_pFormNode);
1190 } else {
1191 pSecondLayoutItem = CreateContentLayoutItem(pLayoutItem->m_pFormNode);
1192 }
1193 pSecondLayoutItem->m_sPos.x = pLayoutItem->m_sPos.x;
1194 pSecondLayoutItem->m_sSize.width = pLayoutItem->m_sSize.width;
1195 pSecondLayoutItem->m_sPos.y = 0;
1196 pSecondLayoutItem->m_sSize.height = pLayoutItem->m_sSize.height - fSplitPos;
1197 pLayoutItem->m_sSize.height -= pSecondLayoutItem->m_sSize.height;
1198 if (pLayoutItem->m_pFirstChild)
1199 pSecondLayoutItem->m_sSize.height += fCurTopMargin;
1200
1201 if (pSecondParent) {
1202 pSecondParent->AddChild(pSecondLayoutItem);
1203 if (fCurTopMargin > 0 && pLayoutItem->m_pFirstChild) {
1204 pSecondParent->m_sSize.height += fCurTopMargin;
1205 CXFA_ContentLayoutItem* pParentItem =
1206 (CXFA_ContentLayoutItem*)pSecondParent->m_pParent;
1207 while (pParentItem) {
1208 pParentItem->m_sSize.height += fCurTopMargin;
1209 pParentItem = (CXFA_ContentLayoutItem*)pParentItem->m_pParent;
1210 }
1211 }
1212 } else {
1213 pSecondLayoutItem->m_pParent = pLayoutItem->m_pParent;
1214 pSecondLayoutItem->m_pNextSibling = pLayoutItem->m_pNextSibling;
1215 pLayoutItem->m_pNextSibling = pSecondLayoutItem;
1216 }
1217
1218 CXFA_ContentLayoutItem* pChildren =
1219 (CXFA_ContentLayoutItem*)pLayoutItem->m_pFirstChild;
1220 pLayoutItem->m_pFirstChild = nullptr;
1221 FX_FLOAT lHeightForKeep = 0;
1222 CFX_ArrayTemplate<CXFA_ContentLayoutItem*> keepLayoutItems;
1223 FX_FLOAT fAddMarginHeight = 0;
1224 for (CXFA_ContentLayoutItem *pChildItem = pChildren, *pChildNext = nullptr;
1225 pChildItem; pChildItem = pChildNext) {
1226 pChildNext = (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling;
1227 pChildItem->m_pNextSibling = nullptr;
1228 if (fSplitPos <= fCurTopMargin + pChildItem->m_sPos.y + fCurBottomMargin +
1229 XFA_LAYOUT_FLOAT_PERCISION) {
1230 if (!ExistContainerKeep(pChildItem->m_pFormNode, true)) {
1231 pChildItem->m_sPos.y -= fSplitPos - fCurBottomMargin;
1232 pChildItem->m_sPos.y += lHeightForKeep;
1233 pChildItem->m_sPos.y += fAddMarginHeight;
1234 pSecondLayoutItem->AddChild(pChildItem);
1235 continue;
1236 }
1237
1238 if (lHeightForKeep < XFA_LAYOUT_FLOAT_PERCISION) {
1239 for (int32_t iIndex = 0; iIndex < keepLayoutItems.GetSize(); iIndex++) {
1240 CXFA_ContentLayoutItem* pPreItem = keepLayoutItems[iIndex];
1241 pLayoutItem->RemoveChild(pPreItem);
1242 pPreItem->m_sPos.y -= fSplitPos;
1243 if (pPreItem->m_sPos.y < 0)
1244 pPreItem->m_sPos.y = 0;
1245
1246 if (pPreItem->m_sPos.y + pPreItem->m_sSize.height > lHeightForKeep) {
1247 pPreItem->m_sPos.y = lHeightForKeep;
1248 lHeightForKeep += pPreItem->m_sSize.height;
1249 pSecondLayoutItem->m_sSize.height += pPreItem->m_sSize.height;
1250 if (pSecondParent)
1251 pSecondParent->m_sSize.height += pPreItem->m_sSize.height;
1252 }
1253 pSecondLayoutItem->AddChild(pPreItem);
1254 }
1255 }
1256
1257 pChildItem->m_sPos.y -= fSplitPos;
1258 pChildItem->m_sPos.y += lHeightForKeep;
1259 pChildItem->m_sPos.y += fAddMarginHeight;
1260 pSecondLayoutItem->AddChild(pChildItem);
1261 continue;
1262 }
1263
1264 if (fSplitPos + XFA_LAYOUT_FLOAT_PERCISION >=
1265 fCurTopMargin + fCurBottomMargin + pChildItem->m_sPos.y +
1266 pChildItem->m_sSize.height) {
1267 pLayoutItem->AddChild(pChildItem);
1268 if (ExistContainerKeep(pChildItem->m_pFormNode, false))
1269 keepLayoutItems.Add(pChildItem);
1270 else
1271 keepLayoutItems.RemoveAll();
1272
1273 continue;
1274 }
1275
1276 FX_FLOAT fOldHeight = pSecondLayoutItem->m_sSize.height;
1277 SplitLayoutItem(
1278 pChildItem, pSecondLayoutItem,
1279 fSplitPos - fCurTopMargin - fCurBottomMargin - pChildItem->m_sPos.y);
1280 fAddMarginHeight = pSecondLayoutItem->m_sSize.height - fOldHeight;
1281 pLayoutItem->AddChild(pChildItem);
1282 }
1283 }
1284
SplitLayoutItem(FX_FLOAT fSplitPos)1285 void CXFA_ItemLayoutProcessor::SplitLayoutItem(FX_FLOAT fSplitPos) {
1286 ASSERT(m_pLayoutItem);
1287 SplitLayoutItem(m_pLayoutItem, nullptr, fSplitPos);
1288 }
1289
ExtractLayoutItem()1290 CXFA_ContentLayoutItem* CXFA_ItemLayoutProcessor::ExtractLayoutItem() {
1291 CXFA_ContentLayoutItem* pLayoutItem = m_pLayoutItem;
1292 if (pLayoutItem) {
1293 m_pLayoutItem =
1294 static_cast<CXFA_ContentLayoutItem*>(pLayoutItem->m_pNextSibling);
1295 pLayoutItem->m_pNextSibling = nullptr;
1296 }
1297
1298 if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Done ||
1299 !ToContentLayoutItem(m_pOldLayoutItem)) {
1300 return pLayoutItem;
1301 }
1302
1303 if (m_pOldLayoutItem->m_pPrev)
1304 m_pOldLayoutItem->m_pPrev->m_pNext = nullptr;
1305
1306 CXFA_FFNotify* pNotify =
1307 m_pOldLayoutItem->m_pFormNode->GetDocument()->GetNotify();
1308 CXFA_LayoutProcessor* pDocLayout =
1309 m_pOldLayoutItem->m_pFormNode->GetDocument()->GetDocLayout();
1310 CXFA_ContentLayoutItem* pOldLayoutItem = m_pOldLayoutItem;
1311 while (pOldLayoutItem) {
1312 CXFA_ContentLayoutItem* pNextOldLayoutItem = pOldLayoutItem->m_pNext;
1313 pNotify->OnLayoutItemRemoving(pDocLayout, pOldLayoutItem);
1314 if (pOldLayoutItem->m_pParent)
1315 pOldLayoutItem->m_pParent->RemoveChild(pOldLayoutItem);
1316
1317 delete pOldLayoutItem;
1318 pOldLayoutItem = pNextOldLayoutItem;
1319 }
1320 m_pOldLayoutItem = nullptr;
1321 return pLayoutItem;
1322 }
1323
GotoNextContainerNode(CXFA_Node * & pCurActionNode,XFA_ItemLayoutProcessorStages & nCurStage,CXFA_Node * pParentContainer,bool bUsePageBreak)1324 void CXFA_ItemLayoutProcessor::GotoNextContainerNode(
1325 CXFA_Node*& pCurActionNode,
1326 XFA_ItemLayoutProcessorStages& nCurStage,
1327 CXFA_Node* pParentContainer,
1328 bool bUsePageBreak) {
1329 CXFA_Node* pEntireContainer = pParentContainer;
1330 CXFA_Node* pChildContainer = XFA_LAYOUT_INVALIDNODE;
1331 switch (nCurStage) {
1332 case XFA_ItemLayoutProcessorStages::BreakBefore:
1333 case XFA_ItemLayoutProcessorStages::BreakAfter: {
1334 pChildContainer = pCurActionNode->GetNodeItem(XFA_NODEITEM_Parent);
1335 break;
1336 }
1337 case XFA_ItemLayoutProcessorStages::Keep:
1338 case XFA_ItemLayoutProcessorStages::Container:
1339 pChildContainer = pCurActionNode;
1340 break;
1341 default:
1342 pChildContainer = XFA_LAYOUT_INVALIDNODE;
1343 break;
1344 }
1345
1346 switch (nCurStage) {
1347 case XFA_ItemLayoutProcessorStages::Keep: {
1348 CXFA_Node* pBreakAfterNode =
1349 pChildContainer->GetNodeItem(XFA_NODEITEM_FirstChild);
1350 if (!m_bKeepBreakFinish &&
1351 FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage, false)) {
1352 return;
1353 }
1354 goto CheckNextChildContainer;
1355 }
1356 case XFA_ItemLayoutProcessorStages::None: {
1357 pCurActionNode = XFA_LAYOUT_INVALIDNODE;
1358 case XFA_ItemLayoutProcessorStages::BookendLeader:
1359 for (CXFA_Node* pBookendNode =
1360 pCurActionNode == XFA_LAYOUT_INVALIDNODE
1361 ? pEntireContainer->GetNodeItem(XFA_NODEITEM_FirstChild)
1362 : pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling);
1363 pBookendNode; pBookendNode = pBookendNode->GetNodeItem(
1364 XFA_NODEITEM_NextSibling)) {
1365 switch (pBookendNode->GetElementType()) {
1366 case XFA_Element::Bookend:
1367 case XFA_Element::Break:
1368 pCurActionNode = pBookendNode;
1369 nCurStage = XFA_ItemLayoutProcessorStages::BookendLeader;
1370 return;
1371 default:
1372 break;
1373 }
1374 }
1375 }
1376 {
1377 pCurActionNode = XFA_LAYOUT_INVALIDNODE;
1378 case XFA_ItemLayoutProcessorStages::BreakBefore:
1379 if (pCurActionNode != XFA_LAYOUT_INVALIDNODE) {
1380 CXFA_Node* pBreakBeforeNode =
1381 pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling);
1382 if (!m_bKeepBreakFinish &&
1383 FindBreakNode(pBreakBeforeNode, pCurActionNode, &nCurStage,
1384 true)) {
1385 return;
1386 }
1387 if (m_bIsProcessKeep) {
1388 if (ProcessKeepNodesForBreakBefore(pCurActionNode, nCurStage,
1389 pChildContainer)) {
1390 return;
1391 }
1392 goto CheckNextChildContainer;
1393 }
1394 pCurActionNode = pChildContainer;
1395 nCurStage = XFA_ItemLayoutProcessorStages::Container;
1396 return;
1397 }
1398 goto CheckNextChildContainer;
1399 }
1400 case XFA_ItemLayoutProcessorStages::Container: {
1401 pCurActionNode = XFA_LAYOUT_INVALIDNODE;
1402 case XFA_ItemLayoutProcessorStages::BreakAfter: {
1403 if (pCurActionNode == XFA_LAYOUT_INVALIDNODE) {
1404 CXFA_Node* pBreakAfterNode =
1405 pChildContainer->GetNodeItem(XFA_NODEITEM_FirstChild);
1406 if (!m_bKeepBreakFinish &&
1407 FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage,
1408 false)) {
1409 return;
1410 }
1411 } else {
1412 CXFA_Node* pBreakAfterNode =
1413 pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling);
1414 if (FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage,
1415 false)) {
1416 return;
1417 }
1418 }
1419 goto CheckNextChildContainer;
1420 }
1421 }
1422
1423 CheckNextChildContainer : {
1424 CXFA_Node* pNextChildContainer =
1425 pChildContainer == XFA_LAYOUT_INVALIDNODE
1426 ? pEntireContainer->GetNodeItem(XFA_NODEITEM_FirstChild,
1427 XFA_ObjectType::ContainerNode)
1428 : pChildContainer->GetNodeItem(XFA_NODEITEM_NextSibling,
1429 XFA_ObjectType::ContainerNode);
1430 while (pNextChildContainer &&
1431 pNextChildContainer->IsLayoutGeneratedNode()) {
1432 CXFA_Node* pSaveNode = pNextChildContainer;
1433 pNextChildContainer = pNextChildContainer->GetNodeItem(
1434 XFA_NODEITEM_NextSibling, XFA_ObjectType::ContainerNode);
1435 if (pSaveNode->IsUnusedNode())
1436 DeleteLayoutGeneratedNode(pSaveNode);
1437 }
1438 if (!pNextChildContainer)
1439 goto NoMoreChildContainer;
1440
1441 bool bLastKeep = false;
1442 if (ProcessKeepNodesForCheckNext(pCurActionNode, nCurStage,
1443 pNextChildContainer, bLastKeep)) {
1444 return;
1445 }
1446 if (!m_bKeepBreakFinish && !bLastKeep &&
1447 FindBreakNode(
1448 pNextChildContainer->GetNodeItem(XFA_NODEITEM_FirstChild),
1449 pCurActionNode, &nCurStage, true)) {
1450 return;
1451 }
1452 pCurActionNode = pNextChildContainer;
1453 if (m_bIsProcessKeep)
1454 nCurStage = XFA_ItemLayoutProcessorStages::Keep;
1455 else
1456 nCurStage = XFA_ItemLayoutProcessorStages::Container;
1457 return;
1458 }
1459
1460 NoMoreChildContainer : {
1461 pCurActionNode = XFA_LAYOUT_INVALIDNODE;
1462 case XFA_ItemLayoutProcessorStages::BookendTrailer:
1463 for (CXFA_Node* pBookendNode =
1464 pCurActionNode == XFA_LAYOUT_INVALIDNODE
1465 ? pEntireContainer->GetNodeItem(XFA_NODEITEM_FirstChild)
1466 : pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling);
1467 pBookendNode; pBookendNode = pBookendNode->GetNodeItem(
1468 XFA_NODEITEM_NextSibling)) {
1469 switch (pBookendNode->GetElementType()) {
1470 case XFA_Element::Bookend:
1471 case XFA_Element::Break:
1472 pCurActionNode = pBookendNode;
1473 nCurStage = XFA_ItemLayoutProcessorStages::BookendTrailer;
1474 return;
1475 default:
1476 break;
1477 }
1478 }
1479 }
1480 default:
1481 pCurActionNode = nullptr;
1482 nCurStage = XFA_ItemLayoutProcessorStages::Done;
1483 }
1484 }
1485
ProcessKeepNodesForCheckNext(CXFA_Node * & pCurActionNode,XFA_ItemLayoutProcessorStages & nCurStage,CXFA_Node * & pNextContainer,bool & bLastKeepNode)1486 bool CXFA_ItemLayoutProcessor::ProcessKeepNodesForCheckNext(
1487 CXFA_Node*& pCurActionNode,
1488 XFA_ItemLayoutProcessorStages& nCurStage,
1489 CXFA_Node*& pNextContainer,
1490 bool& bLastKeepNode) {
1491 const bool bCanSplit = pNextContainer->GetIntact() == XFA_ATTRIBUTEENUM_None;
1492 bool bNextKeep = false;
1493 if (ExistContainerKeep(pNextContainer, false))
1494 bNextKeep = true;
1495
1496 if (bNextKeep && !bCanSplit) {
1497 if (!m_bIsProcessKeep && !m_bKeepBreakFinish) {
1498 m_pKeepHeadNode = pNextContainer;
1499 m_bIsProcessKeep = true;
1500 }
1501 return false;
1502 }
1503
1504 if (m_bIsProcessKeep && m_pKeepHeadNode) {
1505 m_pKeepTailNode = pNextContainer;
1506 if (!m_bKeepBreakFinish &&
1507 FindBreakNode(pNextContainer->GetNodeItem(XFA_NODEITEM_FirstChild),
1508 pCurActionNode, &nCurStage, true)) {
1509 return true;
1510 }
1511
1512 pNextContainer = m_pKeepHeadNode;
1513 m_bKeepBreakFinish = true;
1514 m_pKeepHeadNode = nullptr;
1515 m_pKeepTailNode = nullptr;
1516 m_bIsProcessKeep = false;
1517 } else {
1518 if (m_bKeepBreakFinish)
1519 bLastKeepNode = true;
1520 m_bKeepBreakFinish = false;
1521 }
1522
1523 return false;
1524 }
1525
ProcessKeepNodesForBreakBefore(CXFA_Node * & pCurActionNode,XFA_ItemLayoutProcessorStages & nCurStage,CXFA_Node * pContainerNode)1526 bool CXFA_ItemLayoutProcessor::ProcessKeepNodesForBreakBefore(
1527 CXFA_Node*& pCurActionNode,
1528 XFA_ItemLayoutProcessorStages& nCurStage,
1529 CXFA_Node* pContainerNode) {
1530 if (m_pKeepTailNode == pContainerNode) {
1531 pCurActionNode = m_pKeepHeadNode;
1532 m_bKeepBreakFinish = true;
1533 m_pKeepHeadNode = nullptr;
1534 m_pKeepTailNode = nullptr;
1535 m_bIsProcessKeep = false;
1536 nCurStage = XFA_ItemLayoutProcessorStages::Container;
1537 return true;
1538 }
1539
1540 CXFA_Node* pBreakAfterNode =
1541 pContainerNode->GetNodeItem(XFA_NODEITEM_FirstChild);
1542 return FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage, false);
1543 }
1544
XFA_ItemLayoutProcessor_IsTakingSpace(CXFA_Node * pNode)1545 bool XFA_ItemLayoutProcessor_IsTakingSpace(CXFA_Node* pNode) {
1546 XFA_ATTRIBUTEENUM ePresence = pNode->GetEnum(XFA_ATTRIBUTE_Presence);
1547 return ePresence == XFA_ATTRIBUTEENUM_Visible ||
1548 ePresence == XFA_ATTRIBUTEENUM_Invisible;
1549 }
1550
IncrementRelayoutNode(CXFA_LayoutProcessor * pLayoutProcessor,CXFA_Node * pNode,CXFA_Node * pParentNode)1551 bool CXFA_ItemLayoutProcessor::IncrementRelayoutNode(
1552 CXFA_LayoutProcessor* pLayoutProcessor,
1553 CXFA_Node* pNode,
1554 CXFA_Node* pParentNode) {
1555 return false;
1556 }
1557
DoLayoutPageArea(CXFA_ContainerLayoutItem * pPageAreaLayoutItem)1558 void CXFA_ItemLayoutProcessor::DoLayoutPageArea(
1559 CXFA_ContainerLayoutItem* pPageAreaLayoutItem) {
1560 CXFA_Node* pFormNode = pPageAreaLayoutItem->m_pFormNode;
1561 CXFA_Node* pCurChildNode = XFA_LAYOUT_INVALIDNODE;
1562 XFA_ItemLayoutProcessorStages nCurChildNodeStage =
1563 XFA_ItemLayoutProcessorStages::None;
1564 CXFA_LayoutItem* pBeforeItem = nullptr;
1565 for (GotoNextContainerNode(pCurChildNode, nCurChildNodeStage, pFormNode,
1566 false);
1567 pCurChildNode; GotoNextContainerNode(pCurChildNode, nCurChildNodeStage,
1568 pFormNode, false)) {
1569 if (nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container)
1570 continue;
1571 if (pCurChildNode->GetElementType() == XFA_Element::Variables)
1572 continue;
1573
1574 auto pProcessor =
1575 pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pCurChildNode, nullptr);
1576 pProcessor->DoLayout(false, FLT_MAX, FLT_MAX, nullptr);
1577 if (!pProcessor->HasLayoutItem())
1578 continue;
1579
1580 pProcessor->SetCurrentComponentPos(CalculatePositionedContainerPos(
1581 pCurChildNode, pProcessor->GetCurrentComponentSize()));
1582 CXFA_LayoutItem* pProcessItem = pProcessor->ExtractLayoutItem();
1583 if (!pBeforeItem)
1584 pPageAreaLayoutItem->AddHeadChild(pProcessItem);
1585 else
1586 pPageAreaLayoutItem->InsertChild(pBeforeItem, pProcessItem);
1587
1588 pBeforeItem = pProcessItem;
1589 }
1590
1591 pBeforeItem = nullptr;
1592 CXFA_LayoutItem* pLayoutItem = pPageAreaLayoutItem->m_pFirstChild;
1593 while (pLayoutItem) {
1594 if (!pLayoutItem->IsContentLayoutItem() ||
1595 pLayoutItem->m_pFormNode->GetElementType() != XFA_Element::Draw) {
1596 pLayoutItem = pLayoutItem->m_pNextSibling;
1597 continue;
1598 }
1599 if (pLayoutItem->m_pFormNode->GetElementType() != XFA_Element::Draw)
1600 continue;
1601
1602 CXFA_LayoutItem* pNextLayoutItem = pLayoutItem->m_pNextSibling;
1603 pPageAreaLayoutItem->RemoveChild(pLayoutItem);
1604 if (!pBeforeItem)
1605 pPageAreaLayoutItem->AddHeadChild(pLayoutItem);
1606 else
1607 pPageAreaLayoutItem->InsertChild(pBeforeItem, pLayoutItem);
1608
1609 pBeforeItem = pLayoutItem;
1610 pLayoutItem = pNextLayoutItem;
1611 }
1612 }
1613
DoLayoutPositionedContainer(CXFA_LayoutContext * pContext)1614 void CXFA_ItemLayoutProcessor::DoLayoutPositionedContainer(
1615 CXFA_LayoutContext* pContext) {
1616 if (m_pLayoutItem)
1617 return;
1618
1619 m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
1620 bool bIgnoreXY = (m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout) !=
1621 XFA_ATTRIBUTEENUM_Position);
1622 bool bContainerWidthAutoSize = true;
1623 bool bContainerHeightAutoSize = true;
1624 CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
1625 m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize);
1626
1627 FX_FLOAT fContentCalculatedWidth = 0;
1628 FX_FLOAT fContentCalculatedHeight = 0;
1629 FX_FLOAT fHiddenContentCalculatedWidth = 0;
1630 FX_FLOAT fHiddenContentCalculatedHeight = 0;
1631 if (m_pCurChildNode == XFA_LAYOUT_INVALIDNODE) {
1632 GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
1633 false);
1634 }
1635
1636 int32_t iColIndex = 0;
1637 for (; m_pCurChildNode; GotoNextContainerNode(
1638 m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false)) {
1639 if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container)
1640 continue;
1641 if (m_pCurChildNode->GetElementType() == XFA_Element::Variables)
1642 continue;
1643
1644 auto pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
1645 m_pCurChildNode, m_pPageMgr);
1646 if (pContext && pContext->m_prgSpecifiedColumnWidths) {
1647 int32_t iColSpan = m_pCurChildNode->GetInteger(XFA_ATTRIBUTE_ColSpan);
1648 if (iColSpan <=
1649 pContext->m_prgSpecifiedColumnWidths->GetSize() - iColIndex) {
1650 pContext->m_fCurColumnWidth = 0;
1651 pContext->m_bCurColumnWidthAvaiable = true;
1652 if (iColSpan == -1)
1653 iColSpan = pContext->m_prgSpecifiedColumnWidths->GetSize();
1654
1655 for (int32_t i = 0; iColIndex + i < iColSpan; ++i) {
1656 pContext->m_fCurColumnWidth +=
1657 pContext->m_prgSpecifiedColumnWidths->GetAt(iColIndex + i);
1658 }
1659 if (pContext->m_fCurColumnWidth == 0)
1660 pContext->m_bCurColumnWidthAvaiable = false;
1661
1662 iColIndex += iColSpan >= 0 ? iColSpan : 0;
1663 }
1664 }
1665
1666 pProcessor->DoLayout(false, FLT_MAX, FLT_MAX, pContext);
1667 if (!pProcessor->HasLayoutItem())
1668 continue;
1669
1670 CFX_SizeF size = pProcessor->GetCurrentComponentSize();
1671 bool bChangeParentSize = false;
1672 if (XFA_ItemLayoutProcessor_IsTakingSpace(m_pCurChildNode))
1673 bChangeParentSize = true;
1674
1675 CFX_PointF absolutePos;
1676 if (!bIgnoreXY)
1677 absolutePos = CalculatePositionedContainerPos(m_pCurChildNode, size);
1678
1679 pProcessor->SetCurrentComponentPos(absolutePos);
1680 if (bContainerWidthAutoSize) {
1681 FX_FLOAT fChildSuppliedWidth = absolutePos.x + size.width;
1682 if (bChangeParentSize) {
1683 fContentCalculatedWidth =
1684 std::max(fContentCalculatedWidth, fChildSuppliedWidth);
1685 } else {
1686 if (fHiddenContentCalculatedWidth < fChildSuppliedWidth &&
1687 m_pCurChildNode->GetElementType() != XFA_Element::Subform) {
1688 fHiddenContentCalculatedWidth = fChildSuppliedWidth;
1689 }
1690 }
1691 }
1692
1693 if (bContainerHeightAutoSize) {
1694 FX_FLOAT fChildSuppliedHeight = absolutePos.y + size.height;
1695 if (bChangeParentSize) {
1696 fContentCalculatedHeight =
1697 std::max(fContentCalculatedHeight, fChildSuppliedHeight);
1698 } else {
1699 if (fHiddenContentCalculatedHeight < fChildSuppliedHeight &&
1700 m_pCurChildNode->GetElementType() != XFA_Element::Subform) {
1701 fHiddenContentCalculatedHeight = fChildSuppliedHeight;
1702 }
1703 }
1704 }
1705 m_pLayoutItem->AddChild(pProcessor->ExtractLayoutItem());
1706 }
1707
1708 XFA_VERSION eVersion = m_pFormNode->GetDocument()->GetCurVersionMode();
1709 if (fContentCalculatedWidth == 0 && eVersion < XFA_VERSION_207)
1710 fContentCalculatedWidth = fHiddenContentCalculatedWidth;
1711 if (fContentCalculatedHeight == 0 && eVersion < XFA_VERSION_207)
1712 fContentCalculatedHeight = fHiddenContentCalculatedHeight;
1713
1714 containerSize = CalculateContainerComponentSizeFromContentSize(
1715 m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
1716 bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
1717 SetCurrentComponentSize(containerSize);
1718 }
1719
DoLayoutTableContainer(CXFA_Node * pLayoutNode)1720 void CXFA_ItemLayoutProcessor::DoLayoutTableContainer(CXFA_Node* pLayoutNode) {
1721 if (m_pLayoutItem)
1722 return;
1723 if (!pLayoutNode)
1724 pLayoutNode = m_pFormNode;
1725
1726 ASSERT(m_pCurChildNode == XFA_LAYOUT_INVALIDNODE);
1727
1728 m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
1729 bool bContainerWidthAutoSize = true;
1730 bool bContainerHeightAutoSize = true;
1731 CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
1732 m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize);
1733 FX_FLOAT fContentCalculatedWidth = 0;
1734 FX_FLOAT fContentCalculatedHeight = 0;
1735 CXFA_Node* pMarginNode =
1736 m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
1737 FX_FLOAT fLeftInset = 0;
1738 FX_FLOAT fRightInset = 0;
1739 if (pMarginNode) {
1740 fLeftInset =
1741 pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
1742 fRightInset =
1743 pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
1744 }
1745
1746 FX_FLOAT fContentWidthLimit =
1747 bContainerWidthAutoSize ? FLT_MAX
1748 : containerSize.width - fLeftInset - fRightInset;
1749 CFX_WideStringC wsColumnWidths;
1750 if (pLayoutNode->TryCData(XFA_ATTRIBUTE_ColumnWidths, wsColumnWidths)) {
1751 auto widths = SeparateStringW(wsColumnWidths.c_str(),
1752 wsColumnWidths.GetLength(), L' ');
1753 for (auto& width : widths) {
1754 width.TrimLeft(L' ');
1755 if (width.IsEmpty())
1756 continue;
1757
1758 CXFA_Measurement measure(width.AsStringC());
1759 m_rgSpecifiedColumnWidths.Add(measure.ToUnit(XFA_UNIT_Pt));
1760 }
1761 }
1762
1763 int32_t iSpecifiedColumnCount = m_rgSpecifiedColumnWidths.GetSize();
1764 CXFA_LayoutContext layoutContext;
1765 layoutContext.m_prgSpecifiedColumnWidths = &m_rgSpecifiedColumnWidths;
1766 CXFA_LayoutContext* pLayoutContext =
1767 iSpecifiedColumnCount > 0 ? &layoutContext : nullptr;
1768 if (m_pCurChildNode == XFA_LAYOUT_INVALIDNODE) {
1769 GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
1770 false);
1771 }
1772
1773 for (; m_pCurChildNode; GotoNextContainerNode(
1774 m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false)) {
1775 layoutContext.m_bCurColumnWidthAvaiable = false;
1776 layoutContext.m_fCurColumnWidth = 0;
1777 if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container)
1778 continue;
1779
1780 auto pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
1781 m_pCurChildNode, m_pPageMgr);
1782 pProcessor->DoLayout(false, FLT_MAX, FLT_MAX, pLayoutContext);
1783 if (!pProcessor->HasLayoutItem())
1784 continue;
1785
1786 m_pLayoutItem->AddChild(pProcessor->ExtractLayoutItem());
1787 }
1788
1789 int32_t iRowCount = 0;
1790 int32_t iColCount = 0;
1791 {
1792 CFX_ArrayTemplate<CXFA_ContentLayoutItem*> rgRowItems;
1793 CFX_ArrayTemplate<int32_t> rgRowItemsSpan;
1794 CFX_ArrayTemplate<FX_FLOAT> rgRowItemsWidth;
1795 for (CXFA_ContentLayoutItem* pLayoutChild =
1796 (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
1797 pLayoutChild;
1798 pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
1799 if (pLayoutChild->m_pFormNode->GetElementType() != XFA_Element::Subform)
1800 continue;
1801 if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode))
1802 continue;
1803
1804 XFA_ATTRIBUTEENUM eLayout =
1805 pLayoutChild->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
1806 if (eLayout != XFA_ATTRIBUTEENUM_Row &&
1807 eLayout != XFA_ATTRIBUTEENUM_Rl_row) {
1808 continue;
1809 }
1810 if (CXFA_ContentLayoutItem* pRowLayoutCell =
1811 (CXFA_ContentLayoutItem*)pLayoutChild->m_pFirstChild) {
1812 rgRowItems.Add(pRowLayoutCell);
1813 int32_t iColSpan =
1814 pRowLayoutCell->m_pFormNode->GetInteger(XFA_ATTRIBUTE_ColSpan);
1815 rgRowItemsSpan.Add(iColSpan);
1816 rgRowItemsWidth.Add(pRowLayoutCell->m_sSize.width);
1817 }
1818 }
1819
1820 iRowCount = rgRowItems.GetSize();
1821 iColCount = 0;
1822 bool bMoreColumns = true;
1823 while (bMoreColumns) {
1824 bMoreColumns = false;
1825 bool bAutoCol = false;
1826 for (int32_t i = 0; i < iRowCount; i++) {
1827 while (rgRowItems[i] && (rgRowItemsSpan[i] <= 0 ||
1828 !XFA_ItemLayoutProcessor_IsTakingSpace(
1829 rgRowItems[i]->m_pFormNode))) {
1830 CXFA_ContentLayoutItem* pNewCell =
1831 (CXFA_ContentLayoutItem*)rgRowItems[i]->m_pNextSibling;
1832 if (rgRowItemsSpan[i] < 0 && XFA_ItemLayoutProcessor_IsTakingSpace(
1833 rgRowItems[i]->m_pFormNode)) {
1834 pNewCell = nullptr;
1835 }
1836 rgRowItems[i] = pNewCell;
1837 rgRowItemsSpan[i] =
1838 pNewCell
1839 ? pNewCell->m_pFormNode->GetInteger(XFA_ATTRIBUTE_ColSpan)
1840 : 0;
1841 rgRowItemsWidth[i] = pNewCell ? pNewCell->m_sSize.width : 0;
1842 }
1843 CXFA_ContentLayoutItem* pCell = rgRowItems[i];
1844 if (!pCell)
1845 continue;
1846
1847 bMoreColumns = true;
1848 if (rgRowItemsSpan[i] != 1)
1849 continue;
1850
1851 if (iColCount >= iSpecifiedColumnCount) {
1852 int32_t c = iColCount + 1 - m_rgSpecifiedColumnWidths.GetSize();
1853 for (int32_t j = 0; j < c; j++)
1854 m_rgSpecifiedColumnWidths.Add(0);
1855 }
1856 if (m_rgSpecifiedColumnWidths[iColCount] < XFA_LAYOUT_FLOAT_PERCISION)
1857 bAutoCol = true;
1858 if (bAutoCol &&
1859 m_rgSpecifiedColumnWidths[iColCount] < rgRowItemsWidth[i]) {
1860 m_rgSpecifiedColumnWidths[iColCount] = rgRowItemsWidth[i];
1861 }
1862 }
1863
1864 if (!bMoreColumns)
1865 continue;
1866
1867 FX_FLOAT fFinalColumnWidth = 0.0f;
1868 if (iColCount < m_rgSpecifiedColumnWidths.GetSize())
1869 fFinalColumnWidth = m_rgSpecifiedColumnWidths[iColCount];
1870 for (int32_t i = 0; i < iRowCount; ++i) {
1871 if (!rgRowItems[i])
1872 continue;
1873 --rgRowItemsSpan[i];
1874 rgRowItemsWidth[i] -= fFinalColumnWidth;
1875 }
1876 ++iColCount;
1877 }
1878 }
1879
1880 FX_FLOAT fCurrentRowY = 0;
1881 for (CXFA_ContentLayoutItem* pLayoutChild =
1882 (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
1883 pLayoutChild;
1884 pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
1885 if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode))
1886 continue;
1887
1888 if (pLayoutChild->m_pFormNode->GetElementType() == XFA_Element::Subform) {
1889 XFA_ATTRIBUTEENUM eSubformLayout =
1890 pLayoutChild->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
1891 if (eSubformLayout == XFA_ATTRIBUTEENUM_Row ||
1892 eSubformLayout == XFA_ATTRIBUTEENUM_Rl_row) {
1893 RelocateTableRowCells(pLayoutChild, m_rgSpecifiedColumnWidths,
1894 eSubformLayout);
1895 }
1896 }
1897
1898 pLayoutChild->m_sPos.y = fCurrentRowY;
1899 if (bContainerWidthAutoSize) {
1900 pLayoutChild->m_sPos.x = 0;
1901 } else {
1902 switch (pLayoutChild->m_pFormNode->GetEnum(XFA_ATTRIBUTE_HAlign)) {
1903 case XFA_ATTRIBUTEENUM_Center:
1904 pLayoutChild->m_sPos.x =
1905 (fContentWidthLimit - pLayoutChild->m_sSize.width) / 2;
1906 break;
1907 case XFA_ATTRIBUTEENUM_Right:
1908 pLayoutChild->m_sPos.x =
1909 fContentWidthLimit - pLayoutChild->m_sSize.width;
1910 break;
1911 case XFA_ATTRIBUTEENUM_Left:
1912 default:
1913 pLayoutChild->m_sPos.x = 0;
1914 break;
1915 }
1916 }
1917
1918 if (bContainerWidthAutoSize) {
1919 FX_FLOAT fChildSuppliedWidth =
1920 pLayoutChild->m_sPos.x + pLayoutChild->m_sSize.width;
1921 if (fContentWidthLimit < FLT_MAX &&
1922 fContentWidthLimit > fChildSuppliedWidth) {
1923 fChildSuppliedWidth = fContentWidthLimit;
1924 }
1925 fContentCalculatedWidth =
1926 std::max(fContentCalculatedWidth, fChildSuppliedWidth);
1927 }
1928 fCurrentRowY += pLayoutChild->m_sSize.height;
1929 }
1930
1931 if (bContainerHeightAutoSize)
1932 fContentCalculatedHeight = std::max(fContentCalculatedHeight, fCurrentRowY);
1933
1934 containerSize = CalculateContainerComponentSizeFromContentSize(
1935 m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
1936 bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
1937 SetCurrentComponentSize(containerSize);
1938 }
1939
IsAddNewRowForTrailer(CXFA_ContentLayoutItem * pTrailerItem)1940 bool CXFA_ItemLayoutProcessor::IsAddNewRowForTrailer(
1941 CXFA_ContentLayoutItem* pTrailerItem) {
1942 if (!pTrailerItem)
1943 return false;
1944
1945 FX_FLOAT fWidth = pTrailerItem->m_sSize.width;
1946 XFA_ATTRIBUTEENUM eLayout = m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
1947 return eLayout == XFA_ATTRIBUTEENUM_Tb || m_fWidthLimite <= fWidth;
1948 }
1949
InsertKeepLayoutItems()1950 FX_FLOAT CXFA_ItemLayoutProcessor::InsertKeepLayoutItems() {
1951 if (m_arrayKeepItems.empty())
1952 return 0;
1953
1954 if (!m_pLayoutItem) {
1955 m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
1956 m_pLayoutItem->m_sSize.clear();
1957 }
1958
1959 FX_FLOAT fTotalHeight = 0;
1960 for (auto iter = m_arrayKeepItems.rbegin(); iter != m_arrayKeepItems.rend();
1961 iter++) {
1962 AddLeaderAfterSplit(this, *iter);
1963 fTotalHeight += (*iter)->m_sSize.height;
1964 }
1965 m_arrayKeepItems.clear();
1966
1967 return fTotalHeight;
1968 }
1969
ProcessKeepForSplit(CXFA_ItemLayoutProcessor * pParentProcessor,CXFA_ItemLayoutProcessor * pChildProcessor,XFA_ItemLayoutProcessorResult eRetValue,CFX_ArrayTemplate<CXFA_ContentLayoutItem * > * rgCurLineLayoutItem,FX_FLOAT * fContentCurRowAvailWidth,FX_FLOAT * fContentCurRowHeight,FX_FLOAT * fContentCurRowY,bool * bAddedItemInRow,bool * bForceEndPage,XFA_ItemLayoutProcessorResult * result)1970 bool CXFA_ItemLayoutProcessor::ProcessKeepForSplit(
1971 CXFA_ItemLayoutProcessor* pParentProcessor,
1972 CXFA_ItemLayoutProcessor* pChildProcessor,
1973 XFA_ItemLayoutProcessorResult eRetValue,
1974 CFX_ArrayTemplate<CXFA_ContentLayoutItem*>* rgCurLineLayoutItem,
1975 FX_FLOAT* fContentCurRowAvailWidth,
1976 FX_FLOAT* fContentCurRowHeight,
1977 FX_FLOAT* fContentCurRowY,
1978 bool* bAddedItemInRow,
1979 bool* bForceEndPage,
1980 XFA_ItemLayoutProcessorResult* result) {
1981 if (!pParentProcessor || !pChildProcessor)
1982 return false;
1983
1984 if (pParentProcessor->m_pCurChildNode->GetIntact() ==
1985 XFA_ATTRIBUTEENUM_None &&
1986 pChildProcessor->m_bHasAvailHeight)
1987 return false;
1988
1989 if (!ExistContainerKeep(pParentProcessor->m_pCurChildNode, true))
1990 return false;
1991
1992 CFX_SizeF childSize = pChildProcessor->GetCurrentComponentSize();
1993 std::vector<CXFA_ContentLayoutItem*> keepLayoutItems;
1994 if (pParentProcessor->JudgePutNextPage(pParentProcessor->m_pLayoutItem,
1995 childSize.height, &keepLayoutItems)) {
1996 m_arrayKeepItems.clear();
1997
1998 for (auto item : keepLayoutItems) {
1999 pParentProcessor->m_pLayoutItem->RemoveChild(item);
2000 *fContentCurRowY -= item->m_sSize.height;
2001 m_arrayKeepItems.push_back(item);
2002 }
2003 *bAddedItemInRow = true;
2004 *bForceEndPage = true;
2005 *result = XFA_ItemLayoutProcessorResult::PageFullBreak;
2006 return true;
2007 }
2008
2009 rgCurLineLayoutItem->Add(pChildProcessor->ExtractLayoutItem());
2010 *bAddedItemInRow = true;
2011 *fContentCurRowAvailWidth -= childSize.width;
2012 *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height);
2013 *result = eRetValue;
2014
2015 return true;
2016 }
2017
JudgePutNextPage(CXFA_ContentLayoutItem * pParentLayoutItem,FX_FLOAT fChildHeight,std::vector<CXFA_ContentLayoutItem * > * pKeepItems)2018 bool CXFA_ItemLayoutProcessor::JudgePutNextPage(
2019 CXFA_ContentLayoutItem* pParentLayoutItem,
2020 FX_FLOAT fChildHeight,
2021 std::vector<CXFA_ContentLayoutItem*>* pKeepItems) {
2022 if (!pParentLayoutItem)
2023 return false;
2024
2025 FX_FLOAT fItemsHeight = 0;
2026 for (CXFA_ContentLayoutItem* pChildLayoutItem =
2027 (CXFA_ContentLayoutItem*)pParentLayoutItem->m_pFirstChild;
2028 pChildLayoutItem;
2029 pChildLayoutItem =
2030 (CXFA_ContentLayoutItem*)pChildLayoutItem->m_pNextSibling) {
2031 if (ExistContainerKeep(pChildLayoutItem->m_pFormNode, false)) {
2032 pKeepItems->push_back(pChildLayoutItem);
2033 fItemsHeight += pChildLayoutItem->m_sSize.height;
2034 } else {
2035 pKeepItems->clear();
2036 fItemsHeight = 0;
2037 }
2038 }
2039 fItemsHeight += fChildHeight;
2040 return m_pPageMgr->GetNextAvailContentHeight(fItemsHeight);
2041 }
2042
ProcessUnUseBinds(CXFA_Node * pFormNode)2043 void CXFA_ItemLayoutProcessor::ProcessUnUseBinds(CXFA_Node* pFormNode) {
2044 if (!pFormNode)
2045 return;
2046
2047 CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
2048 pFormNode);
2049 for (CXFA_Node* pNode = sIterator.MoveToNext(); pNode;
2050 pNode = sIterator.MoveToNext()) {
2051 if (pNode->IsContainerNode()) {
2052 CXFA_Node* pBindNode = pNode->GetBindData();
2053 if (pBindNode) {
2054 pBindNode->RemoveBindItem(pNode);
2055 pNode->SetObject(XFA_ATTRIBUTE_BindingNode, nullptr);
2056 }
2057 }
2058 pNode->SetFlag(XFA_NodeFlag_UnusedNode, true);
2059 }
2060 }
2061
ProcessUnUseOverFlow(CXFA_Node * pLeaderNode,CXFA_Node * pTrailerNode,CXFA_ContentLayoutItem * pTrailerItem,CXFA_Node * pFormNode)2062 void CXFA_ItemLayoutProcessor::ProcessUnUseOverFlow(
2063 CXFA_Node* pLeaderNode,
2064 CXFA_Node* pTrailerNode,
2065 CXFA_ContentLayoutItem* pTrailerItem,
2066 CXFA_Node* pFormNode) {
2067 ProcessUnUseBinds(pLeaderNode);
2068 ProcessUnUseBinds(pTrailerNode);
2069 if (!pFormNode)
2070 return;
2071
2072 if (pFormNode->GetElementType() == XFA_Element::Overflow ||
2073 pFormNode->GetElementType() == XFA_Element::Break) {
2074 pFormNode = pFormNode->GetNodeItem(XFA_NODEITEM_Parent);
2075 }
2076 if (pLeaderNode && pFormNode)
2077 pFormNode->RemoveChild(pLeaderNode);
2078 if (pTrailerNode && pFormNode)
2079 pFormNode->RemoveChild(pTrailerNode);
2080 if (pTrailerItem)
2081 XFA_ReleaseLayoutItem(pTrailerItem);
2082 }
2083
DoLayoutFlowedContainer(bool bUseBreakControl,XFA_ATTRIBUTEENUM eFlowStrategy,FX_FLOAT fHeightLimit,FX_FLOAT fRealHeight,CXFA_LayoutContext * pContext,bool bRootForceTb)2084 XFA_ItemLayoutProcessorResult CXFA_ItemLayoutProcessor::DoLayoutFlowedContainer(
2085 bool bUseBreakControl,
2086 XFA_ATTRIBUTEENUM eFlowStrategy,
2087 FX_FLOAT fHeightLimit,
2088 FX_FLOAT fRealHeight,
2089 CXFA_LayoutContext* pContext,
2090 bool bRootForceTb) {
2091 m_bHasAvailHeight = true;
2092 bool bBreakDone = false;
2093 bool bContainerWidthAutoSize = true;
2094 bool bContainerHeightAutoSize = true;
2095 bool bForceEndPage = false;
2096 bool bIsManualBreak = false;
2097 if (m_pCurChildPreprocessor) {
2098 m_pCurChildPreprocessor->m_ePreProcessRs =
2099 XFA_ItemLayoutProcessorResult::Done;
2100 }
2101
2102 CFX_SizeF containerSize = CalculateContainerSpecifiedSize(
2103 m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize);
2104 if (pContext && pContext->m_bCurColumnWidthAvaiable) {
2105 bContainerWidthAutoSize = false;
2106 containerSize.width = pContext->m_fCurColumnWidth;
2107 }
2108 if (!bContainerHeightAutoSize)
2109 containerSize.height -= m_fUsedSize;
2110
2111 if (!bContainerHeightAutoSize) {
2112 CXFA_Node* pParentNode = m_pFormNode->GetNodeItem(XFA_NODEITEM_Parent);
2113 bool bFocrTb = false;
2114 if (pParentNode &&
2115 GetLayout(pParentNode, &bFocrTb) == XFA_ATTRIBUTEENUM_Row) {
2116 CXFA_Node* pChildContainer = m_pFormNode->GetNodeItem(
2117 XFA_NODEITEM_FirstChild, XFA_ObjectType::ContainerNode);
2118 if (pChildContainer &&
2119 pChildContainer->GetNodeItem(XFA_NODEITEM_NextSibling,
2120 XFA_ObjectType::ContainerNode)) {
2121 containerSize.height = 0;
2122 bContainerHeightAutoSize = true;
2123 }
2124 }
2125 }
2126
2127 CXFA_Node* pMarginNode =
2128 m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
2129 FX_FLOAT fLeftInset = 0;
2130 FX_FLOAT fTopInset = 0;
2131 FX_FLOAT fRightInset = 0;
2132 FX_FLOAT fBottomInset = 0;
2133 if (pMarginNode) {
2134 fLeftInset =
2135 pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
2136 fTopInset =
2137 pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
2138 fRightInset =
2139 pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
2140 fBottomInset =
2141 pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset).ToUnit(XFA_UNIT_Pt);
2142 }
2143 FX_FLOAT fContentWidthLimit =
2144 bContainerWidthAutoSize ? FLT_MAX
2145 : containerSize.width - fLeftInset - fRightInset;
2146 FX_FLOAT fContentCalculatedWidth = 0;
2147 FX_FLOAT fContentCalculatedHeight = 0;
2148 FX_FLOAT fAvailHeight = fHeightLimit - fTopInset - fBottomInset;
2149 if (fAvailHeight < 0)
2150 m_bHasAvailHeight = false;
2151
2152 fRealHeight = fRealHeight - fTopInset - fBottomInset;
2153 FX_FLOAT fContentCurRowY = 0;
2154 CXFA_ContentLayoutItem* pLayoutChild = nullptr;
2155 if (m_pLayoutItem) {
2156 if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Done &&
2157 eFlowStrategy != XFA_ATTRIBUTEENUM_Tb) {
2158 pLayoutChild = (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
2159 for (CXFA_ContentLayoutItem* pLayoutNext = pLayoutChild; pLayoutNext;
2160 pLayoutNext = (CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling) {
2161 if (pLayoutNext->m_sPos.y != pLayoutChild->m_sPos.y)
2162 pLayoutChild = pLayoutNext;
2163 }
2164 }
2165
2166 for (CXFA_ContentLayoutItem* pLayoutTempChild =
2167 (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
2168 pLayoutTempChild != pLayoutChild;
2169 pLayoutTempChild =
2170 (CXFA_ContentLayoutItem*)pLayoutTempChild->m_pNextSibling) {
2171 if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutTempChild->m_pFormNode))
2172 continue;
2173
2174 fContentCalculatedWidth = std::max(
2175 fContentCalculatedWidth,
2176 pLayoutTempChild->m_sPos.x + pLayoutTempChild->m_sSize.width);
2177 fContentCalculatedHeight = std::max(
2178 fContentCalculatedHeight,
2179 pLayoutTempChild->m_sPos.y + pLayoutTempChild->m_sSize.height);
2180 }
2181
2182 if (pLayoutChild)
2183 fContentCurRowY = pLayoutChild->m_sPos.y;
2184 else
2185 fContentCurRowY = fContentCalculatedHeight;
2186 }
2187
2188 fContentCurRowY += InsertKeepLayoutItems();
2189 if (m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::None) {
2190 GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
2191 true);
2192 }
2193
2194 fContentCurRowY += InsertPendingItems(this, m_pFormNode);
2195 if (m_pCurChildPreprocessor &&
2196 m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::Container) {
2197 if (ExistContainerKeep(m_pCurChildPreprocessor->GetFormNode(), false)) {
2198 m_pKeepHeadNode = m_pCurChildNode;
2199 m_bIsProcessKeep = true;
2200 m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Keep;
2201 }
2202 }
2203
2204 while (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Done) {
2205 FX_FLOAT fContentCurRowHeight = 0;
2206 FX_FLOAT fContentCurRowAvailWidth = fContentWidthLimit;
2207 m_fWidthLimite = fContentCurRowAvailWidth;
2208 CFX_ArrayTemplate<CXFA_ContentLayoutItem*> rgCurLineLayoutItems[3];
2209 uint8_t uCurHAlignState =
2210 (eFlowStrategy != XFA_ATTRIBUTEENUM_Rl_tb ? 0 : 2);
2211 if (pLayoutChild) {
2212 for (CXFA_ContentLayoutItem* pLayoutNext = pLayoutChild; pLayoutNext;
2213 pLayoutNext = (CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling) {
2214 if (!pLayoutNext->m_pNextSibling && m_pCurChildPreprocessor &&
2215 m_pCurChildPreprocessor->m_pFormNode == pLayoutNext->m_pFormNode) {
2216 pLayoutNext->m_pNext = m_pCurChildPreprocessor->m_pLayoutItem;
2217 m_pCurChildPreprocessor->m_pLayoutItem = pLayoutNext;
2218 break;
2219 }
2220 uint8_t uHAlign = HAlignEnumToInt(
2221 pLayoutNext->m_pFormNode->GetEnum(XFA_ATTRIBUTE_HAlign));
2222 rgCurLineLayoutItems[uHAlign].Add(pLayoutNext);
2223 if (eFlowStrategy == XFA_ATTRIBUTEENUM_Lr_tb) {
2224 if (uHAlign > uCurHAlignState)
2225 uCurHAlignState = uHAlign;
2226 } else if (uHAlign < uCurHAlignState) {
2227 uCurHAlignState = uHAlign;
2228 }
2229 if (XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutNext->m_pFormNode)) {
2230 if (pLayoutNext->m_sSize.height > fContentCurRowHeight)
2231 fContentCurRowHeight = pLayoutNext->m_sSize.height;
2232 fContentCurRowAvailWidth -= pLayoutNext->m_sSize.width;
2233 }
2234 }
2235
2236 if ((CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild ==
2237 pLayoutChild) {
2238 m_pLayoutItem->m_pFirstChild = nullptr;
2239 } else {
2240 CXFA_ContentLayoutItem* pLayoutNext =
2241 (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
2242 for (; pLayoutNext;
2243 pLayoutNext =
2244 (CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling) {
2245 if ((CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling ==
2246 pLayoutChild) {
2247 pLayoutNext->m_pNextSibling = nullptr;
2248 break;
2249 }
2250 }
2251 }
2252
2253 CXFA_ContentLayoutItem* pLayoutNextTemp =
2254 (CXFA_ContentLayoutItem*)pLayoutChild;
2255 while (pLayoutNextTemp) {
2256 pLayoutNextTemp->m_pParent = nullptr;
2257 CXFA_ContentLayoutItem* pSaveLayoutNext =
2258 (CXFA_ContentLayoutItem*)pLayoutNextTemp->m_pNextSibling;
2259 pLayoutNextTemp->m_pNextSibling = nullptr;
2260 pLayoutNextTemp = pSaveLayoutNext;
2261 }
2262 pLayoutChild = nullptr;
2263 }
2264
2265 while (m_pCurChildNode) {
2266 std::unique_ptr<CXFA_ItemLayoutProcessor> pProcessor;
2267 bool bAddedItemInRow = false;
2268 fContentCurRowY += InsertPendingItems(this, m_pFormNode);
2269 switch (m_nCurChildNodeStage) {
2270 case XFA_ItemLayoutProcessorStages::Keep:
2271 case XFA_ItemLayoutProcessorStages::None:
2272 break;
2273 case XFA_ItemLayoutProcessorStages::BreakBefore: {
2274 for (auto item : m_arrayKeepItems) {
2275 m_pLayoutItem->RemoveChild(item);
2276 fContentCalculatedHeight -= item->m_sSize.height;
2277 }
2278
2279 CXFA_Node* pLeaderNode = nullptr;
2280 CXFA_Node* pTrailerNode = nullptr;
2281 bool bCreatePage = false;
2282 if (!bUseBreakControl || !m_pPageMgr ||
2283 !m_pPageMgr->ProcessBreakBeforeOrAfter(m_pCurChildNode, true,
2284 pLeaderNode, pTrailerNode,
2285 bCreatePage) ||
2286 m_pFormNode->GetElementType() == XFA_Element::Form ||
2287 !bCreatePage) {
2288 break;
2289 }
2290
2291 if (JudgeLeaderOrTrailerForOccur(pLeaderNode))
2292 AddPendingNode(this, pLeaderNode, true);
2293
2294 if (JudgeLeaderOrTrailerForOccur(pTrailerNode)) {
2295 if (m_pFormNode->GetNodeItem(XFA_NODEITEM_Parent)
2296 ->GetElementType() == XFA_Element::Form &&
2297 !m_pLayoutItem) {
2298 AddPendingNode(this, pTrailerNode, true);
2299 } else {
2300 auto pTempProcessor =
2301 pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pTrailerNode,
2302 nullptr);
2303 InsertFlowedItem(
2304 this, pTempProcessor.get(), bContainerWidthAutoSize,
2305 bContainerHeightAutoSize, containerSize.height, eFlowStrategy,
2306 &uCurHAlignState, rgCurLineLayoutItems, false, FLT_MAX,
2307 FLT_MAX, fContentWidthLimit, &fContentCurRowY,
2308 &fContentCurRowAvailWidth, &fContentCurRowHeight,
2309 &bAddedItemInRow, &bForceEndPage, pContext, false);
2310 }
2311 }
2312 GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage,
2313 m_pFormNode, true);
2314 bForceEndPage = true;
2315 bIsManualBreak = true;
2316 goto SuspendAndCreateNewRow;
2317 }
2318 case XFA_ItemLayoutProcessorStages::BreakAfter: {
2319 CXFA_Node* pLeaderNode = nullptr;
2320 CXFA_Node* pTrailerNode = nullptr;
2321 bool bCreatePage = false;
2322 if (!bUseBreakControl || !m_pPageMgr ||
2323 !m_pPageMgr->ProcessBreakBeforeOrAfter(m_pCurChildNode, false,
2324 pLeaderNode, pTrailerNode,
2325 bCreatePage) ||
2326 m_pFormNode->GetElementType() == XFA_Element::Form) {
2327 break;
2328 }
2329
2330 if (JudgeLeaderOrTrailerForOccur(pTrailerNode)) {
2331 auto pTempProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
2332 pTrailerNode, nullptr);
2333 InsertFlowedItem(
2334 this, pTempProcessor.get(), bContainerWidthAutoSize,
2335 bContainerHeightAutoSize, containerSize.height, eFlowStrategy,
2336 &uCurHAlignState, rgCurLineLayoutItems, false, FLT_MAX, FLT_MAX,
2337 fContentWidthLimit, &fContentCurRowY, &fContentCurRowAvailWidth,
2338 &fContentCurRowHeight, &bAddedItemInRow, &bForceEndPage,
2339 pContext, false);
2340 }
2341 if (!bCreatePage) {
2342 if (JudgeLeaderOrTrailerForOccur(pLeaderNode)) {
2343 CalculateRowChildPosition(
2344 rgCurLineLayoutItems, eFlowStrategy, bContainerHeightAutoSize,
2345 bContainerWidthAutoSize, &fContentCalculatedWidth,
2346 &fContentCalculatedHeight, &fContentCurRowY,
2347 fContentCurRowHeight, fContentWidthLimit, false);
2348 rgCurLineLayoutItems->RemoveAll();
2349 auto pTempProcessor =
2350 pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pLeaderNode,
2351 nullptr);
2352 InsertFlowedItem(
2353 this, pTempProcessor.get(), bContainerWidthAutoSize,
2354 bContainerHeightAutoSize, containerSize.height, eFlowStrategy,
2355 &uCurHAlignState, rgCurLineLayoutItems, false, FLT_MAX,
2356 FLT_MAX, fContentWidthLimit, &fContentCurRowY,
2357 &fContentCurRowAvailWidth, &fContentCurRowHeight,
2358 &bAddedItemInRow, &bForceEndPage, pContext, false);
2359 }
2360 } else {
2361 if (JudgeLeaderOrTrailerForOccur(pLeaderNode))
2362 AddPendingNode(this, pLeaderNode, true);
2363 }
2364
2365 GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage,
2366 m_pFormNode, true);
2367 if (bCreatePage) {
2368 bForceEndPage = true;
2369 bIsManualBreak = true;
2370 if (m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::Done)
2371 bBreakDone = true;
2372 }
2373 goto SuspendAndCreateNewRow;
2374 }
2375 case XFA_ItemLayoutProcessorStages::BookendLeader: {
2376 CXFA_Node* pLeaderNode = nullptr;
2377 if (m_pCurChildPreprocessor) {
2378 pProcessor.reset(m_pCurChildPreprocessor);
2379 m_pCurChildPreprocessor = nullptr;
2380 } else if (m_pPageMgr &&
2381 m_pPageMgr->ProcessBookendLeaderOrTrailer(
2382 m_pCurChildNode, true, pLeaderNode)) {
2383 pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
2384 pLeaderNode, m_pPageMgr);
2385 }
2386
2387 if (pProcessor) {
2388 if (InsertFlowedItem(
2389 this, pProcessor.get(), bContainerWidthAutoSize,
2390 bContainerHeightAutoSize, containerSize.height,
2391 eFlowStrategy, &uCurHAlignState, rgCurLineLayoutItems,
2392 bUseBreakControl, fAvailHeight, fRealHeight,
2393 fContentWidthLimit, &fContentCurRowY,
2394 &fContentCurRowAvailWidth, &fContentCurRowHeight,
2395 &bAddedItemInRow, &bForceEndPage, pContext,
2396 false) != XFA_ItemLayoutProcessorResult::Done) {
2397 goto SuspendAndCreateNewRow;
2398 } else {
2399 pProcessor.reset();
2400 }
2401 }
2402 break;
2403 }
2404 case XFA_ItemLayoutProcessorStages::BookendTrailer: {
2405 CXFA_Node* pTrailerNode = nullptr;
2406 if (m_pCurChildPreprocessor) {
2407 pProcessor.reset(m_pCurChildPreprocessor);
2408 m_pCurChildPreprocessor = nullptr;
2409 } else if (m_pPageMgr &&
2410 m_pPageMgr->ProcessBookendLeaderOrTrailer(
2411 m_pCurChildNode, false, pTrailerNode)) {
2412 pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
2413 pTrailerNode, m_pPageMgr);
2414 }
2415 if (pProcessor) {
2416 if (InsertFlowedItem(
2417 this, pProcessor.get(), bContainerWidthAutoSize,
2418 bContainerHeightAutoSize, containerSize.height,
2419 eFlowStrategy, &uCurHAlignState, rgCurLineLayoutItems,
2420 bUseBreakControl, fAvailHeight, fRealHeight,
2421 fContentWidthLimit, &fContentCurRowY,
2422 &fContentCurRowAvailWidth, &fContentCurRowHeight,
2423 &bAddedItemInRow, &bForceEndPage, pContext,
2424 false) != XFA_ItemLayoutProcessorResult::Done) {
2425 goto SuspendAndCreateNewRow;
2426 } else {
2427 pProcessor.reset();
2428 }
2429 }
2430 break;
2431 }
2432 case XFA_ItemLayoutProcessorStages::Container: {
2433 ASSERT(m_pCurChildNode->IsContainerNode());
2434 if (m_pCurChildNode->GetElementType() == XFA_Element::Variables)
2435 break;
2436 if (fContentCurRowY >= fHeightLimit + XFA_LAYOUT_FLOAT_PERCISION &&
2437 XFA_ItemLayoutProcessor_IsTakingSpace(m_pCurChildNode)) {
2438 bForceEndPage = true;
2439 goto SuspendAndCreateNewRow;
2440 }
2441 if (!m_pCurChildNode->IsContainerNode())
2442 break;
2443
2444 bool bNewRow = false;
2445 if (m_pCurChildPreprocessor) {
2446 pProcessor.reset(m_pCurChildPreprocessor);
2447 m_pCurChildPreprocessor = nullptr;
2448 bNewRow = true;
2449 } else {
2450 pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(
2451 m_pCurChildNode, m_pPageMgr);
2452 }
2453
2454 InsertPendingItems(pProcessor.get(), m_pCurChildNode);
2455 XFA_ItemLayoutProcessorResult rs = InsertFlowedItem(
2456 this, pProcessor.get(), bContainerWidthAutoSize,
2457 bContainerHeightAutoSize, containerSize.height, eFlowStrategy,
2458 &uCurHAlignState, rgCurLineLayoutItems, bUseBreakControl,
2459 fAvailHeight, fRealHeight, fContentWidthLimit, &fContentCurRowY,
2460 &fContentCurRowAvailWidth, &fContentCurRowHeight,
2461 &bAddedItemInRow, &bForceEndPage, pContext, bNewRow);
2462 switch (rs) {
2463 case XFA_ItemLayoutProcessorResult::ManualBreak:
2464 bIsManualBreak = true;
2465 case XFA_ItemLayoutProcessorResult::PageFullBreak:
2466 bForceEndPage = true;
2467 case XFA_ItemLayoutProcessorResult::RowFullBreak:
2468 goto SuspendAndCreateNewRow;
2469 case XFA_ItemLayoutProcessorResult::Done:
2470 default:
2471 fContentCurRowY +=
2472 InsertPendingItems(pProcessor.get(), m_pCurChildNode);
2473 pProcessor.reset();
2474 }
2475 break;
2476 }
2477 case XFA_ItemLayoutProcessorStages::Done:
2478 break;
2479 default:
2480 break;
2481 }
2482 GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode,
2483 true);
2484 if (bAddedItemInRow && eFlowStrategy == XFA_ATTRIBUTEENUM_Tb)
2485 break;
2486 else
2487 continue;
2488 SuspendAndCreateNewRow:
2489 if (pProcessor)
2490 m_pCurChildPreprocessor = pProcessor.release();
2491 break;
2492 }
2493
2494 CalculateRowChildPosition(
2495 rgCurLineLayoutItems, eFlowStrategy, bContainerHeightAutoSize,
2496 bContainerWidthAutoSize, &fContentCalculatedWidth,
2497 &fContentCalculatedHeight, &fContentCurRowY, fContentCurRowHeight,
2498 fContentWidthLimit, bRootForceTb);
2499 m_fWidthLimite = fContentCurRowAvailWidth;
2500 if (bForceEndPage)
2501 break;
2502 }
2503
2504 bool bRetValue =
2505 m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::Done &&
2506 m_PendingNodes.empty();
2507 if (bBreakDone)
2508 bRetValue = false;
2509
2510 containerSize = CalculateContainerComponentSizeFromContentSize(
2511 m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
2512 bContainerHeightAutoSize, fContentCalculatedHeight, containerSize);
2513
2514 if (containerSize.height >= XFA_LAYOUT_FLOAT_PERCISION || m_pLayoutItem ||
2515 bRetValue) {
2516 if (!m_pLayoutItem)
2517 m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
2518 containerSize.height = std::max(containerSize.height, 0.f);
2519
2520 SetCurrentComponentSize(containerSize);
2521 if (bForceEndPage)
2522 m_fUsedSize = 0;
2523 else
2524 m_fUsedSize += m_pLayoutItem->m_sSize.height;
2525 }
2526
2527 return bRetValue
2528 ? XFA_ItemLayoutProcessorResult::Done
2529 : (bIsManualBreak ? XFA_ItemLayoutProcessorResult::ManualBreak
2530 : XFA_ItemLayoutProcessorResult::PageFullBreak);
2531 }
2532
CalculateRowChildPosition(CFX_ArrayTemplate<CXFA_ContentLayoutItem * > (& rgCurLineLayoutItems)[3],XFA_ATTRIBUTEENUM eFlowStrategy,bool bContainerHeightAutoSize,bool bContainerWidthAutoSize,FX_FLOAT * fContentCalculatedWidth,FX_FLOAT * fContentCalculatedHeight,FX_FLOAT * fContentCurRowY,FX_FLOAT fContentCurRowHeight,FX_FLOAT fContentWidthLimit,bool bRootForceTb)2533 bool CXFA_ItemLayoutProcessor::CalculateRowChildPosition(
2534 CFX_ArrayTemplate<CXFA_ContentLayoutItem*> (&rgCurLineLayoutItems)[3],
2535 XFA_ATTRIBUTEENUM eFlowStrategy,
2536 bool bContainerHeightAutoSize,
2537 bool bContainerWidthAutoSize,
2538 FX_FLOAT* fContentCalculatedWidth,
2539 FX_FLOAT* fContentCalculatedHeight,
2540 FX_FLOAT* fContentCurRowY,
2541 FX_FLOAT fContentCurRowHeight,
2542 FX_FLOAT fContentWidthLimit,
2543 bool bRootForceTb) {
2544 int32_t nGroupLengths[3] = {0, 0, 0};
2545 FX_FLOAT fGroupWidths[3] = {0, 0, 0};
2546 int32_t nTotalLength = 0;
2547 for (int32_t i = 0; i < 3; i++) {
2548 nGroupLengths[i] = rgCurLineLayoutItems[i].GetSize();
2549 for (int32_t c = nGroupLengths[i], j = 0; j < c; j++) {
2550 nTotalLength++;
2551 if (XFA_ItemLayoutProcessor_IsTakingSpace(
2552 rgCurLineLayoutItems[i][j]->m_pFormNode)) {
2553 fGroupWidths[i] += rgCurLineLayoutItems[i][j]->m_sSize.width;
2554 }
2555 }
2556 }
2557
2558 if (!nTotalLength) {
2559 if (bContainerHeightAutoSize) {
2560 *fContentCalculatedHeight =
2561 std::min(*fContentCalculatedHeight, *fContentCurRowY);
2562 }
2563 return false;
2564 }
2565
2566 if (!m_pLayoutItem)
2567 m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
2568
2569 if (eFlowStrategy != XFA_ATTRIBUTEENUM_Rl_tb) {
2570 FX_FLOAT fCurPos;
2571 fCurPos = 0;
2572 for (int32_t c = nGroupLengths[0], j = 0; j < c; j++) {
2573 if (bRootForceTb) {
2574 rgCurLineLayoutItems[0][j]->m_sPos = CalculatePositionedContainerPos(
2575 rgCurLineLayoutItems[0][j]->m_pFormNode,
2576 rgCurLineLayoutItems[0][j]->m_sSize);
2577 } else {
2578 rgCurLineLayoutItems[0][j]->m_sPos =
2579 CFX_PointF(fCurPos, *fContentCurRowY);
2580 if (XFA_ItemLayoutProcessor_IsTakingSpace(
2581 rgCurLineLayoutItems[0][j]->m_pFormNode)) {
2582 fCurPos += rgCurLineLayoutItems[0][j]->m_sSize.width;
2583 }
2584 }
2585 m_pLayoutItem->AddChild(rgCurLineLayoutItems[0][j]);
2586 m_fLastRowWidth = fCurPos;
2587 }
2588 fCurPos = (fContentWidthLimit + fGroupWidths[0] - fGroupWidths[1] -
2589 fGroupWidths[2]) /
2590 2;
2591 for (int32_t c = nGroupLengths[1], j = 0; j < c; j++) {
2592 if (bRootForceTb) {
2593 rgCurLineLayoutItems[1][j]->m_sPos = CalculatePositionedContainerPos(
2594 rgCurLineLayoutItems[1][j]->m_pFormNode,
2595 rgCurLineLayoutItems[1][j]->m_sSize);
2596 } else {
2597 rgCurLineLayoutItems[1][j]->m_sPos =
2598 CFX_PointF(fCurPos, *fContentCurRowY);
2599 if (XFA_ItemLayoutProcessor_IsTakingSpace(
2600 rgCurLineLayoutItems[1][j]->m_pFormNode)) {
2601 fCurPos += rgCurLineLayoutItems[1][j]->m_sSize.width;
2602 }
2603 }
2604 m_pLayoutItem->AddChild(rgCurLineLayoutItems[1][j]);
2605 m_fLastRowWidth = fCurPos;
2606 }
2607 fCurPos = fContentWidthLimit - fGroupWidths[2];
2608 for (int32_t c = nGroupLengths[2], j = 0; j < c; j++) {
2609 if (bRootForceTb) {
2610 rgCurLineLayoutItems[2][j]->m_sPos = CalculatePositionedContainerPos(
2611 rgCurLineLayoutItems[2][j]->m_pFormNode,
2612 rgCurLineLayoutItems[2][j]->m_sSize);
2613 } else {
2614 rgCurLineLayoutItems[2][j]->m_sPos =
2615 CFX_PointF(fCurPos, *fContentCurRowY);
2616 if (XFA_ItemLayoutProcessor_IsTakingSpace(
2617 rgCurLineLayoutItems[2][j]->m_pFormNode)) {
2618 fCurPos += rgCurLineLayoutItems[2][j]->m_sSize.width;
2619 }
2620 }
2621 m_pLayoutItem->AddChild(rgCurLineLayoutItems[2][j]);
2622 m_fLastRowWidth = fCurPos;
2623 }
2624 } else {
2625 FX_FLOAT fCurPos;
2626 fCurPos = fGroupWidths[0];
2627 for (int32_t c = nGroupLengths[0], j = 0; j < c; j++) {
2628 if (XFA_ItemLayoutProcessor_IsTakingSpace(
2629 rgCurLineLayoutItems[0][j]->m_pFormNode)) {
2630 fCurPos -= rgCurLineLayoutItems[0][j]->m_sSize.width;
2631 }
2632 rgCurLineLayoutItems[0][j]->m_sPos =
2633 CFX_PointF(fCurPos, *fContentCurRowY);
2634 m_pLayoutItem->AddChild(rgCurLineLayoutItems[0][j]);
2635 m_fLastRowWidth = fCurPos;
2636 }
2637 fCurPos = (fContentWidthLimit + fGroupWidths[0] + fGroupWidths[1] -
2638 fGroupWidths[2]) /
2639 2;
2640 for (int32_t c = nGroupLengths[1], j = 0; j < c; j++) {
2641 if (XFA_ItemLayoutProcessor_IsTakingSpace(
2642 rgCurLineLayoutItems[1][j]->m_pFormNode)) {
2643 fCurPos -= rgCurLineLayoutItems[1][j]->m_sSize.width;
2644 }
2645 rgCurLineLayoutItems[1][j]->m_sPos =
2646 CFX_PointF(fCurPos, *fContentCurRowY);
2647 m_pLayoutItem->AddChild(rgCurLineLayoutItems[1][j]);
2648 m_fLastRowWidth = fCurPos;
2649 }
2650 fCurPos = fContentWidthLimit;
2651 for (int32_t c = nGroupLengths[2], j = 0; j < c; j++) {
2652 if (XFA_ItemLayoutProcessor_IsTakingSpace(
2653 rgCurLineLayoutItems[2][j]->m_pFormNode)) {
2654 fCurPos -= rgCurLineLayoutItems[2][j]->m_sSize.width;
2655 }
2656 rgCurLineLayoutItems[2][j]->m_sPos =
2657 CFX_PointF(fCurPos, *fContentCurRowY);
2658 m_pLayoutItem->AddChild(rgCurLineLayoutItems[2][j]);
2659 m_fLastRowWidth = fCurPos;
2660 }
2661 }
2662 m_fLastRowY = *fContentCurRowY;
2663 *fContentCurRowY += fContentCurRowHeight;
2664 if (bContainerWidthAutoSize) {
2665 FX_FLOAT fChildSuppliedWidth = fGroupWidths[0];
2666 if (fContentWidthLimit < FLT_MAX &&
2667 fContentWidthLimit > fChildSuppliedWidth) {
2668 fChildSuppliedWidth = fContentWidthLimit;
2669 }
2670 *fContentCalculatedWidth =
2671 std::max(*fContentCalculatedWidth, fChildSuppliedWidth);
2672 }
2673 if (bContainerHeightAutoSize) {
2674 *fContentCalculatedHeight =
2675 std::max(*fContentCalculatedHeight, *fContentCurRowY);
2676 }
2677 return true;
2678 }
2679
GetSubformSetParent(CXFA_Node * pSubformSet)2680 CXFA_Node* CXFA_ItemLayoutProcessor::GetSubformSetParent(
2681 CXFA_Node* pSubformSet) {
2682 if (pSubformSet && pSubformSet->GetElementType() == XFA_Element::SubformSet) {
2683 CXFA_Node* pParent = pSubformSet->GetNodeItem(XFA_NODEITEM_Parent);
2684 while (pParent) {
2685 if (pParent->GetElementType() != XFA_Element::SubformSet)
2686 return pParent;
2687 pParent = pParent->GetNodeItem(XFA_NODEITEM_Parent);
2688 }
2689 }
2690 return pSubformSet;
2691 }
2692
DoLayoutField()2693 void CXFA_ItemLayoutProcessor::DoLayoutField() {
2694 if (m_pLayoutItem)
2695 return;
2696
2697 ASSERT(m_pCurChildNode == XFA_LAYOUT_INVALIDNODE);
2698 m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
2699 if (!m_pLayoutItem)
2700 return;
2701
2702 CXFA_Document* pDocument = m_pFormNode->GetDocument();
2703 CXFA_FFNotify* pNotify = pDocument->GetNotify();
2704 CFX_SizeF size(-1, -1);
2705 pNotify->StartFieldDrawLayout(m_pFormNode, size.width, size.height);
2706
2707 int32_t nRotate =
2708 FXSYS_round(m_pFormNode->GetMeasure(XFA_ATTRIBUTE_Rotate).GetValue());
2709 nRotate = XFA_MapRotation(nRotate);
2710 if (nRotate == 90 || nRotate == 270)
2711 std::swap(size.width, size.height);
2712
2713 SetCurrentComponentSize(size);
2714 }
2715
DoLayout(bool bUseBreakControl,FX_FLOAT fHeightLimit,FX_FLOAT fRealHeight,CXFA_LayoutContext * pContext)2716 XFA_ItemLayoutProcessorResult CXFA_ItemLayoutProcessor::DoLayout(
2717 bool bUseBreakControl,
2718 FX_FLOAT fHeightLimit,
2719 FX_FLOAT fRealHeight,
2720 CXFA_LayoutContext* pContext) {
2721 switch (m_pFormNode->GetElementType()) {
2722 case XFA_Element::Subform:
2723 case XFA_Element::Area:
2724 case XFA_Element::ExclGroup:
2725 case XFA_Element::SubformSet: {
2726 bool bRootForceTb = false;
2727 CXFA_Node* pLayoutNode = GetSubformSetParent(m_pFormNode);
2728 XFA_ATTRIBUTEENUM eLayoutStrategy = GetLayout(pLayoutNode, &bRootForceTb);
2729 switch (eLayoutStrategy) {
2730 case XFA_ATTRIBUTEENUM_Tb:
2731 case XFA_ATTRIBUTEENUM_Lr_tb:
2732 case XFA_ATTRIBUTEENUM_Rl_tb:
2733 return DoLayoutFlowedContainer(bUseBreakControl, eLayoutStrategy,
2734 fHeightLimit, fRealHeight, pContext,
2735 bRootForceTb);
2736 case XFA_ATTRIBUTEENUM_Position:
2737 case XFA_ATTRIBUTEENUM_Row:
2738 case XFA_ATTRIBUTEENUM_Rl_row:
2739 default:
2740 DoLayoutPositionedContainer(pContext);
2741 m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Done;
2742 return XFA_ItemLayoutProcessorResult::Done;
2743 case XFA_ATTRIBUTEENUM_Table:
2744 DoLayoutTableContainer(pLayoutNode);
2745 m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Done;
2746 return XFA_ItemLayoutProcessorResult::Done;
2747 }
2748 }
2749 case XFA_Element::Draw:
2750 case XFA_Element::Field:
2751 DoLayoutField();
2752 m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Done;
2753 return XFA_ItemLayoutProcessorResult::Done;
2754 case XFA_Element::ContentArea:
2755 return XFA_ItemLayoutProcessorResult::Done;
2756 default:
2757 return XFA_ItemLayoutProcessorResult::Done;
2758 }
2759 }
2760
GetCurrentComponentSize()2761 CFX_SizeF CXFA_ItemLayoutProcessor::GetCurrentComponentSize() {
2762 return CFX_SizeF(m_pLayoutItem->m_sSize.width, m_pLayoutItem->m_sSize.height);
2763 }
2764
SetCurrentComponentPos(const CFX_PointF & pos)2765 void CXFA_ItemLayoutProcessor::SetCurrentComponentPos(const CFX_PointF& pos) {
2766 m_pLayoutItem->m_sPos = pos;
2767 }
2768
SetCurrentComponentSize(const CFX_SizeF & size)2769 void CXFA_ItemLayoutProcessor::SetCurrentComponentSize(const CFX_SizeF& size) {
2770 m_pLayoutItem->m_sSize = size;
2771 }
2772
JudgeLeaderOrTrailerForOccur(CXFA_Node * pFormNode)2773 bool CXFA_ItemLayoutProcessor::JudgeLeaderOrTrailerForOccur(
2774 CXFA_Node* pFormNode) {
2775 if (!pFormNode)
2776 return false;
2777
2778 CXFA_Node* pTemplate = pFormNode->GetTemplateNode();
2779 if (!pTemplate)
2780 pTemplate = pFormNode;
2781
2782 CXFA_Occur NodeOccur(pTemplate->GetFirstChildByClass(XFA_Element::Occur));
2783 int32_t iMax = NodeOccur.GetMax();
2784 if (iMax < 0)
2785 return true;
2786
2787 int32_t iCount = m_PendingNodesCount[pTemplate];
2788 if (iCount >= iMax)
2789 return false;
2790
2791 m_PendingNodesCount[pTemplate] = iCount + 1;
2792 return true;
2793 }
2794