Home | History | Annotate | Download | only in parser
      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 
     35 namespace {
     36 
     37 std::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 
     60 void 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 
     86 CFX_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 
    129 CFX_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 
    172 void 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 
    323 void 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 
    338 void 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 
    420 void 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 
    469 void 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 
    476 float 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 
    506 XFA_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 
    521 bool 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 
    566 bool 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 
    614 void 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 
    636 uint8_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 
    648 XFA_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 
    985 bool 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 
   1069 CFX_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 
   1142 CXFA_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 
   1169 CXFA_ItemLayoutProcessor::~CXFA_ItemLayoutProcessor() {}
   1170 
   1171 CXFA_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 
   1200 float 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 
   1216 void 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 
   1335 void CXFA_ItemLayoutProcessor::SplitLayoutItem(float fSplitPos) {
   1336   ASSERT(m_pLayoutItem);
   1337   SplitLayoutItem(m_pLayoutItem, nullptr, fSplitPos);
   1338 }
   1339 
   1340 CXFA_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 
   1374 void 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 
   1524 bool 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 
   1564 bool 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 
   1582 bool 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 
   1590 bool CXFA_ItemLayoutProcessor::IncrementRelayoutNode(
   1591     CXFA_LayoutProcessor* pLayoutProcessor,
   1592     CXFA_Node* pNode,
   1593     CXFA_Node* pParentNode) {
   1594   return false;
   1595 }
   1596 
   1597 void 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 
   1653 void 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 
   1764 void 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 
   1991 bool 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 
   2002 float 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 
   2022 bool 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 
   2070 bool 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 
   2095 void 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 
   2114 void 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 
   2136 XFA_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 
   2586 bool 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 
   2731 CXFA_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 
   2744 void 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 
   2766 XFA_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 
   2811 CFX_SizeF CXFA_ItemLayoutProcessor::GetCurrentComponentSize() {
   2812   return CFX_SizeF(m_pLayoutItem->m_sSize.width, m_pLayoutItem->m_sSize.height);
   2813 }
   2814 
   2815 void CXFA_ItemLayoutProcessor::SetCurrentComponentPos(const CFX_PointF& pos) {
   2816   m_pLayoutItem->m_sPos = pos;
   2817 }
   2818 
   2819 void CXFA_ItemLayoutProcessor::SetCurrentComponentSize(const CFX_SizeF& size) {
   2820   m_pLayoutItem->m_sSize = size;
   2821 }
   2822 
   2823 bool 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