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