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