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