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