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