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