// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#include "xfa/fxfa/parser/xfa_layout_itemlayout.h"

#include <algorithm>
#include <memory>

#include "xfa/fxfa/app/xfa_ffnotify.h"
#include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
#include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
#include "xfa/fxfa/parser/cxfa_document.h"
#include "xfa/fxfa/parser/cxfa_layoutpagemgr.h"
#include "xfa/fxfa/parser/cxfa_measurement.h"
#include "xfa/fxfa/parser/cxfa_occur.h"
#include "xfa/fxfa/parser/xfa_localemgr.h"
#include "xfa/fxfa/parser/xfa_object.h"
#include "xfa/fxfa/parser/xfa_utils.h"

namespace {

int32_t SeparateStringW(const FX_WCHAR* pStr,
                        int32_t iStrLen,
                        FX_WCHAR delimiter,
                        CFX_WideStringArray& pieces) {
  if (!pStr)
    return 0;
  if (iStrLen < 0)
    iStrLen = FXSYS_wcslen(pStr);

  const FX_WCHAR* pToken = pStr;
  const FX_WCHAR* pEnd = pStr + iStrLen;
  while (true) {
    if (pStr >= pEnd || delimiter == *pStr) {
      CFX_WideString sub(pToken, pStr - pToken);
      pieces.Add(sub);
      pToken = pStr + 1;
      if (pStr >= pEnd)
        break;
    }
    pStr++;
  }
  return pieces.GetSize();
}

}  // namespace

CXFA_ItemLayoutProcessor::CXFA_ItemLayoutProcessor(CXFA_Node* pNode,
                                                   CXFA_LayoutPageMgr* pPageMgr)
    : m_bKeepBreakFinish(false),
      m_bIsProcessKeep(false),
      m_pKeepHeadNode(nullptr),
      m_pKeepTailNode(nullptr),
      m_pFormNode(pNode),
      m_pLayoutItem(nullptr),
      m_pOldLayoutItem(nullptr),
      m_pCurChildNode(XFA_LAYOUT_INVALIDNODE),
      m_pCurChildPreprocessor(nullptr),
      m_nCurChildNodeStage(XFA_ItemLayoutProcessorStages_None),
      m_fUsedSize(0),
      m_pPageMgr(pPageMgr),
      m_bBreakPending(true),
      m_fLastRowWidth(0),
      m_fLastRowY(0),
      m_fWidthLimite(0),
      m_bUseInheriated(false),
      m_ePreProcessRs(XFA_ItemLayoutProcessorResult_Done),
      m_bHasAvailHeight(true) {
  ASSERT(m_pFormNode && (m_pFormNode->IsContainerNode() ||
                         m_pFormNode->GetElementType() == XFA_Element::Form));
  m_pOldLayoutItem =
      (CXFA_ContentLayoutItem*)m_pFormNode->GetUserData(XFA_LAYOUTITEMKEY);
}

CXFA_ItemLayoutProcessor::~CXFA_ItemLayoutProcessor() {}

CXFA_ContentLayoutItem* CXFA_ItemLayoutProcessor::CreateContentLayoutItem(
    CXFA_Node* pFormNode) {
  if (!pFormNode) {
    return nullptr;
  }
  CXFA_ContentLayoutItem* pLayoutItem = nullptr;
  if (m_pOldLayoutItem) {
    pLayoutItem = m_pOldLayoutItem;
    m_pOldLayoutItem = m_pOldLayoutItem->m_pNext;
    return pLayoutItem;
  }
  pLayoutItem = (CXFA_ContentLayoutItem*)pFormNode->GetDocument()
                    ->GetNotify()
                    ->OnCreateLayoutItem(pFormNode);
  CXFA_ContentLayoutItem* pPrevLayoutItem =
      (CXFA_ContentLayoutItem*)pFormNode->GetUserData(XFA_LAYOUTITEMKEY);
  if (pPrevLayoutItem) {
    while (pPrevLayoutItem->m_pNext) {
      pPrevLayoutItem = pPrevLayoutItem->m_pNext;
    }
    pPrevLayoutItem->m_pNext = pLayoutItem;
    pLayoutItem->m_pPrev = pPrevLayoutItem;
  } else {
    pFormNode->SetUserData(XFA_LAYOUTITEMKEY, pLayoutItem);
  }
  return pLayoutItem;
}
bool CXFA_ItemLayoutProcessor::FindLayoutItemSplitPos(
    CXFA_ContentLayoutItem* pLayoutItem,
    FX_FLOAT fCurVerticalOffset,
    FX_FLOAT& fProposedSplitPos,
    bool& bAppChange,
    bool bCalculateMargin) {
  CXFA_Node* pFormNode = pLayoutItem->m_pFormNode;
  if (fProposedSplitPos > fCurVerticalOffset + XFA_LAYOUT_FLOAT_PERCISION &&
      fProposedSplitPos <= fCurVerticalOffset + pLayoutItem->m_sSize.y -
                               XFA_LAYOUT_FLOAT_PERCISION) {
    switch (pFormNode->GetIntact()) {
      case XFA_ATTRIBUTEENUM_None: {
        bool bAnyChanged = false;
        CXFA_Document* pDocument = pFormNode->GetDocument();
        CXFA_FFNotify* pNotify = pDocument->GetNotify();
        FX_FLOAT fCurTopMargin = 0, fCurBottomMargin = 0;
        CXFA_Node* pMarginNode =
            pFormNode->GetFirstChildByClass(XFA_Element::Margin);
        if (pMarginNode && bCalculateMargin) {
          fCurTopMargin = pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset)
                              .ToUnit(XFA_UNIT_Pt);
          fCurBottomMargin = pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset)
                                 .ToUnit(XFA_UNIT_Pt);
        }
        bool bChanged = true;
        while (bChanged) {
          bChanged = false;
          {
            FX_FLOAT fRelSplitPos = fProposedSplitPos - fCurVerticalOffset;
            if (pNotify->FindSplitPos(pFormNode, pLayoutItem->GetIndex(),
                                      fRelSplitPos)) {
              bAnyChanged = true;
              bChanged = true;
              fProposedSplitPos = fCurVerticalOffset + fRelSplitPos;
              bAppChange = true;
              if (fProposedSplitPos <=
                  fCurVerticalOffset + XFA_LAYOUT_FLOAT_PERCISION) {
                return true;
              }
            }
          }
          FX_FLOAT fRelSplitPos = fProposedSplitPos - fCurBottomMargin;
          for (CXFA_ContentLayoutItem* pChildItem =
                   (CXFA_ContentLayoutItem*)pLayoutItem->m_pFirstChild;
               pChildItem;
               pChildItem =
                   (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling) {
            FX_FLOAT fChildOffset =
                fCurVerticalOffset + fCurTopMargin + pChildItem->m_sPos.y;
            bool bChange = false;
            if (FindLayoutItemSplitPos(pChildItem, fChildOffset, fRelSplitPos,
                                       bChange, bCalculateMargin)) {
              if (fRelSplitPos - fChildOffset < XFA_LAYOUT_FLOAT_PERCISION &&
                  bChange) {
                fProposedSplitPos = fRelSplitPos - fCurTopMargin;
              } else {
                fProposedSplitPos = fRelSplitPos + fCurBottomMargin;
              }
              bAnyChanged = true;
              bChanged = true;
              if (fProposedSplitPos <=
                  fCurVerticalOffset + XFA_LAYOUT_FLOAT_PERCISION) {
                return true;
              }
              if (bAnyChanged) {
                break;
              }
            }
          }
        }
        return bAnyChanged;
      } break;
      case XFA_ATTRIBUTEENUM_ContentArea:
      case XFA_ATTRIBUTEENUM_PageArea: {
        fProposedSplitPos = fCurVerticalOffset;
        return true;
      }
      default:
        return false;
    }
  }
  return false;
}
static XFA_ATTRIBUTEENUM XFA_ItemLayoutProcessor_GetLayout(CXFA_Node* pFormNode,
                                                           bool& bRootForceTb) {
  bRootForceTb = false;
  XFA_ATTRIBUTEENUM eLayoutMode;
  if (pFormNode->TryEnum(XFA_ATTRIBUTE_Layout, eLayoutMode, false)) {
    return eLayoutMode;
  }
  CXFA_Node* pParentNode = pFormNode->GetNodeItem(XFA_NODEITEM_Parent);
  if (pParentNode && pParentNode->GetElementType() == XFA_Element::Form) {
    bRootForceTb = true;
    return XFA_ATTRIBUTEENUM_Tb;
  }
  return XFA_ATTRIBUTEENUM_Position;
}
static bool XFA_ExistContainerKeep(CXFA_Node* pCurNode, bool bPreFind) {
  if (!pCurNode || !XFA_ItemLayoutProcessor_IsTakingSpace(pCurNode)) {
    return false;
  }
  XFA_NODEITEM eItemType = XFA_NODEITEM_PrevSibling;
  if (!bPreFind) {
    eItemType = XFA_NODEITEM_NextSibling;
  }
  CXFA_Node* pPreContainer =
      pCurNode->GetNodeItem(eItemType, XFA_ObjectType::ContainerNode);
  if (!pPreContainer) {
    return false;
  }
  CXFA_Node* pKeep = pCurNode->GetFirstChildByClass(XFA_Element::Keep);
  if (pKeep) {
    XFA_ATTRIBUTEENUM ePrevious;
    XFA_ATTRIBUTE eKeepType = XFA_ATTRIBUTE_Previous;
    if (!bPreFind) {
      eKeepType = XFA_ATTRIBUTE_Next;
    }
    if (pKeep->TryEnum(eKeepType, ePrevious, false)) {
      if (ePrevious == XFA_ATTRIBUTEENUM_ContentArea ||
          ePrevious == XFA_ATTRIBUTEENUM_PageArea) {
        return true;
      }
    }
  }
  pKeep = pPreContainer->GetFirstChildByClass(XFA_Element::Keep);
  if (!pKeep) {
    return false;
  }
  XFA_ATTRIBUTEENUM eNext;
  XFA_ATTRIBUTE eKeepType = XFA_ATTRIBUTE_Next;
  if (!bPreFind) {
    eKeepType = XFA_ATTRIBUTE_Previous;
  }
  if (!pKeep->TryEnum(eKeepType, eNext, false)) {
    return false;
  }
  if (eNext == XFA_ATTRIBUTEENUM_ContentArea ||
      eNext == XFA_ATTRIBUTEENUM_PageArea) {
    return true;
  }
  return false;
}
FX_FLOAT CXFA_ItemLayoutProcessor::FindSplitPos(FX_FLOAT fProposedSplitPos) {
  ASSERT(m_pLayoutItem);
  XFA_ATTRIBUTEENUM eLayout = m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
  bool bCalculateMargin = true;
  if (eLayout == XFA_ATTRIBUTEENUM_Position) {
    bCalculateMargin = false;
  }
  while (fProposedSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
    bool bAppChange = false;
    if (!FindLayoutItemSplitPos(m_pLayoutItem, 0, fProposedSplitPos, bAppChange,
                                bCalculateMargin)) {
      break;
    }
  }
  return fProposedSplitPos;
}
void CXFA_ItemLayoutProcessor::SplitLayoutItem(
    CXFA_ContentLayoutItem* pLayoutItem,
    CXFA_ContentLayoutItem* pSecondParent,
    FX_FLOAT fSplitPos) {
  FX_FLOAT fCurTopMargin = 0, fCurBottomMargin = 0;
  XFA_ATTRIBUTEENUM eLayout = m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
  bool bCalculateMargin = true;
  if (eLayout == XFA_ATTRIBUTEENUM_Position) {
    bCalculateMargin = false;
  }
  CXFA_Node* pMarginNode =
      pLayoutItem->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
  if (pMarginNode && bCalculateMargin) {
    fCurTopMargin =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
    fCurBottomMargin =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset).ToUnit(XFA_UNIT_Pt);
  }
  CXFA_ContentLayoutItem* pSecondLayoutItem = nullptr;
  if (m_pCurChildPreprocessor &&
      m_pCurChildPreprocessor->m_pFormNode == pLayoutItem->m_pFormNode) {
    pSecondLayoutItem = m_pCurChildPreprocessor->CreateContentLayoutItem(
        pLayoutItem->m_pFormNode);
  } else {
    pSecondLayoutItem = CreateContentLayoutItem(pLayoutItem->m_pFormNode);
  }
  pSecondLayoutItem->m_sPos.x = pLayoutItem->m_sPos.x;
  pSecondLayoutItem->m_sSize.x = pLayoutItem->m_sSize.x;
  pSecondLayoutItem->m_sPos.y = 0;
  pSecondLayoutItem->m_sSize.y = pLayoutItem->m_sSize.y - fSplitPos;
  pLayoutItem->m_sSize.y -= pSecondLayoutItem->m_sSize.y;
  if (pLayoutItem->m_pFirstChild) {
    pSecondLayoutItem->m_sSize.y += fCurTopMargin;
  }
  if (pSecondParent) {
    pSecondParent->AddChild(pSecondLayoutItem);
    if (fCurTopMargin > 0 && pLayoutItem->m_pFirstChild) {
      pSecondParent->m_sSize.y += fCurTopMargin;
      CXFA_ContentLayoutItem* pParentItem =
          (CXFA_ContentLayoutItem*)pSecondParent->m_pParent;
      while (pParentItem) {
        pParentItem->m_sSize.y += fCurTopMargin;
        pParentItem = (CXFA_ContentLayoutItem*)pParentItem->m_pParent;
      }
    }
  } else {
    pSecondLayoutItem->m_pParent = pLayoutItem->m_pParent;
    pSecondLayoutItem->m_pNextSibling = pLayoutItem->m_pNextSibling;
    pLayoutItem->m_pNextSibling = pSecondLayoutItem;
  }
  CXFA_ContentLayoutItem* pChildren =
      (CXFA_ContentLayoutItem*)pLayoutItem->m_pFirstChild;
  pLayoutItem->m_pFirstChild = nullptr;
  FX_FLOAT lHeightForKeep = 0;
  CFX_ArrayTemplate<CXFA_ContentLayoutItem*> keepLayoutItems;
  FX_FLOAT fAddMarginHeight = 0;
  for (CXFA_ContentLayoutItem *pChildItem = pChildren, *pChildNext = nullptr;
       pChildItem; pChildItem = pChildNext) {
    pChildNext = (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling;
    pChildItem->m_pNextSibling = nullptr;
    if (fSplitPos <= fCurTopMargin + pChildItem->m_sPos.y + fCurBottomMargin +
                         XFA_LAYOUT_FLOAT_PERCISION) {
      if (!XFA_ExistContainerKeep(pChildItem->m_pFormNode, true)) {
        pChildItem->m_sPos.y -= fSplitPos - fCurBottomMargin;
        pChildItem->m_sPos.y += lHeightForKeep;
        pChildItem->m_sPos.y += fAddMarginHeight;
        pSecondLayoutItem->AddChild(pChildItem);
      } else {
        if (lHeightForKeep < XFA_LAYOUT_FLOAT_PERCISION) {
          for (int32_t iIndex = 0; iIndex < keepLayoutItems.GetSize();
               iIndex++) {
            CXFA_ContentLayoutItem* pPreItem = keepLayoutItems[iIndex];
            pLayoutItem->RemoveChild(pPreItem);
            pPreItem->m_sPos.y -= fSplitPos;
            if (pPreItem->m_sPos.y < 0) {
              pPreItem->m_sPos.y = 0;
            }
            if (pPreItem->m_sPos.y + pPreItem->m_sSize.y > lHeightForKeep) {
              pPreItem->m_sPos.y = lHeightForKeep;
              lHeightForKeep += pPreItem->m_sSize.y;
              pSecondLayoutItem->m_sSize.y += pPreItem->m_sSize.y;
              if (pSecondParent) {
                pSecondParent->m_sSize.y += pPreItem->m_sSize.y;
              }
            }
            pSecondLayoutItem->AddChild(pPreItem);
          }
        }
        pChildItem->m_sPos.y -= fSplitPos;
        pChildItem->m_sPos.y += lHeightForKeep;
        pChildItem->m_sPos.y += fAddMarginHeight;
        pSecondLayoutItem->AddChild(pChildItem);
      }
    } else if (fSplitPos + XFA_LAYOUT_FLOAT_PERCISION >=
               fCurTopMargin + fCurBottomMargin + pChildItem->m_sPos.y +
                   pChildItem->m_sSize.y) {
      pLayoutItem->AddChild(pChildItem);
      if (XFA_ExistContainerKeep(pChildItem->m_pFormNode, false)) {
        keepLayoutItems.Add(pChildItem);
      } else {
        keepLayoutItems.RemoveAll();
      }
    } else {
      FX_FLOAT fOldHeight = pSecondLayoutItem->m_sSize.y;
      SplitLayoutItem(
          pChildItem, pSecondLayoutItem,
          fSplitPos - fCurTopMargin - fCurBottomMargin - pChildItem->m_sPos.y);
      fAddMarginHeight = pSecondLayoutItem->m_sSize.y - fOldHeight;
      pLayoutItem->AddChild(pChildItem);
    }
  }
}
void CXFA_ItemLayoutProcessor::SplitLayoutItem(FX_FLOAT fSplitPos) {
  ASSERT(m_pLayoutItem);
  SplitLayoutItem(m_pLayoutItem, nullptr, fSplitPos);
}

CXFA_ContainerLayoutItem* CXFA_LayoutItem::GetPage() const {
  for (CXFA_LayoutItem* pCurNode = const_cast<CXFA_LayoutItem*>(this); pCurNode;
       pCurNode = pCurNode->m_pParent) {
    if (pCurNode->m_pFormNode->GetElementType() == XFA_Element::PageArea)
      return static_cast<CXFA_ContainerLayoutItem*>(pCurNode);
  }
  return nullptr;
}

CXFA_Node* CXFA_LayoutItem::GetFormNode() const {
  return m_pFormNode;
}

void CXFA_LayoutItem::GetRect(CFX_RectF& rtLayout, bool bRelative) const {
  ASSERT(m_bIsContentLayoutItem);
  const CXFA_ContentLayoutItem* pThis =
      static_cast<const CXFA_ContentLayoutItem*>(this);
  CFX_PointF sPos = pThis->m_sPos;
  CFX_SizeF sSize = pThis->m_sSize;
  if (!bRelative) {
    for (CXFA_LayoutItem* pLayoutItem = pThis->m_pParent; pLayoutItem;
         pLayoutItem = pLayoutItem->m_pParent) {
      if (CXFA_ContentLayoutItem* pContent =
              pLayoutItem->AsContentLayoutItem()) {
        sPos += pContent->m_sPos;
        if (CXFA_Node* pMarginNode =
                pLayoutItem->m_pFormNode->GetFirstChildByClass(
                    XFA_Element::Margin)) {
          sPos += CFX_PointF(pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset)
                                 .ToUnit(XFA_UNIT_Pt),
                             pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset)
                                 .ToUnit(XFA_UNIT_Pt));
        }
      } else {
        if (pLayoutItem->m_pFormNode->GetElementType() ==
            XFA_Element::ContentArea) {
          sPos +=
              CFX_PointF(pLayoutItem->m_pFormNode->GetMeasure(XFA_ATTRIBUTE_X)
                             .ToUnit(XFA_UNIT_Pt),
                         pLayoutItem->m_pFormNode->GetMeasure(XFA_ATTRIBUTE_Y)
                             .ToUnit(XFA_UNIT_Pt));
          break;
        } else if (pLayoutItem->m_pFormNode->GetElementType() ==
                   XFA_Element::PageArea) {
          break;
        }
      }
    }
  }
  rtLayout.Set(sPos.x, sPos.y, sSize.x, sSize.y);
}

CXFA_LayoutItem* CXFA_LayoutItem::GetParent() const {
  return m_pParent;
}

const CXFA_LayoutItem* CXFA_LayoutItem::GetFirst() const {
  ASSERT(m_bIsContentLayoutItem);
  const CXFA_ContentLayoutItem* pCurNode =
      static_cast<const CXFA_ContentLayoutItem*>(this);
  while (pCurNode->m_pPrev) {
    pCurNode = pCurNode->m_pPrev;
  }
  return pCurNode;
}

CXFA_LayoutItem* CXFA_LayoutItem::GetFirst() {
  ASSERT(m_bIsContentLayoutItem);
  CXFA_ContentLayoutItem* pCurNode = static_cast<CXFA_ContentLayoutItem*>(this);
  while (pCurNode->m_pPrev) {
    pCurNode = pCurNode->m_pPrev;
  }
  return pCurNode;
}

CXFA_LayoutItem* CXFA_LayoutItem::GetLast() {
  ASSERT(m_bIsContentLayoutItem);
  CXFA_ContentLayoutItem* pCurNode = static_cast<CXFA_ContentLayoutItem*>(this);
  while (pCurNode->m_pNext) {
    pCurNode = pCurNode->m_pNext;
  }
  return pCurNode;
}

const CXFA_LayoutItem* CXFA_LayoutItem::GetLast() const {
  ASSERT(m_bIsContentLayoutItem);
  const CXFA_ContentLayoutItem* pCurNode =
      static_cast<const CXFA_ContentLayoutItem*>(this);
  while (pCurNode->m_pNext) {
    pCurNode = pCurNode->m_pNext;
  }
  return pCurNode;
}

CXFA_LayoutItem* CXFA_LayoutItem::GetPrev() const {
  ASSERT(m_bIsContentLayoutItem);
  return static_cast<const CXFA_ContentLayoutItem*>(this)->m_pPrev;
}

CXFA_LayoutItem* CXFA_LayoutItem::GetNext() const {
  ASSERT(m_bIsContentLayoutItem);
  return static_cast<const CXFA_ContentLayoutItem*>(this)->m_pNext;
}

int32_t CXFA_LayoutItem::GetIndex() const {
  ASSERT(m_bIsContentLayoutItem);
  int32_t iIndex = 0;
  const CXFA_ContentLayoutItem* pCurNode =
      static_cast<const CXFA_ContentLayoutItem*>(this);
  while (pCurNode->m_pPrev) {
    pCurNode = pCurNode->m_pPrev;
    ++iIndex;
  }
  return iIndex;
}

int32_t CXFA_LayoutItem::GetCount() const {
  ASSERT(m_bIsContentLayoutItem);
  int32_t iCount = GetIndex() + 1;
  const CXFA_ContentLayoutItem* pCurNode =
      static_cast<const CXFA_ContentLayoutItem*>(this);
  while (pCurNode->m_pNext) {
    pCurNode = pCurNode->m_pNext;
    iCount++;
  }
  return iCount;
}

void CXFA_LayoutItem::AddChild(CXFA_LayoutItem* pChildItem) {
  if (pChildItem->m_pParent) {
    pChildItem->m_pParent->RemoveChild(pChildItem);
  }
  pChildItem->m_pParent = this;
  if (!m_pFirstChild) {
    m_pFirstChild = pChildItem;
  } else {
    CXFA_LayoutItem* pExistingChildItem = m_pFirstChild;
    while (pExistingChildItem->m_pNextSibling) {
      pExistingChildItem = pExistingChildItem->m_pNextSibling;
    }
    pExistingChildItem->m_pNextSibling = pChildItem;
  }
}
void CXFA_LayoutItem::AddHeadChild(CXFA_LayoutItem* pChildItem) {
  if (pChildItem->m_pParent) {
    pChildItem->m_pParent->RemoveChild(pChildItem);
  }
  pChildItem->m_pParent = this;
  if (!m_pFirstChild) {
    m_pFirstChild = pChildItem;
  } else {
    CXFA_LayoutItem* pExistingChildItem = m_pFirstChild;
    m_pFirstChild = pChildItem;
    m_pFirstChild->m_pNextSibling = pExistingChildItem;
  }
}
void CXFA_LayoutItem::InsertChild(CXFA_LayoutItem* pBeforeItem,
                                  CXFA_LayoutItem* pChildItem) {
  if (pBeforeItem->m_pParent != this) {
    return;
  }
  if (pChildItem->m_pParent) {
    pChildItem->m_pParent = nullptr;
  }
  pChildItem->m_pParent = this;
  CXFA_LayoutItem* pExistingChildItem = pBeforeItem->m_pNextSibling;
  pBeforeItem->m_pNextSibling = pChildItem;
  pChildItem->m_pNextSibling = pExistingChildItem;
}
void CXFA_LayoutItem::RemoveChild(CXFA_LayoutItem* pChildItem) {
  if (pChildItem->m_pParent != this) {
    return;
  }
  if (m_pFirstChild == pChildItem) {
    m_pFirstChild = pChildItem->m_pNextSibling;
  } else {
    CXFA_LayoutItem* pExistingChildItem = m_pFirstChild;
    while (pExistingChildItem &&
           pExistingChildItem->m_pNextSibling != pChildItem) {
      pExistingChildItem = pExistingChildItem->m_pNextSibling;
    }
    if (pExistingChildItem) {
      pExistingChildItem->m_pNextSibling = pChildItem->m_pNextSibling;
    }
  }
  pChildItem->m_pNextSibling = nullptr;
  pChildItem->m_pParent = nullptr;
}
CXFA_ContentLayoutItem* CXFA_ItemLayoutProcessor::ExtractLayoutItem() {
  CXFA_ContentLayoutItem* pLayoutItem = m_pLayoutItem;
  if (pLayoutItem) {
    m_pLayoutItem =
        static_cast<CXFA_ContentLayoutItem*>(pLayoutItem->m_pNextSibling);
    pLayoutItem->m_pNextSibling = nullptr;
  }
  if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages_Done ||
      !ToContentLayoutItem(m_pOldLayoutItem))
    return pLayoutItem;
  if (m_pOldLayoutItem->m_pPrev)
    m_pOldLayoutItem->m_pPrev->m_pNext = nullptr;
  CXFA_FFNotify* pNotify =
      m_pOldLayoutItem->m_pFormNode->GetDocument()->GetNotify();
  CXFA_LayoutProcessor* pDocLayout =
      m_pOldLayoutItem->m_pFormNode->GetDocument()->GetDocLayout();
  CXFA_ContentLayoutItem* pOldLayoutItem = m_pOldLayoutItem;
  while (pOldLayoutItem) {
    CXFA_ContentLayoutItem* pNextOldLayoutItem = pOldLayoutItem->m_pNext;
    pNotify->OnLayoutItemRemoving(pDocLayout, pOldLayoutItem);
    if (pOldLayoutItem->m_pParent)
      pOldLayoutItem->m_pParent->RemoveChild(pOldLayoutItem);
    delete pOldLayoutItem;
    pOldLayoutItem = pNextOldLayoutItem;
  }
  m_pOldLayoutItem = nullptr;
  return pLayoutItem;
}
static bool XFA_ItemLayoutProcessor_FindBreakNode(
    CXFA_Node* pContainerNode,
    CXFA_Node*& pCurActionNode,
    XFA_ItemLayoutProcessorStages& nCurStage,
    bool bBreakBefore) {
  bool bFindRs = false;
  for (CXFA_Node* pBreakNode = pContainerNode; pBreakNode;
       pBreakNode = pBreakNode->GetNodeItem(XFA_NODEITEM_NextSibling)) {
    XFA_ATTRIBUTE eAttributeType = XFA_ATTRIBUTE_Before;
    if (!bBreakBefore) {
      eAttributeType = XFA_ATTRIBUTE_After;
    }
    switch (pBreakNode->GetElementType()) {
      case XFA_Element::BreakBefore: {
        if (bBreakBefore) {
          pCurActionNode = pBreakNode;
          nCurStage = XFA_ItemLayoutProcessorStages_BreakBefore;
          bFindRs = true;
        }
      } break;
      case XFA_Element::BreakAfter: {
        if (!bBreakBefore) {
          pCurActionNode = pBreakNode;
          nCurStage = XFA_ItemLayoutProcessorStages_BreakAfter;
          bFindRs = true;
        }
      } break;
      case XFA_Element::Break:
        if (pBreakNode->GetEnum(eAttributeType) != XFA_ATTRIBUTEENUM_Auto) {
          pCurActionNode = pBreakNode;
          nCurStage = XFA_ItemLayoutProcessorStages_BreakBefore;
          if (!bBreakBefore) {
            nCurStage = XFA_ItemLayoutProcessorStages_BreakAfter;
          }
          bFindRs = true;
          break;
        }
      default:
        break;
    }
    if (bFindRs) {
      break;
    }
  }
  return bFindRs;
}
static void XFA_DeleteLayoutGeneratedNode(CXFA_Node* pGenerateNode) {
  CXFA_FFNotify* pNotify = pGenerateNode->GetDocument()->GetNotify();
  CXFA_LayoutProcessor* pDocLayout =
      pGenerateNode->GetDocument()->GetDocLayout();
  CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
      pGenerateNode);
  for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
       pNode = sIterator.MoveToNext()) {
    CXFA_ContentLayoutItem* pCurLayoutItem =
        (CXFA_ContentLayoutItem*)pNode->GetUserData(XFA_LAYOUTITEMKEY);
    CXFA_ContentLayoutItem* pNextLayoutItem = nullptr;
    while (pCurLayoutItem) {
      pNextLayoutItem = pCurLayoutItem->m_pNext;
      pNotify->OnLayoutItemRemoving(pDocLayout, pCurLayoutItem);
      delete pCurLayoutItem;
      pCurLayoutItem = pNextLayoutItem;
    }
  }
  pGenerateNode->GetNodeItem(XFA_NODEITEM_Parent)->RemoveChild(pGenerateNode);
}
void CXFA_ItemLayoutProcessor::XFA_ItemLayoutProcessor_GotoNextContainerNode(
    CXFA_Node*& pCurActionNode,
    XFA_ItemLayoutProcessorStages& nCurStage,
    CXFA_Node* pParentContainer,
    bool bUsePageBreak) {
  CXFA_Node* pEntireContainer = pParentContainer;
  CXFA_Node* pChildContainer = XFA_LAYOUT_INVALIDNODE;
  switch (nCurStage) {
    case XFA_ItemLayoutProcessorStages_BreakBefore:
    case XFA_ItemLayoutProcessorStages_BreakAfter: {
      pChildContainer = pCurActionNode->GetNodeItem(XFA_NODEITEM_Parent);
    } break;
    case XFA_ItemLayoutProcessorStages_Keep:
    case XFA_ItemLayoutProcessorStages_Container:
      pChildContainer = pCurActionNode;
      break;
    default:
      pChildContainer = XFA_LAYOUT_INVALIDNODE;
      break;
  }
  switch (nCurStage) {
    case XFA_ItemLayoutProcessorStages_Keep: {
      CXFA_Node* pBreakAfterNode =
          pChildContainer->GetNodeItem(XFA_NODEITEM_FirstChild);
      if (!m_bKeepBreakFinish &&
          XFA_ItemLayoutProcessor_FindBreakNode(pBreakAfterNode, pCurActionNode,
                                                nCurStage, false)) {
        return;
      }
      goto CheckNextChildContainer;
    }
    case XFA_ItemLayoutProcessorStages_None: {
      pCurActionNode = XFA_LAYOUT_INVALIDNODE;
      case XFA_ItemLayoutProcessorStages_BookendLeader:
        for (CXFA_Node* pBookendNode =
                 pCurActionNode == XFA_LAYOUT_INVALIDNODE
                     ? pEntireContainer->GetNodeItem(XFA_NODEITEM_FirstChild)
                     : pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling);
             pBookendNode; pBookendNode = pBookendNode->GetNodeItem(
                               XFA_NODEITEM_NextSibling)) {
          switch (pBookendNode->GetElementType()) {
            case XFA_Element::Bookend:
            case XFA_Element::Break:
              pCurActionNode = pBookendNode;
              nCurStage = XFA_ItemLayoutProcessorStages_BookendLeader;
              return;
            default:
              break;
          }
        }
    }
      {
        pCurActionNode = XFA_LAYOUT_INVALIDNODE;
        case XFA_ItemLayoutProcessorStages_BreakBefore:
          if (pCurActionNode != XFA_LAYOUT_INVALIDNODE) {
            CXFA_Node* pBreakBeforeNode =
                pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling);
            if (!m_bKeepBreakFinish &&
                XFA_ItemLayoutProcessor_FindBreakNode(
                    pBreakBeforeNode, pCurActionNode, nCurStage, true)) {
              return;
            }
            if (m_bIsProcessKeep) {
              if (ProcessKeepNodesForBreakBefore(pCurActionNode, nCurStage,
                                                 pChildContainer)) {
                return;
              }
              goto CheckNextChildContainer;
            }
            pCurActionNode = pChildContainer;
            nCurStage = XFA_ItemLayoutProcessorStages_Container;
            return;
          }
          goto CheckNextChildContainer;
      }
    case XFA_ItemLayoutProcessorStages_Container: {
      pCurActionNode = XFA_LAYOUT_INVALIDNODE;
      case XFA_ItemLayoutProcessorStages_BreakAfter: {
        if (pCurActionNode == XFA_LAYOUT_INVALIDNODE) {
          CXFA_Node* pBreakAfterNode =
              pChildContainer->GetNodeItem(XFA_NODEITEM_FirstChild);
          if (!m_bKeepBreakFinish &&
              XFA_ItemLayoutProcessor_FindBreakNode(
                  pBreakAfterNode, pCurActionNode, nCurStage, false)) {
            return;
          }
        } else {
          CXFA_Node* pBreakAfterNode =
              pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling);
          if (XFA_ItemLayoutProcessor_FindBreakNode(
                  pBreakAfterNode, pCurActionNode, nCurStage, false)) {
            return;
          }
        }
        goto CheckNextChildContainer;
      }
    }
    CheckNextChildContainer : {
      CXFA_Node* pNextChildContainer =
          pChildContainer == XFA_LAYOUT_INVALIDNODE
              ? pEntireContainer->GetNodeItem(XFA_NODEITEM_FirstChild,
                                              XFA_ObjectType::ContainerNode)
              : pChildContainer->GetNodeItem(XFA_NODEITEM_NextSibling,
                                             XFA_ObjectType::ContainerNode);
      while (pNextChildContainer &&
             pNextChildContainer->IsLayoutGeneratedNode()) {
        CXFA_Node* pSaveNode = pNextChildContainer;
        pNextChildContainer = pNextChildContainer->GetNodeItem(
            XFA_NODEITEM_NextSibling, XFA_ObjectType::ContainerNode);
        if (pSaveNode->IsUnusedNode())
          XFA_DeleteLayoutGeneratedNode(pSaveNode);
      }
      if (!pNextChildContainer) {
        goto NoMoreChildContainer;
      }
      bool bLastKeep = false;
      if (ProcessKeepNodesForCheckNext(pCurActionNode, nCurStage,
                                       pNextChildContainer, bLastKeep)) {
        return;
      }
      if (!m_bKeepBreakFinish && !bLastKeep &&
          XFA_ItemLayoutProcessor_FindBreakNode(
              pNextChildContainer->GetNodeItem(XFA_NODEITEM_FirstChild),
              pCurActionNode, nCurStage, true)) {
        return;
      }
      pCurActionNode = pNextChildContainer;
      if (m_bIsProcessKeep) {
        nCurStage = XFA_ItemLayoutProcessorStages_Keep;
      } else {
        nCurStage = XFA_ItemLayoutProcessorStages_Container;
      }
      return;
    }
    NoMoreChildContainer : {
      pCurActionNode = XFA_LAYOUT_INVALIDNODE;
      case XFA_ItemLayoutProcessorStages_BookendTrailer:
        for (CXFA_Node* pBookendNode =
                 pCurActionNode == XFA_LAYOUT_INVALIDNODE
                     ? pEntireContainer->GetNodeItem(XFA_NODEITEM_FirstChild)
                     : pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling);
             pBookendNode; pBookendNode = pBookendNode->GetNodeItem(
                               XFA_NODEITEM_NextSibling)) {
          switch (pBookendNode->GetElementType()) {
            case XFA_Element::Bookend:
            case XFA_Element::Break:
              pCurActionNode = pBookendNode;
              nCurStage = XFA_ItemLayoutProcessorStages_BookendTrailer;
              return;
            default:
              break;
          }
        }
    }
    default:
      pCurActionNode = nullptr;
      nCurStage = XFA_ItemLayoutProcessorStages_Done;
  }
}
bool CXFA_ItemLayoutProcessor::ProcessKeepNodesForCheckNext(
    CXFA_Node*& pCurActionNode,
    XFA_ItemLayoutProcessorStages& nCurStage,
    CXFA_Node*& pNextContainer,
    bool& bLastKeepNode) {
  const bool bCanSplit = pNextContainer->GetIntact() == XFA_ATTRIBUTEENUM_None;
  bool bNextKeep = false;
  if (XFA_ExistContainerKeep(pNextContainer, false)) {
    bNextKeep = true;
  }
  if (bNextKeep && !bCanSplit) {
    if (!m_bIsProcessKeep && !m_bKeepBreakFinish) {
      m_pKeepHeadNode = pNextContainer;
      m_bIsProcessKeep = true;
    }
  } else {
    if (m_bIsProcessKeep && m_pKeepHeadNode) {
      m_pKeepTailNode = pNextContainer;
      if (!m_bKeepBreakFinish &&
          XFA_ItemLayoutProcessor_FindBreakNode(
              pNextContainer->GetNodeItem(XFA_NODEITEM_FirstChild),
              pCurActionNode, nCurStage, true)) {
        return true;
      } else {
        pNextContainer = m_pKeepHeadNode;
        m_bKeepBreakFinish = true;
        m_pKeepHeadNode = nullptr;
        m_pKeepTailNode = nullptr;
        m_bIsProcessKeep = false;
      }
    } else {
      if (m_bKeepBreakFinish) {
        bLastKeepNode = true;
      }
      m_bKeepBreakFinish = false;
    }
  }
  return false;
}
bool CXFA_ItemLayoutProcessor::ProcessKeepNodesForBreakBefore(
    CXFA_Node*& pCurActionNode,
    XFA_ItemLayoutProcessorStages& nCurStage,
    CXFA_Node* pContainerNode) {
  if (m_pKeepTailNode == pContainerNode) {
    pCurActionNode = m_pKeepHeadNode;
    m_bKeepBreakFinish = true;
    m_pKeepHeadNode = nullptr;
    m_pKeepTailNode = nullptr;
    m_bIsProcessKeep = false;
    nCurStage = XFA_ItemLayoutProcessorStages_Container;
    return true;
  }
  CXFA_Node* pBreakAfterNode =
      pContainerNode->GetNodeItem(XFA_NODEITEM_FirstChild);
  if (XFA_ItemLayoutProcessor_FindBreakNode(pBreakAfterNode, pCurActionNode,
                                            nCurStage, false)) {
    return true;
  }
  return false;
}
bool XFA_ItemLayoutProcessor_IsTakingSpace(CXFA_Node* pNode) {
  XFA_ATTRIBUTEENUM ePresence = pNode->GetEnum(XFA_ATTRIBUTE_Presence);
  return ePresence == XFA_ATTRIBUTEENUM_Visible ||
         ePresence == XFA_ATTRIBUTEENUM_Invisible;
}
static inline void XFA_ItemLayoutProcessor_CalculateContainerSpecfiedSize(
    CXFA_Node* pFormNode,
    FX_FLOAT& fContainerWidth,
    FX_FLOAT& fContainerHeight,
    bool& bContainerWidthAutoSize,
    bool& bContainerHeightAutoSize) {
  fContainerWidth = 0;
  fContainerHeight = 0;
  bContainerWidthAutoSize = true;
  bContainerHeightAutoSize = true;
  XFA_Element eType = pFormNode->GetElementType();
  CXFA_Measurement mTmpValue;
  if (bContainerWidthAutoSize &&
      (eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup) &&
      pFormNode->TryMeasure(XFA_ATTRIBUTE_W, mTmpValue, false) &&
      mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
    fContainerWidth = mTmpValue.ToUnit(XFA_UNIT_Pt);
    bContainerWidthAutoSize = false;
  }
  if (bContainerHeightAutoSize &&
      (eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup) &&
      pFormNode->TryMeasure(XFA_ATTRIBUTE_H, mTmpValue, false) &&
      mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
    fContainerHeight = mTmpValue.ToUnit(XFA_UNIT_Pt);
    bContainerHeightAutoSize = false;
  }
  if (bContainerWidthAutoSize && eType == XFA_Element::Subform &&
      pFormNode->TryMeasure(XFA_ATTRIBUTE_MaxW, mTmpValue, false) &&
      mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
    fContainerWidth = mTmpValue.ToUnit(XFA_UNIT_Pt);
    bContainerWidthAutoSize = false;
  }
  if (bContainerHeightAutoSize && eType == XFA_Element::Subform &&
      pFormNode->TryMeasure(XFA_ATTRIBUTE_MaxH, mTmpValue, false) &&
      mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) {
    fContainerHeight = mTmpValue.ToUnit(XFA_UNIT_Pt);
    bContainerHeightAutoSize = false;
  }
}
static inline void
XFA_ItemLayoutProcessor_CalculateContainerComponentSizeFromContentSize(
    CXFA_Node* pFormNode,
    bool bContainerWidthAutoSize,
    FX_FLOAT fContentCalculatedWidth,
    FX_FLOAT& fContainerWidth,
    bool bContainerHeightAutoSize,
    FX_FLOAT fContentCalculatedHeight,
    FX_FLOAT& fContainerHeight) {
  CXFA_Node* pMarginNode = pFormNode->GetFirstChildByClass(XFA_Element::Margin);
  CXFA_Measurement mTmpValue;
  if (bContainerWidthAutoSize) {
    fContainerWidth = fContentCalculatedWidth;
    if (pMarginNode) {
      if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_LeftInset, mTmpValue, false)) {
        fContainerWidth += mTmpValue.ToUnit(XFA_UNIT_Pt);
      }
      if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_RightInset, mTmpValue, false)) {
        fContainerWidth += mTmpValue.ToUnit(XFA_UNIT_Pt);
      }
    }
  }
  if (bContainerHeightAutoSize) {
    fContainerHeight = fContentCalculatedHeight;
    if (pMarginNode) {
      if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_TopInset, mTmpValue, false)) {
        fContainerHeight += mTmpValue.ToUnit(XFA_UNIT_Pt);
      }
      if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_BottomInset, mTmpValue,
                                  false)) {
        fContainerHeight += mTmpValue.ToUnit(XFA_UNIT_Pt);
      }
    }
  }
}
void CXFA_ItemLayoutProcessor::CalculatePositionedContainerPos(
    CXFA_Node* pNode,
    FX_FLOAT fWidth,
    FX_FLOAT fHeight,
    FX_FLOAT& fAbsoluteX,
    FX_FLOAT& fAbsoluteY) {
  XFA_ATTRIBUTEENUM eAnchorType = pNode->GetEnum(XFA_ATTRIBUTE_AnchorType);
  int32_t nAnchorType = 0;
  switch (eAnchorType) {
    case XFA_ATTRIBUTEENUM_TopLeft:
      nAnchorType = 0;
      break;
    case XFA_ATTRIBUTEENUM_TopCenter:
      nAnchorType = 1;
      break;
    case XFA_ATTRIBUTEENUM_TopRight:
      nAnchorType = 2;
      break;
    case XFA_ATTRIBUTEENUM_MiddleLeft:
      nAnchorType = 3;
      break;
    case XFA_ATTRIBUTEENUM_MiddleCenter:
      nAnchorType = 4;
      break;
    case XFA_ATTRIBUTEENUM_MiddleRight:
      nAnchorType = 5;
      break;
    case XFA_ATTRIBUTEENUM_BottomLeft:
      nAnchorType = 6;
      break;
    case XFA_ATTRIBUTEENUM_BottomCenter:
      nAnchorType = 7;
      break;
    case XFA_ATTRIBUTEENUM_BottomRight:
      nAnchorType = 8;
      break;
    default:
      break;
  }
  static const uint8_t nNextPos[4][9] = {{0, 1, 2, 3, 4, 5, 6, 7, 8},
                                         {6, 3, 0, 7, 4, 1, 8, 5, 2},
                                         {8, 7, 6, 5, 4, 3, 2, 1, 0},
                                         {2, 5, 8, 1, 4, 7, 0, 3, 6}};

  FX_FLOAT fAnchorX = pNode->GetMeasure(XFA_ATTRIBUTE_X).ToUnit(XFA_UNIT_Pt);
  FX_FLOAT fAnchorY = pNode->GetMeasure(XFA_ATTRIBUTE_Y).ToUnit(XFA_UNIT_Pt);
  int32_t nRotate =
      FXSYS_round(pNode->GetMeasure(XFA_ATTRIBUTE_Rotate).GetValue());
  nRotate = XFA_MapRotation(nRotate) / 90;
  int32_t nAbsoluteAnchorType = nNextPos[nRotate][nAnchorType];
  fAbsoluteX = fAnchorX;
  fAbsoluteY = fAnchorY;
  switch (nAbsoluteAnchorType / 3) {
    case 1:
      fAbsoluteY -= fHeight / 2;
      break;
    case 2:
      fAbsoluteY -= fHeight;
      break;
    default:
      break;
  }
  switch (nAbsoluteAnchorType % 3) {
    case 1:
      fAbsoluteX -= fWidth / 2;
      break;
    case 2:
      fAbsoluteX -= fWidth;
      break;
    default:
      break;
  }
}
bool CXFA_ItemLayoutProcessor::IncrementRelayoutNode(
    CXFA_LayoutProcessor* pLayoutProcessor,
    CXFA_Node* pNode,
    CXFA_Node* pParentNode) {
  return false;
}
void CXFA_ItemLayoutProcessor::DoLayoutPageArea(
    CXFA_ContainerLayoutItem* pPageAreaLayoutItem) {
  CXFA_Node* pFormNode = pPageAreaLayoutItem->m_pFormNode;
  CXFA_Node* pCurChildNode = XFA_LAYOUT_INVALIDNODE;
  XFA_ItemLayoutProcessorStages nCurChildNodeStage =
      XFA_ItemLayoutProcessorStages_None;
  CXFA_LayoutItem* pBeforeItem = nullptr;
  for (XFA_ItemLayoutProcessor_GotoNextContainerNode(
           pCurChildNode, nCurChildNodeStage, pFormNode, false);
       pCurChildNode; XFA_ItemLayoutProcessor_GotoNextContainerNode(
           pCurChildNode, nCurChildNodeStage, pFormNode, false)) {
    if (nCurChildNodeStage != XFA_ItemLayoutProcessorStages_Container) {
      continue;
    }
    if (pCurChildNode->GetElementType() == XFA_Element::Variables) {
      continue;
    }
    CXFA_ItemLayoutProcessor* pProcessor =
        new CXFA_ItemLayoutProcessor(pCurChildNode, nullptr);
    pProcessor->DoLayout(false, XFA_LAYOUT_FLOAT_MAX);
    if (!pProcessor->HasLayoutItem()) {
      delete pProcessor;
      continue;
    }
    FX_FLOAT fWidth, fHeight;
    pProcessor->GetCurrentComponentSize(fWidth, fHeight);
    FX_FLOAT fAbsoluteX = 0, fAbsoluteY = 0;
    CalculatePositionedContainerPos(pCurChildNode, fWidth, fHeight, fAbsoluteX,
                                    fAbsoluteY);
    pProcessor->SetCurrentComponentPos(fAbsoluteX, fAbsoluteY);
    CXFA_LayoutItem* pProcessItem = pProcessor->ExtractLayoutItem();
    if (!pBeforeItem) {
      pPageAreaLayoutItem->AddHeadChild(pProcessItem);
    } else {
      pPageAreaLayoutItem->InsertChild(pBeforeItem, pProcessItem);
    }
    pBeforeItem = pProcessItem;
    delete pProcessor;
  }
  pBeforeItem = nullptr;
  CXFA_LayoutItem* pLayoutItem = pPageAreaLayoutItem->m_pFirstChild;
  while (pLayoutItem) {
    if (!pLayoutItem->IsContentLayoutItem() ||
        pLayoutItem->m_pFormNode->GetElementType() != XFA_Element::Draw) {
      pLayoutItem = pLayoutItem->m_pNextSibling;
      continue;
    }
    if (pLayoutItem->m_pFormNode->GetElementType() == XFA_Element::Draw) {
      CXFA_LayoutItem* pNextLayoutItem = pLayoutItem->m_pNextSibling;
      pPageAreaLayoutItem->RemoveChild(pLayoutItem);
      if (!pBeforeItem) {
        pPageAreaLayoutItem->AddHeadChild(pLayoutItem);
      } else {
        pPageAreaLayoutItem->InsertChild(pBeforeItem, pLayoutItem);
      }
      pBeforeItem = pLayoutItem;
      pLayoutItem = pNextLayoutItem;
    }
  }
}
void CXFA_ItemLayoutProcessor::DoLayoutPositionedContainer(
    CXFA_LayoutContext* pContext) {
  if (m_pLayoutItem)
    return;

  m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
  bool bIgnoreXY = (m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout) !=
                    XFA_ATTRIBUTEENUM_Position);
  FX_FLOAT fContainerWidth = 0, fContainerHeight = 0;
  bool bContainerWidthAutoSize = true, bContainerHeightAutoSize = true;
  XFA_ItemLayoutProcessor_CalculateContainerSpecfiedSize(
      m_pFormNode, fContainerWidth, fContainerHeight, bContainerWidthAutoSize,
      bContainerHeightAutoSize);
  FX_FLOAT fContentCalculatedWidth = 0, fContentCalculatedHeight = 0;
  FX_FLOAT fHiddenContentCalculatedWidth = 0,
           fHiddenContentCalculatedHeight = 0;
  if (m_pCurChildNode == XFA_LAYOUT_INVALIDNODE) {
    XFA_ItemLayoutProcessor_GotoNextContainerNode(
        m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false);
  }
  int32_t iColIndex = 0;
  for (; m_pCurChildNode; XFA_ItemLayoutProcessor_GotoNextContainerNode(
           m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false)) {
    if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages_Container) {
      continue;
    }
    if (m_pCurChildNode->GetElementType() == XFA_Element::Variables) {
      continue;
    }
    CXFA_ItemLayoutProcessor* pProcessor =
        new CXFA_ItemLayoutProcessor(m_pCurChildNode, m_pPageMgr);
    if (pContext && pContext->m_prgSpecifiedColumnWidths) {
      int32_t iColSpan = m_pCurChildNode->GetInteger(XFA_ATTRIBUTE_ColSpan);
      if (iColSpan <=
          pContext->m_prgSpecifiedColumnWidths->GetSize() - iColIndex) {
        pContext->m_fCurColumnWidth = 0;
        pContext->m_bCurColumnWidthAvaiable = true;
        if (iColSpan == -1)
          iColSpan = pContext->m_prgSpecifiedColumnWidths->GetSize();
        for (int32_t i = 0; iColIndex + i < iColSpan; ++i) {
          pContext->m_fCurColumnWidth +=
              pContext->m_prgSpecifiedColumnWidths->GetAt(iColIndex + i);
        }
        if (pContext->m_fCurColumnWidth == 0)
          pContext->m_bCurColumnWidthAvaiable = false;
        iColIndex += iColSpan >= 0 ? iColSpan : 0;
      }
    }
    pProcessor->DoLayout(false, XFA_LAYOUT_FLOAT_MAX, XFA_LAYOUT_FLOAT_MAX,
                         pContext);
    if (!pProcessor->HasLayoutItem()) {
      delete pProcessor;
      continue;
    }
    FX_FLOAT fWidth, fHeight;
    pProcessor->GetCurrentComponentSize(fWidth, fHeight);
    bool bChangeParentSize = false;
    if (XFA_ItemLayoutProcessor_IsTakingSpace(m_pCurChildNode)) {
      bChangeParentSize = true;
    }
    FX_FLOAT fAbsoluteX = 0, fAbsoluteY = 0;
    if (!bIgnoreXY) {
      CalculatePositionedContainerPos(m_pCurChildNode, fWidth, fHeight,
                                      fAbsoluteX, fAbsoluteY);
    }
    pProcessor->SetCurrentComponentPos(fAbsoluteX, fAbsoluteY);
    if (bContainerWidthAutoSize) {
      FX_FLOAT fChildSuppliedWidth = fAbsoluteX + fWidth;
      if (bChangeParentSize) {
        if (fContentCalculatedWidth < fChildSuppliedWidth) {
          fContentCalculatedWidth = fChildSuppliedWidth;
        }
      } else {
        if (fHiddenContentCalculatedWidth < fChildSuppliedWidth &&
            m_pCurChildNode->GetElementType() != XFA_Element::Subform) {
          fHiddenContentCalculatedWidth = fChildSuppliedWidth;
        }
      }
    }
    if (bContainerHeightAutoSize) {
      FX_FLOAT fChildSuppliedHeight = fAbsoluteY + fHeight;
      if (bChangeParentSize) {
        if (fContentCalculatedHeight < fChildSuppliedHeight) {
          fContentCalculatedHeight = fChildSuppliedHeight;
        }
      } else {
        if (fHiddenContentCalculatedHeight < fChildSuppliedHeight &&
            m_pCurChildNode->GetElementType() != XFA_Element::Subform) {
          fHiddenContentCalculatedHeight = fChildSuppliedHeight;
        }
      }
    }
    m_pLayoutItem->AddChild(pProcessor->ExtractLayoutItem());
    delete pProcessor;
  }
  XFA_VERSION eVersion = m_pFormNode->GetDocument()->GetCurVersionMode();
  if (fContentCalculatedWidth == 0 && eVersion < XFA_VERSION_207) {
    fContentCalculatedWidth = fHiddenContentCalculatedWidth;
  }
  if (fContentCalculatedHeight == 0 && eVersion < XFA_VERSION_207) {
    fContentCalculatedHeight = fHiddenContentCalculatedHeight;
  }
  XFA_ItemLayoutProcessor_CalculateContainerComponentSizeFromContentSize(
      m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
      fContainerWidth, bContainerHeightAutoSize, fContentCalculatedHeight,
      fContainerHeight);
  SetCurrentComponentSize(fContainerWidth, fContainerHeight);
}
static inline void XFA_ItemLayoutProcessor_UpdateWidgetSize(
    CXFA_ContentLayoutItem* pLayoutItem,
    FX_FLOAT& fWidth,
    FX_FLOAT& fHeight) {
  CXFA_Node* pNode = pLayoutItem->m_pFormNode;
  ASSERT(pNode);
  switch (pNode->GetElementType()) {
    case XFA_Element::Subform:
    case XFA_Element::Area:
    case XFA_Element::ExclGroup:
    case XFA_Element::SubformSet: {
      if (fWidth < -XFA_LAYOUT_FLOAT_PERCISION) {
        fWidth = pLayoutItem->m_sSize.x;
      }
      if (fHeight < -XFA_LAYOUT_FLOAT_PERCISION) {
        fHeight = pLayoutItem->m_sSize.y;
      }
      break;
    }
    case XFA_Element::Draw:
    case XFA_Element::Field: {
      pNode->GetDocument()->GetNotify()->StartFieldDrawLayout(pNode, fWidth,
                                                              fHeight);
      break;
    }
    default:
      ASSERT(false);
  }
}
static inline void XFA_ItemLayoutProcessor_RelocateTableRowCells(
    CXFA_ContentLayoutItem* pLayoutRow,
    const CFX_ArrayTemplate<FX_FLOAT>& rgSpecifiedColumnWidths,
    XFA_ATTRIBUTEENUM eLayout) {
  FX_FLOAT fContainerWidth = 0, fContainerHeight = 0;
  bool bContainerWidthAutoSize = true, bContainerHeightAutoSize = true;
  XFA_ItemLayoutProcessor_CalculateContainerSpecfiedSize(
      pLayoutRow->m_pFormNode, fContainerWidth, fContainerHeight,
      bContainerWidthAutoSize, bContainerHeightAutoSize);
  CXFA_Node* pMarginNode =
      pLayoutRow->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
  FX_FLOAT fLeftInset = 0, fTopInset = 0, fRightInset = 0, fBottomInset = 0;
  if (pMarginNode) {
    fLeftInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
    fTopInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
    fRightInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
    fBottomInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset).ToUnit(XFA_UNIT_Pt);
  }
  FX_FLOAT fContentWidthLimit =
      bContainerWidthAutoSize ? XFA_LAYOUT_FLOAT_MAX
                              : fContainerWidth - fLeftInset - fRightInset;
  FX_FLOAT fContentCurrentHeight =
      pLayoutRow->m_sSize.y - fTopInset - fBottomInset;
  FX_FLOAT fContentCalculatedWidth = 0, fContentCalculatedHeight = 0;
  FX_FLOAT fCurrentColX = 0;
  int32_t nCurrentColIdx = 0;
  bool bMetWholeRowCell = false;
  for (CXFA_ContentLayoutItem* pLayoutChild =
           (CXFA_ContentLayoutItem*)pLayoutRow->m_pFirstChild;
       pLayoutChild;
       pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
    int32_t nOriginalColSpan =
        pLayoutChild->m_pFormNode->GetInteger(XFA_ATTRIBUTE_ColSpan);
    int32_t nColSpan = nOriginalColSpan;
    FX_FLOAT fColSpanWidth = 0;
    if (nColSpan == -1 ||
        nCurrentColIdx + nColSpan > rgSpecifiedColumnWidths.GetSize()) {
      nColSpan = rgSpecifiedColumnWidths.GetSize() - nCurrentColIdx;
    }
    for (int32_t i = 0; i < nColSpan; i++) {
      fColSpanWidth += rgSpecifiedColumnWidths[nCurrentColIdx + i];
    }
    if (nColSpan != nOriginalColSpan) {
      fColSpanWidth = bMetWholeRowCell ? 0 : std::max(fColSpanWidth,
                                                      pLayoutChild->m_sSize.y);
    }
    if (nOriginalColSpan == -1) {
      bMetWholeRowCell = true;
    }
    pLayoutChild->m_sPos = CFX_PointF(fCurrentColX, 0);
    pLayoutChild->m_sSize.x = fColSpanWidth;
    if (XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode)) {
      fCurrentColX += fColSpanWidth;
      nCurrentColIdx += nColSpan;
      FX_FLOAT fNewHeight =
          bContainerHeightAutoSize ? -1 : fContentCurrentHeight;
      XFA_ItemLayoutProcessor_UpdateWidgetSize(pLayoutChild, fColSpanWidth,
                                               fNewHeight);
      pLayoutChild->m_sSize.y = fNewHeight;
      if (bContainerHeightAutoSize) {
        FX_FLOAT fChildSuppliedHeight = pLayoutChild->m_sSize.y;
        if (fContentCalculatedHeight < fChildSuppliedHeight) {
          fContentCalculatedHeight = fChildSuppliedHeight;
        }
      }
    }
  }
  if (bContainerHeightAutoSize) {
    for (CXFA_ContentLayoutItem* pLayoutChild =
             (CXFA_ContentLayoutItem*)pLayoutRow->m_pFirstChild;
         pLayoutChild;
         pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
      XFA_ItemLayoutProcessor_UpdateWidgetSize(
          pLayoutChild, pLayoutChild->m_sSize.x, fContentCalculatedHeight);
      FX_FLOAT fOldChildHeight = pLayoutChild->m_sSize.y;
      pLayoutChild->m_sSize.y = fContentCalculatedHeight;
      CXFA_Node* pParaNode =
          pLayoutChild->m_pFormNode->GetFirstChildByClass(XFA_Element::Para);
      if (pParaNode && pLayoutChild->m_pFirstChild) {
        FX_FLOAT fOffHeight = fContentCalculatedHeight - fOldChildHeight;
        XFA_ATTRIBUTEENUM eVType = pParaNode->GetEnum(XFA_ATTRIBUTE_VAlign);
        switch (eVType) {
          case XFA_ATTRIBUTEENUM_Middle:
            fOffHeight = fOffHeight / 2;
            break;
          case XFA_ATTRIBUTEENUM_Bottom:
            break;
          case XFA_ATTRIBUTEENUM_Top:
          default:
            fOffHeight = 0;
            break;
        }
        if (fOffHeight > 0) {
          for (CXFA_ContentLayoutItem* pInnerLayoutChild =
                   (CXFA_ContentLayoutItem*)pLayoutChild->m_pFirstChild;
               pInnerLayoutChild;
               pInnerLayoutChild =
                   (CXFA_ContentLayoutItem*)pInnerLayoutChild->m_pNextSibling) {
            pInnerLayoutChild->m_sPos.y += fOffHeight;
          }
        }
      }
    }
  }
  if (bContainerWidthAutoSize) {
    FX_FLOAT fChildSuppliedWidth = fCurrentColX;
    if (fContentWidthLimit < XFA_LAYOUT_FLOAT_MAX &&
        fContentWidthLimit > fChildSuppliedWidth) {
      fChildSuppliedWidth = fContentWidthLimit;
    }
    if (fContentCalculatedWidth < fChildSuppliedWidth) {
      fContentCalculatedWidth = fChildSuppliedWidth;
    }
  } else {
    fContentCalculatedWidth = fContainerWidth - fLeftInset - fRightInset;
  }
  if (pLayoutRow->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout) ==
      XFA_ATTRIBUTEENUM_Rl_row) {
    for (CXFA_ContentLayoutItem* pLayoutChild =
             (CXFA_ContentLayoutItem*)pLayoutRow->m_pFirstChild;
         pLayoutChild;
         pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
      pLayoutChild->m_sPos.x = fContentCalculatedWidth -
                               pLayoutChild->m_sPos.x - pLayoutChild->m_sSize.x;
    }
  }
  XFA_ItemLayoutProcessor_CalculateContainerComponentSizeFromContentSize(
      pLayoutRow->m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
      fContainerWidth, bContainerHeightAutoSize, fContentCalculatedHeight,
      fContainerHeight);
  pLayoutRow->m_sSize = CFX_SizeF(fContainerWidth, fContainerHeight);
}
void CXFA_ItemLayoutProcessor::DoLayoutTableContainer(CXFA_Node* pLayoutNode) {
  if (m_pLayoutItem)
    return;

  if (!pLayoutNode) {
    pLayoutNode = m_pFormNode;
  }
  ASSERT(m_pCurChildNode == XFA_LAYOUT_INVALIDNODE);
  m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
  FX_FLOAT fContainerWidth = 0, fContainerHeight = 0;
  bool bContainerWidthAutoSize = true, bContainerHeightAutoSize = true;
  XFA_ItemLayoutProcessor_CalculateContainerSpecfiedSize(
      m_pFormNode, fContainerWidth, fContainerHeight, bContainerWidthAutoSize,
      bContainerHeightAutoSize);
  FX_FLOAT fContentCalculatedWidth = 0, fContentCalculatedHeight = 0;
  CXFA_Node* pMarginNode =
      m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
  FX_FLOAT fLeftInset = 0;
  FX_FLOAT fRightInset = 0;
  if (pMarginNode) {
    fLeftInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
    fRightInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
  }
  FX_FLOAT fContentWidthLimit =
      bContainerWidthAutoSize ? XFA_LAYOUT_FLOAT_MAX
                              : fContainerWidth - fLeftInset - fRightInset;
  CFX_WideStringC wsColumnWidths;
  if (pLayoutNode->TryCData(XFA_ATTRIBUTE_ColumnWidths, wsColumnWidths)) {
    CFX_WideStringArray widths;
    if (SeparateStringW(wsColumnWidths.c_str(), wsColumnWidths.GetLength(),
                        L' ', widths) > 0) {
      int32_t iCols = widths.GetSize();
      CFX_WideString wsWidth;
      for (int32_t i = 0; i < iCols; i++) {
        wsWidth = widths[i];
        wsWidth.TrimLeft(L' ');
        if (!wsWidth.IsEmpty()) {
          CXFA_Measurement measure(wsWidth.AsStringC());
          m_rgSpecifiedColumnWidths.Add(measure.ToUnit(XFA_UNIT_Pt));
        }
      }
    }
  }
  int32_t iSpecifiedColumnCount = m_rgSpecifiedColumnWidths.GetSize();
  CXFA_LayoutContext layoutContext;
  layoutContext.m_prgSpecifiedColumnWidths = &m_rgSpecifiedColumnWidths;
  CXFA_LayoutContext* pLayoutContext =
      iSpecifiedColumnCount > 0 ? &layoutContext : nullptr;
  if (m_pCurChildNode == XFA_LAYOUT_INVALIDNODE) {
    XFA_ItemLayoutProcessor_GotoNextContainerNode(
        m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false);
  }
  for (; m_pCurChildNode; XFA_ItemLayoutProcessor_GotoNextContainerNode(
           m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false)) {
    layoutContext.m_bCurColumnWidthAvaiable = false;
    layoutContext.m_fCurColumnWidth = 0;
    if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages_Container) {
      continue;
    }
    CXFA_ItemLayoutProcessor* pProcessor =
        new CXFA_ItemLayoutProcessor(m_pCurChildNode, m_pPageMgr);
    pProcessor->DoLayout(false, XFA_LAYOUT_FLOAT_MAX, XFA_LAYOUT_FLOAT_MAX,
                         pLayoutContext);
    if (!pProcessor->HasLayoutItem()) {
      delete pProcessor;
      continue;
    }
    m_pLayoutItem->AddChild(pProcessor->ExtractLayoutItem());
    delete pProcessor;
  }
  int32_t iRowCount = 0, iColCount = 0;
  {
    CFX_ArrayTemplate<CXFA_ContentLayoutItem*> rgRowItems;
    CFX_ArrayTemplate<int32_t> rgRowItemsSpan;
    CFX_ArrayTemplate<FX_FLOAT> rgRowItemsWidth;
    for (CXFA_ContentLayoutItem* pLayoutChild =
             (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
         pLayoutChild;
         pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
      if (pLayoutChild->m_pFormNode->GetElementType() != XFA_Element::Subform) {
        continue;
      }
      if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode)) {
        continue;
      }
      XFA_ATTRIBUTEENUM eLayout =
          pLayoutChild->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
      if (eLayout != XFA_ATTRIBUTEENUM_Row &&
          eLayout != XFA_ATTRIBUTEENUM_Rl_row) {
        continue;
      }
      if (CXFA_ContentLayoutItem* pRowLayoutCell =
              (CXFA_ContentLayoutItem*)pLayoutChild->m_pFirstChild) {
        rgRowItems.Add(pRowLayoutCell);
        int32_t iColSpan =
            pRowLayoutCell->m_pFormNode->GetInteger(XFA_ATTRIBUTE_ColSpan);
        rgRowItemsSpan.Add(iColSpan);
        rgRowItemsWidth.Add(pRowLayoutCell->m_sSize.x);
      }
    }
    iRowCount = rgRowItems.GetSize();
    iColCount = 0;
    bool bMoreColumns = true;
    while (bMoreColumns) {
      bMoreColumns = false;
      bool bAutoCol = false;
      for (int32_t i = 0; i < iRowCount; i++) {
        while (rgRowItems[i] && (rgRowItemsSpan[i] <= 0 ||
                                 !XFA_ItemLayoutProcessor_IsTakingSpace(
                                     rgRowItems[i]->m_pFormNode))) {
          CXFA_ContentLayoutItem* pNewCell =
              (CXFA_ContentLayoutItem*)rgRowItems[i]->m_pNextSibling;
          if (rgRowItemsSpan[i] < 0 && XFA_ItemLayoutProcessor_IsTakingSpace(
                                           rgRowItems[i]->m_pFormNode)) {
            pNewCell = nullptr;
          }
          rgRowItems[i] = pNewCell;
          rgRowItemsSpan[i] =
              pNewCell
                  ? pNewCell->m_pFormNode->GetInteger(XFA_ATTRIBUTE_ColSpan)
                  : 0;
          rgRowItemsWidth[i] = pNewCell ? pNewCell->m_sSize.x : 0;
        }
        CXFA_ContentLayoutItem* pCell = rgRowItems[i];
        if (!pCell) {
          continue;
        }
        bMoreColumns = true;
        if (rgRowItemsSpan[i] == 1) {
          if (iColCount >= iSpecifiedColumnCount) {
            for (int32_t j = 0, c = iColCount + 1 -
                                    m_rgSpecifiedColumnWidths.GetSize();
                 j < c; j++) {
              m_rgSpecifiedColumnWidths.Add(0);
            }
          }
          if (m_rgSpecifiedColumnWidths[iColCount] <
              XFA_LAYOUT_FLOAT_PERCISION) {
            bAutoCol = true;
          }
          if (bAutoCol &&
              m_rgSpecifiedColumnWidths[iColCount] < rgRowItemsWidth[i]) {
            m_rgSpecifiedColumnWidths[iColCount] = rgRowItemsWidth[i];
          }
        }
      }
      if (bMoreColumns) {
        FX_FLOAT fFinalColumnWidth = 0.0f;
        if (iColCount < m_rgSpecifiedColumnWidths.GetSize())
          fFinalColumnWidth = m_rgSpecifiedColumnWidths[iColCount];
        for (int32_t i = 0; i < iRowCount; ++i) {
          if (!rgRowItems[i])
            continue;
          --rgRowItemsSpan[i];
          rgRowItemsWidth[i] -= fFinalColumnWidth;
        }
        ++iColCount;
      }
    }
  }
  FX_FLOAT fCurrentRowY = 0;
  for (CXFA_ContentLayoutItem* pLayoutChild =
           (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
       pLayoutChild;
       pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) {
    if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode)) {
      continue;
    }
    if (pLayoutChild->m_pFormNode->GetElementType() == XFA_Element::Subform) {
      XFA_ATTRIBUTEENUM eSubformLayout =
          pLayoutChild->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
      if (eSubformLayout == XFA_ATTRIBUTEENUM_Row ||
          eSubformLayout == XFA_ATTRIBUTEENUM_Rl_row) {
        XFA_ItemLayoutProcessor_RelocateTableRowCells(
            pLayoutChild, m_rgSpecifiedColumnWidths, eSubformLayout);
      }
    }
    pLayoutChild->m_sPos.y = fCurrentRowY;
    if (bContainerWidthAutoSize) {
      pLayoutChild->m_sPos.x = 0;
    } else {
      switch (pLayoutChild->m_pFormNode->GetEnum(XFA_ATTRIBUTE_HAlign)) {
        case XFA_ATTRIBUTEENUM_Left:
        default:
          pLayoutChild->m_sPos.x = 0;
          break;
        case XFA_ATTRIBUTEENUM_Center:
          pLayoutChild->m_sPos.x =
              (fContentWidthLimit - pLayoutChild->m_sSize.x) / 2;
          break;
        case XFA_ATTRIBUTEENUM_Right:
          pLayoutChild->m_sPos.x = fContentWidthLimit - pLayoutChild->m_sSize.x;
          break;
      }
    }
    if (bContainerWidthAutoSize) {
      FX_FLOAT fChildSuppliedWidth =
          pLayoutChild->m_sPos.x + pLayoutChild->m_sSize.x;
      if (fContentWidthLimit < XFA_LAYOUT_FLOAT_MAX &&
          fContentWidthLimit > fChildSuppliedWidth) {
        fChildSuppliedWidth = fContentWidthLimit;
      }
      if (fContentCalculatedWidth < fChildSuppliedWidth) {
        fContentCalculatedWidth = fChildSuppliedWidth;
      }
    }
    fCurrentRowY += pLayoutChild->m_sSize.y;
  }
  if (bContainerHeightAutoSize) {
    FX_FLOAT fChildSuppliedHeight = fCurrentRowY;
    if (fContentCalculatedHeight < fChildSuppliedHeight) {
      fContentCalculatedHeight = fChildSuppliedHeight;
    }
  }
  XFA_ItemLayoutProcessor_CalculateContainerComponentSizeFromContentSize(
      m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
      fContainerWidth, bContainerHeightAutoSize, fContentCalculatedHeight,
      fContainerHeight);
  SetCurrentComponentSize(fContainerWidth, fContainerHeight);
}
static uint8_t XFA_ItemLayoutProcessor_HAlignEnumToInt(
    XFA_ATTRIBUTEENUM eHAlign) {
  switch (eHAlign) {
    case XFA_ATTRIBUTEENUM_Center:
      return 1;
    case XFA_ATTRIBUTEENUM_Right:
      return 2;
    case XFA_ATTRIBUTEENUM_Left:
    default:
      return 0;
  }
}
static void XFA_ItemLayoutProcessor_UpdatePendedItemLayout(
    CXFA_ItemLayoutProcessor* pProcessor,
    CXFA_ContentLayoutItem* pLayoutItem) {
  XFA_ATTRIBUTEENUM eLayout =
      pLayoutItem->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
  switch (eLayout) {
    case XFA_ATTRIBUTEENUM_Row:
    case XFA_ATTRIBUTEENUM_Rl_row:
      XFA_ItemLayoutProcessor_RelocateTableRowCells(
          pLayoutItem, pProcessor->m_rgSpecifiedColumnWidths, eLayout);
      break;
    default:
      break;
  }
}
bool CXFA_ItemLayoutProcessor::IsAddNewRowForTrailer(
    CXFA_ContentLayoutItem* pTrailerItem) {
  if (!pTrailerItem) {
    return false;
  }
  FX_FLOAT fWidth = pTrailerItem->m_sSize.x;
  XFA_ATTRIBUTEENUM eLayout = m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
  if (eLayout != XFA_ATTRIBUTEENUM_Tb && m_fWidthLimite > fWidth) {
    return false;
  }
  return true;
}
static void XFA_ItemLayoutProcessor_AddTrailerBeforeSplit(
    CXFA_ItemLayoutProcessor* pProcessor,
    FX_FLOAT fSplitPos,
    CXFA_ContentLayoutItem* pTrailerLayoutItem,
    bool bUseInherited = false) {
  if (!pTrailerLayoutItem) {
    return;
  }
  FX_FLOAT fHeight = pTrailerLayoutItem->m_sSize.y;
  if (bUseInherited) {
    FX_FLOAT fNewSplitPos = 0;
    if (fSplitPos - fHeight > XFA_LAYOUT_FLOAT_PERCISION) {
      fNewSplitPos = pProcessor->FindSplitPos(fSplitPos - fHeight);
    }
    if (fNewSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
      pProcessor->SplitLayoutItem(fNewSplitPos);
    }
    return;
  }
  XFA_ItemLayoutProcessor_UpdatePendedItemLayout(pProcessor,
                                                 pTrailerLayoutItem);
  CXFA_Node* pMarginNode =
      pProcessor->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
  FX_FLOAT fLeftInset = 0, fTopInset = 0, fRightInset = 0, fBottomInset = 0;
  if (pMarginNode) {
    fLeftInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
    fTopInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
    fRightInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
    fBottomInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset).ToUnit(XFA_UNIT_Pt);
  }
  if (!pProcessor->IsAddNewRowForTrailer(pTrailerLayoutItem)) {
    pTrailerLayoutItem->m_sPos.y = pProcessor->m_fLastRowY;
    pTrailerLayoutItem->m_sPos.x = pProcessor->m_fLastRowWidth;
    pProcessor->m_pLayoutItem->m_sSize.x += pTrailerLayoutItem->m_sSize.x;
    pProcessor->m_pLayoutItem->AddChild(pTrailerLayoutItem);
    return;
  }
  FX_FLOAT fNewSplitPos = 0;
  if (fSplitPos - fHeight > XFA_LAYOUT_FLOAT_PERCISION) {
    fNewSplitPos = pProcessor->FindSplitPos(fSplitPos - fHeight);
  }
  if (fNewSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
    pProcessor->SplitLayoutItem(fNewSplitPos);
    pTrailerLayoutItem->m_sPos.y = fNewSplitPos - fTopInset - fBottomInset;
  } else {
    pTrailerLayoutItem->m_sPos.y = fSplitPos - fTopInset - fBottomInset;
  }
  switch (pTrailerLayoutItem->m_pFormNode->GetEnum(XFA_ATTRIBUTE_HAlign)) {
    case XFA_ATTRIBUTEENUM_Left:
    default:
      pTrailerLayoutItem->m_sPos.x = fLeftInset;
      break;
    case XFA_ATTRIBUTEENUM_Right:
      pTrailerLayoutItem->m_sPos.x = pProcessor->m_pLayoutItem->m_sSize.x -
                                     fRightInset -
                                     pTrailerLayoutItem->m_sSize.x;
      break;
    case XFA_ATTRIBUTEENUM_Center:
      pTrailerLayoutItem->m_sPos.x =
          (pProcessor->m_pLayoutItem->m_sSize.x - fLeftInset - fRightInset -
           pTrailerLayoutItem->m_sSize.x) /
          2;
      break;
  }
  pProcessor->m_pLayoutItem->m_sSize.y += fHeight;
  pProcessor->m_pLayoutItem->AddChild(pTrailerLayoutItem);
}
static void XFA_ItemLayoutProcessor_AddLeaderAfterSplit(
    CXFA_ItemLayoutProcessor* pProcessor,
    CXFA_ContentLayoutItem* pLeaderLayoutItem) {
  XFA_ItemLayoutProcessor_UpdatePendedItemLayout(pProcessor, pLeaderLayoutItem);
  CXFA_Node* pMarginNode =
      pProcessor->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
  FX_FLOAT fLeftInset = 0;
  FX_FLOAT fRightInset = 0;
  if (pMarginNode) {
    fLeftInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
    fRightInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
  }
  FX_FLOAT fHeight = pLeaderLayoutItem->m_sSize.y;
  for (CXFA_ContentLayoutItem* pChildItem =
           (CXFA_ContentLayoutItem*)pProcessor->m_pLayoutItem->m_pFirstChild;
       pChildItem;
       pChildItem = (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling) {
    pChildItem->m_sPos.y += fHeight;
  }
  pLeaderLayoutItem->m_sPos.y = 0;
  switch (pLeaderLayoutItem->m_pFormNode->GetEnum(XFA_ATTRIBUTE_HAlign)) {
    case XFA_ATTRIBUTEENUM_Left:
    default:
      pLeaderLayoutItem->m_sPos.x = fLeftInset;
      break;
    case XFA_ATTRIBUTEENUM_Right:
      pLeaderLayoutItem->m_sPos.x = pProcessor->m_pLayoutItem->m_sSize.x -
                                    fRightInset - pLeaderLayoutItem->m_sSize.x;
      break;
    case XFA_ATTRIBUTEENUM_Center:
      pLeaderLayoutItem->m_sPos.x =
          (pProcessor->m_pLayoutItem->m_sSize.x - fLeftInset - fRightInset -
           pLeaderLayoutItem->m_sSize.x) /
          2;
      break;
  }
  pProcessor->m_pLayoutItem->m_sSize.y += fHeight;
  pProcessor->m_pLayoutItem->AddChild(pLeaderLayoutItem);
}
static void XFA_ItemLayoutProcessor_AddPendingNode(
    CXFA_ItemLayoutProcessor* pProcessor,
    CXFA_Node* pPendingNode,
    bool bBreakPending) {
  pProcessor->m_PendingNodes.push_back(pPendingNode);
  pProcessor->m_bBreakPending = bBreakPending;
}
static FX_FLOAT XFA_ItemLayoutProcessor_InsertPendingItems(
    CXFA_ItemLayoutProcessor* pProcessor,
    CXFA_Node* pCurChildNode) {
  FX_FLOAT fTotalHeight = 0;
  if (pProcessor->m_PendingNodes.empty()) {
    return fTotalHeight;
  }
  if (!pProcessor->m_pLayoutItem) {
    pProcessor->m_pLayoutItem =
        pProcessor->CreateContentLayoutItem(pCurChildNode);
    pProcessor->m_pLayoutItem->m_sSize.clear();
  }
  while (!pProcessor->m_PendingNodes.empty()) {
    std::unique_ptr<CXFA_ItemLayoutProcessor> pPendingProcessor(
        new CXFA_ItemLayoutProcessor(pProcessor->m_PendingNodes.front(),
                                     nullptr));
    pProcessor->m_PendingNodes.pop_front();
    pPendingProcessor->DoLayout(false, XFA_LAYOUT_FLOAT_MAX);
    CXFA_ContentLayoutItem* pPendingLayoutItem =
        pPendingProcessor->HasLayoutItem()
            ? pPendingProcessor->ExtractLayoutItem()
            : nullptr;
    if (pPendingLayoutItem) {
      XFA_ItemLayoutProcessor_AddLeaderAfterSplit(pProcessor,
                                                  pPendingLayoutItem);
      if (pProcessor->m_bBreakPending) {
        fTotalHeight += pPendingLayoutItem->m_sSize.y;
      }
    }
  }
  return fTotalHeight;
}
FX_FLOAT CXFA_ItemLayoutProcessor::InsertKeepLayoutItems() {
  FX_FLOAT fTotalHeight = 0;
  if (m_arrayKeepItems.GetSize()) {
    if (!m_pLayoutItem) {
      m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
      m_pLayoutItem->m_sSize.clear();
    }
    for (int32_t iIndex = m_arrayKeepItems.GetSize() - 1; iIndex >= 0;
         iIndex--) {
      XFA_ItemLayoutProcessor_AddLeaderAfterSplit(this,
                                                  m_arrayKeepItems[iIndex]);
      fTotalHeight += m_arrayKeepItems[iIndex]->m_sSize.y;
    }
    m_arrayKeepItems.RemoveAll();
  }
  return fTotalHeight;
}
bool CXFA_ItemLayoutProcessor::ProcessKeepForSplite(
    CXFA_ItemLayoutProcessor* pParentProcessor,
    CXFA_ItemLayoutProcessor* pChildProcessor,
    XFA_ItemLayoutProcessorResult eRetValue,
    CFX_ArrayTemplate<CXFA_ContentLayoutItem*>& rgCurLineLayoutItem,
    FX_FLOAT& fContentCurRowAvailWidth,
    FX_FLOAT& fContentCurRowHeight,
    FX_FLOAT& fContentCurRowY,
    bool& bAddedItemInRow,
    bool& bForceEndPage,
    XFA_ItemLayoutProcessorResult& result) {
  if (!pParentProcessor || !pChildProcessor) {
    return false;
  }
  if (pParentProcessor->m_pCurChildNode->GetIntact() !=
          XFA_ATTRIBUTEENUM_None ||
      !pChildProcessor->m_bHasAvailHeight) {
    if (XFA_ExistContainerKeep(pParentProcessor->m_pCurChildNode, true)) {
      FX_FLOAT fChildWidth, fChildHeight;
      pChildProcessor->GetCurrentComponentSize(fChildWidth, fChildHeight);
      CFX_ArrayTemplate<CXFA_ContentLayoutItem*> keepLayoutItems;
      if (pParentProcessor->JudgePutNextPage(pParentProcessor->m_pLayoutItem,
                                             fChildHeight, keepLayoutItems)) {
        m_arrayKeepItems.RemoveAll();
        for (int32_t iIndex = 0; iIndex < keepLayoutItems.GetSize(); iIndex++) {
          CXFA_ContentLayoutItem* pItem = keepLayoutItems.GetAt(iIndex);
          pParentProcessor->m_pLayoutItem->RemoveChild(pItem);
          fContentCurRowY -= pItem->m_sSize.y;
          m_arrayKeepItems.Add(pItem);
        }
        bAddedItemInRow = true;
        bForceEndPage = true;
        result = XFA_ItemLayoutProcessorResult_PageFullBreak;
        return true;
      }
      rgCurLineLayoutItem.Add(pChildProcessor->ExtractLayoutItem());
      bAddedItemInRow = true;
      fContentCurRowAvailWidth -= fChildWidth;
      if (fContentCurRowHeight < fChildHeight) {
        fContentCurRowHeight = fChildHeight;
      }
      result = eRetValue;
      return true;
    }
  }
  return false;
}
bool CXFA_ItemLayoutProcessor::JudgePutNextPage(
    CXFA_ContentLayoutItem* pParentLayoutItem,
    FX_FLOAT fChildHeight,
    CFX_ArrayTemplate<CXFA_ContentLayoutItem*>& pKeepItems) {
  if (!pParentLayoutItem) {
    return false;
  }
  FX_FLOAT fItemsHeight = 0;
  for (CXFA_ContentLayoutItem* pChildLayoutItem =
           (CXFA_ContentLayoutItem*)pParentLayoutItem->m_pFirstChild;
       pChildLayoutItem;
       pChildLayoutItem =
           (CXFA_ContentLayoutItem*)pChildLayoutItem->m_pNextSibling) {
    if (XFA_ExistContainerKeep(pChildLayoutItem->m_pFormNode, false)) {
      pKeepItems.Add(pChildLayoutItem);
      fItemsHeight += pChildLayoutItem->m_sSize.y;
    } else {
      pKeepItems.RemoveAll();
      fItemsHeight = 0;
    }
  }
  fItemsHeight += fChildHeight;
  if (m_pPageMgr->GetNextAvailContentHeight(fItemsHeight)) {
    return true;
  }
  return false;
}
void CXFA_ItemLayoutProcessor::ProcessUnUseBinds(CXFA_Node* pFormNode) {
  if (!pFormNode) {
    return;
  }
  CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
      pFormNode);
  for (CXFA_Node* pNode = sIterator.MoveToNext(); pNode;
       pNode = sIterator.MoveToNext()) {
    if (pNode->IsContainerNode()) {
      CXFA_Node* pBindNode = pNode->GetBindData();
      if (pBindNode) {
        pBindNode->RemoveBindItem(pNode);
        pNode->SetObject(XFA_ATTRIBUTE_BindingNode, nullptr);
      }
    }
    pNode->SetFlag(XFA_NodeFlag_UnusedNode, true);
  }
}
void CXFA_ItemLayoutProcessor::ProcessUnUseOverFlow(
    CXFA_Node* pLeaderNode,
    CXFA_Node* pTrailerNode,
    CXFA_ContentLayoutItem* pTrailerItem,
    CXFA_Node* pFormNode) {
  ProcessUnUseBinds(pLeaderNode);
  ProcessUnUseBinds(pTrailerNode);
  if (!pFormNode) {
    return;
  }
  if (pFormNode->GetElementType() == XFA_Element::Overflow ||
      pFormNode->GetElementType() == XFA_Element::Break) {
    pFormNode = pFormNode->GetNodeItem(XFA_NODEITEM_Parent);
  }
  if (pLeaderNode && pFormNode) {
    pFormNode->RemoveChild(pLeaderNode);
  }
  if (pTrailerNode && pFormNode) {
    pFormNode->RemoveChild(pTrailerNode);
  }
  if (pTrailerItem) {
    XFA_ReleaseLayoutItem(pTrailerItem);
  }
}
static XFA_ItemLayoutProcessorResult XFA_ItemLayoutProcessor_InsertFlowedItem(
    CXFA_ItemLayoutProcessor* pThis,
    CXFA_ItemLayoutProcessor* pProcessor,
    bool bContainerWidthAutoSize,
    bool bContainerHeightAutoSize,
    FX_FLOAT fContainerHeight,
    XFA_ATTRIBUTEENUM eFlowStrategy,
    uint8_t& uCurHAlignState,
    CFX_ArrayTemplate<CXFA_ContentLayoutItem*> (&rgCurLineLayoutItems)[3],
    bool bUseBreakControl,
    FX_FLOAT fAvailHeight,
    FX_FLOAT fRealHeight,
    FX_FLOAT& fContentCurRowY,
    FX_FLOAT& fContentWidthLimit,
    FX_FLOAT& fContentCurRowAvailWidth,
    FX_FLOAT& fContentCurRowHeight,
    bool& bAddedItemInRow,
    bool& bForceEndPage,
    CXFA_LayoutContext* pLayoutContext = nullptr,
    bool bNewRow = false) {
  bool bTakeSpace =
      XFA_ItemLayoutProcessor_IsTakingSpace(pProcessor->m_pFormNode);
  uint8_t uHAlign = XFA_ItemLayoutProcessor_HAlignEnumToInt(
      pThis->m_pCurChildNode->GetEnum(XFA_ATTRIBUTE_HAlign));
  if (bContainerWidthAutoSize) {
    uHAlign = 0;
  }
  if ((eFlowStrategy != XFA_ATTRIBUTEENUM_Rl_tb && uHAlign < uCurHAlignState) ||
      (eFlowStrategy == XFA_ATTRIBUTEENUM_Rl_tb && uHAlign > uCurHAlignState)) {
    return XFA_ItemLayoutProcessorResult_RowFullBreak;
  }
  uCurHAlignState = uHAlign;
  bool bIsOwnSplite =
      pProcessor->m_pFormNode->GetIntact() == XFA_ATTRIBUTEENUM_None;
  bool bUseRealHeight =
      bTakeSpace && bContainerHeightAutoSize && bIsOwnSplite &&
      pProcessor->m_pFormNode->GetNodeItem(XFA_NODEITEM_Parent)->GetIntact() ==
          XFA_ATTRIBUTEENUM_None;
  bool bIsTransHeight = bTakeSpace;
  if (bIsTransHeight && !bIsOwnSplite) {
    bool bRootForceTb = false;
    XFA_ATTRIBUTEENUM eLayoutStrategy = XFA_ItemLayoutProcessor_GetLayout(
        pProcessor->m_pFormNode, bRootForceTb);
    if (eLayoutStrategy == XFA_ATTRIBUTEENUM_Lr_tb ||
        eLayoutStrategy == XFA_ATTRIBUTEENUM_Rl_tb) {
      bIsTransHeight = false;
    }
  }
  bool bUseInherited = false;
  CXFA_LayoutContext layoutContext;
  if (pThis->m_pPageMgr) {
    CXFA_Node* pOverflowNode =
        pThis->m_pPageMgr->QueryOverflow(pThis->m_pFormNode);
    if (pOverflowNode) {
      layoutContext.m_pOverflowNode = pOverflowNode;
      layoutContext.m_pOverflowProcessor = pThis;
      pLayoutContext = &layoutContext;
    }
  }
  XFA_ItemLayoutProcessorResult eRetValue = XFA_ItemLayoutProcessorResult_Done;
  if (!bNewRow ||
      pProcessor->m_ePreProcessRs == XFA_ItemLayoutProcessorResult_Done) {
    eRetValue = pProcessor->DoLayout(
        bTakeSpace ? bUseBreakControl : false,
        bUseRealHeight ? fRealHeight - fContentCurRowY : XFA_LAYOUT_FLOAT_MAX,
        bIsTransHeight ? fRealHeight - fContentCurRowY : XFA_LAYOUT_FLOAT_MAX,
        pLayoutContext);
    pProcessor->m_ePreProcessRs = eRetValue;
  } else {
    eRetValue = pProcessor->m_ePreProcessRs;
    pProcessor->m_ePreProcessRs = XFA_ItemLayoutProcessorResult_Done;
  }
  if (pProcessor->HasLayoutItem() == false) {
    return eRetValue;
  }
  FX_FLOAT fChildWidth, fChildHeight;
  pProcessor->GetCurrentComponentSize(fChildWidth, fChildHeight);
  if (bUseRealHeight && fRealHeight < XFA_LAYOUT_FLOAT_PERCISION) {
    fRealHeight = XFA_LAYOUT_FLOAT_MAX;
    fAvailHeight = XFA_LAYOUT_FLOAT_MAX;
  }
  if (!bTakeSpace ||
      (fChildWidth <= fContentCurRowAvailWidth + XFA_LAYOUT_FLOAT_PERCISION) ||
      (fContentWidthLimit - fContentCurRowAvailWidth <=
       XFA_LAYOUT_FLOAT_PERCISION)) {
    CXFA_Node* pOverflowLeaderNode = nullptr;
    CXFA_Node* pOverflowTrailerNode = nullptr;
    CXFA_Node* pFormNode = nullptr;
    CXFA_ContentLayoutItem* pTrailerLayoutItem = nullptr;
    bool bIsAddTrailerHeight = false;
    if (pThis->m_pPageMgr &&
        pProcessor->m_pFormNode->GetIntact() == XFA_ATTRIBUTEENUM_None) {
      pFormNode = pThis->m_pPageMgr->QueryOverflow(pProcessor->m_pFormNode);
      if (!pFormNode && pLayoutContext &&
          pLayoutContext->m_pOverflowProcessor) {
        pFormNode = pLayoutContext->m_pOverflowNode;
        bUseInherited = true;
      }
      if (pThis->m_pPageMgr->ProcessOverflow(pFormNode, pOverflowLeaderNode,
                                             pOverflowTrailerNode, false,
                                             false)) {
        if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowTrailerNode)) {
          if (pOverflowTrailerNode) {
            CXFA_ItemLayoutProcessor* pOverflowLeaderProcessor =
                new CXFA_ItemLayoutProcessor(pOverflowTrailerNode, nullptr);
            pOverflowLeaderProcessor->DoLayout(false, XFA_LAYOUT_FLOAT_MAX);
            pTrailerLayoutItem =
                pOverflowLeaderProcessor->HasLayoutItem()
                    ? pOverflowLeaderProcessor->ExtractLayoutItem()
                    : nullptr;
            delete pOverflowLeaderProcessor;
          }
          if (bUseInherited) {
            bIsAddTrailerHeight =
                pThis->IsAddNewRowForTrailer(pTrailerLayoutItem);
          } else {
            bIsAddTrailerHeight =
                pProcessor->IsAddNewRowForTrailer(pTrailerLayoutItem);
          }
          if (bIsAddTrailerHeight) {
            FX_FLOAT fTrailerHeight = pTrailerLayoutItem->m_sSize.y;
            fChildHeight += fTrailerHeight;
            bIsAddTrailerHeight = true;
          }
        }
      }
    }
    if (!bTakeSpace ||
        fContentCurRowY + fChildHeight <=
            fAvailHeight + XFA_LAYOUT_FLOAT_PERCISION ||
        (!bContainerHeightAutoSize &&
         pThis->m_fUsedSize + fAvailHeight + XFA_LAYOUT_FLOAT_PERCISION >=
             fContainerHeight)) {
      if (!bTakeSpace || eRetValue == XFA_ItemLayoutProcessorResult_Done) {
        if (pProcessor->m_bUseInheriated) {
          if (pTrailerLayoutItem) {
            XFA_ItemLayoutProcessor_AddTrailerBeforeSplit(
                pProcessor, fChildHeight, pTrailerLayoutItem);
          }
          if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode)) {
            XFA_ItemLayoutProcessor_AddPendingNode(pProcessor,
                                                   pOverflowLeaderNode, false);
          }
          pProcessor->m_bUseInheriated = false;
        } else {
          if (bIsAddTrailerHeight) {
            fChildHeight -= pTrailerLayoutItem->m_sSize.y;
          }
          pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
                                           pOverflowTrailerNode,
                                           pTrailerLayoutItem, pFormNode);
        }
        CXFA_ContentLayoutItem* pChildLayoutItem =
            pProcessor->ExtractLayoutItem();
        if (XFA_ExistContainerKeep(pProcessor->m_pFormNode, false) &&
            pProcessor->m_pFormNode->GetIntact() == XFA_ATTRIBUTEENUM_None) {
          pThis->m_arrayKeepItems.Add(pChildLayoutItem);
        } else {
          pThis->m_arrayKeepItems.RemoveAll();
        }
        rgCurLineLayoutItems[uHAlign].Add(pChildLayoutItem);
        bAddedItemInRow = true;
        if (bTakeSpace) {
          fContentCurRowAvailWidth -= fChildWidth;
          if (fContentCurRowHeight < fChildHeight) {
            fContentCurRowHeight = fChildHeight;
          }
        }
        return XFA_ItemLayoutProcessorResult_Done;
      } else {
        if (eRetValue == XFA_ItemLayoutProcessorResult_PageFullBreak) {
          if (pProcessor->m_bUseInheriated) {
            if (pTrailerLayoutItem) {
              XFA_ItemLayoutProcessor_AddTrailerBeforeSplit(
                  pProcessor, fChildHeight, pTrailerLayoutItem);
            }
            if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode)) {
              XFA_ItemLayoutProcessor_AddPendingNode(
                  pProcessor, pOverflowLeaderNode, false);
            }
            pProcessor->m_bUseInheriated = false;
          } else {
            if (bIsAddTrailerHeight) {
              fChildHeight -= pTrailerLayoutItem->m_sSize.y;
            }
            pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
                                             pOverflowTrailerNode,
                                             pTrailerLayoutItem, pFormNode);
          }
        }
        rgCurLineLayoutItems[uHAlign].Add(pProcessor->ExtractLayoutItem());
        bAddedItemInRow = true;
        fContentCurRowAvailWidth -= fChildWidth;
        if (fContentCurRowHeight < fChildHeight) {
          fContentCurRowHeight = fChildHeight;
        }
        return eRetValue;
      }
    } else {
      XFA_ItemLayoutProcessorResult eResult;
      if (pThis->ProcessKeepForSplite(
              pThis, pProcessor, eRetValue, rgCurLineLayoutItems[uHAlign],
              fContentCurRowAvailWidth, fContentCurRowHeight, fContentCurRowY,
              bAddedItemInRow, bForceEndPage, eResult)) {
        return eResult;
      }
      bForceEndPage = true;
      FX_FLOAT fSplitPos =
          pProcessor->FindSplitPos(fAvailHeight - fContentCurRowY);
      if (fSplitPos > XFA_LAYOUT_FLOAT_PERCISION) {
        XFA_ATTRIBUTEENUM eLayout =
            pProcessor->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
        if (eLayout == XFA_ATTRIBUTEENUM_Tb &&
            eRetValue == XFA_ItemLayoutProcessorResult_Done) {
          pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
                                           pOverflowTrailerNode,
                                           pTrailerLayoutItem, pFormNode);
          rgCurLineLayoutItems[uHAlign].Add(pProcessor->ExtractLayoutItem());
          bAddedItemInRow = true;
          if (bTakeSpace) {
            fContentCurRowAvailWidth -= fChildWidth;
            if (fContentCurRowHeight < fChildHeight) {
              fContentCurRowHeight = fChildHeight;
            }
          }
          return XFA_ItemLayoutProcessorResult_PageFullBreak;
        }
        CXFA_Node* pTempLeaderNode = nullptr;
        CXFA_Node* pTempTrailerNode = nullptr;
        if (pThis->m_pPageMgr && !pProcessor->m_bUseInheriated &&
            eRetValue != XFA_ItemLayoutProcessorResult_PageFullBreak) {
          pThis->m_pPageMgr->ProcessOverflow(pFormNode, pTempLeaderNode,
                                             pTempTrailerNode, false, true);
        }
        if (pTrailerLayoutItem && bIsAddTrailerHeight) {
          XFA_ItemLayoutProcessor_AddTrailerBeforeSplit(
              pProcessor, fSplitPos, pTrailerLayoutItem, bUseInherited);
        } else {
          pProcessor->SplitLayoutItem(fSplitPos);
        }
        if (bUseInherited) {
          pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
                                           pOverflowTrailerNode,
                                           pTrailerLayoutItem, pFormNode);
          pThis->m_bUseInheriated = true;
        } else {
          CXFA_LayoutItem* firstChild =
              pProcessor->m_pLayoutItem->m_pFirstChild;
          if (firstChild && !firstChild->m_pNextSibling &&
              firstChild->m_pFormNode->IsLayoutGeneratedNode()) {
            pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
                                             pOverflowTrailerNode,
                                             pTrailerLayoutItem, pFormNode);
          } else {
            if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode)) {
              XFA_ItemLayoutProcessor_AddPendingNode(
                  pProcessor, pOverflowLeaderNode, false);
            }
          }
        }
        if (pProcessor->m_pLayoutItem->m_pNextSibling) {
          pProcessor->GetCurrentComponentSize(fChildWidth, fChildHeight);
          rgCurLineLayoutItems[uHAlign].Add(pProcessor->ExtractLayoutItem());
          bAddedItemInRow = true;
          if (bTakeSpace) {
            fContentCurRowAvailWidth -= fChildWidth;
            if (fContentCurRowHeight < fChildHeight) {
              fContentCurRowHeight = fChildHeight;
            }
          }
        }
        return XFA_ItemLayoutProcessorResult_PageFullBreak;
      } else if (fContentCurRowY <= XFA_LAYOUT_FLOAT_PERCISION) {
        pProcessor->GetCurrentComponentSize(fChildWidth, fChildHeight);
        if (pProcessor->m_pPageMgr->GetNextAvailContentHeight(fChildHeight)) {
          CXFA_Node* pTempLeaderNode = nullptr;
          CXFA_Node* pTempTrailerNode = nullptr;
          if (pThis->m_pPageMgr) {
            if (!pFormNode && pLayoutContext) {
              pFormNode = pLayoutContext->m_pOverflowProcessor->m_pFormNode;
            }
            pThis->m_pPageMgr->ProcessOverflow(pFormNode, pTempLeaderNode,
                                               pTempTrailerNode, false, true);
          }
          if (bUseInherited) {
            pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
                                             pOverflowTrailerNode,
                                             pTrailerLayoutItem, pFormNode);
            pThis->m_bUseInheriated = true;
          }
          return XFA_ItemLayoutProcessorResult_PageFullBreak;
        }
        rgCurLineLayoutItems[uHAlign].Add(pProcessor->ExtractLayoutItem());
        bAddedItemInRow = true;
        if (bTakeSpace) {
          fContentCurRowAvailWidth -= fChildWidth;
          if (fContentCurRowHeight < fChildHeight) {
            fContentCurRowHeight = fChildHeight;
          }
        }
        if (eRetValue == XFA_ItemLayoutProcessorResult_Done) {
          bForceEndPage = false;
        }
        return eRetValue;
      } else {
        XFA_ATTRIBUTEENUM eLayout =
            pProcessor->m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout);
        if (pProcessor->m_pFormNode->GetIntact() == XFA_ATTRIBUTEENUM_None &&
            eLayout == XFA_ATTRIBUTEENUM_Tb) {
          if (pThis->m_pPageMgr) {
            pThis->m_pPageMgr->ProcessOverflow(pFormNode, pOverflowLeaderNode,
                                               pOverflowTrailerNode, false,
                                               true);
          }
          if (pTrailerLayoutItem) {
            XFA_ItemLayoutProcessor_AddTrailerBeforeSplit(pProcessor, fSplitPos,
                                                          pTrailerLayoutItem);
          }
          if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode)) {
            XFA_ItemLayoutProcessor_AddPendingNode(pProcessor,
                                                   pOverflowLeaderNode, false);
          }
        } else {
          if (eRetValue == XFA_ItemLayoutProcessorResult_Done) {
            if (!pFormNode && pLayoutContext) {
              pFormNode = pLayoutContext->m_pOverflowProcessor->m_pFormNode;
            }
            if (pThis->m_pPageMgr) {
              pThis->m_pPageMgr->ProcessOverflow(pFormNode, pOverflowLeaderNode,
                                                 pOverflowTrailerNode, false,
                                                 true);
            }
            if (bUseInherited) {
              pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode,
                                               pOverflowTrailerNode,
                                               pTrailerLayoutItem, pFormNode);
              pThis->m_bUseInheriated = true;
            }
          }
        }
        return XFA_ItemLayoutProcessorResult_PageFullBreak;
      }
    }
  } else {
    return XFA_ItemLayoutProcessorResult_RowFullBreak;
  }
  return XFA_ItemLayoutProcessorResult_Done;
}

XFA_ItemLayoutProcessorResult CXFA_ItemLayoutProcessor::DoLayoutFlowedContainer(
    bool bUseBreakControl,
    XFA_ATTRIBUTEENUM eFlowStrategy,
    FX_FLOAT fHeightLimit,
    FX_FLOAT fRealHeight,
    CXFA_LayoutContext* pContext,
    bool bRootForceTb) {
  m_bHasAvailHeight = true;
  FX_FLOAT fContainerWidth = 0, fContainerHeight = 0;
  bool bBreakDone = false;
  bool bContainerWidthAutoSize = true, bContainerHeightAutoSize = true;
  bool bForceEndPage = false;
  bool bIsManualBreak = false;
  if (m_pCurChildPreprocessor) {
    m_pCurChildPreprocessor->m_ePreProcessRs =
        XFA_ItemLayoutProcessorResult_Done;
  }
  XFA_ItemLayoutProcessor_CalculateContainerSpecfiedSize(
      m_pFormNode, fContainerWidth, fContainerHeight, bContainerWidthAutoSize,
      bContainerHeightAutoSize);
  if (pContext && pContext->m_bCurColumnWidthAvaiable) {
    bContainerWidthAutoSize = false;
    fContainerWidth = pContext->m_fCurColumnWidth;
  }
  if (!bContainerHeightAutoSize) {
    fContainerHeight -= m_fUsedSize;
  }
  if (!bContainerHeightAutoSize) {
    CXFA_Node* pParentNode = m_pFormNode->GetNodeItem(XFA_NODEITEM_Parent);
    bool bFocrTb = false;
    if (pParentNode &&
        XFA_ItemLayoutProcessor_GetLayout(pParentNode, bFocrTb) ==
            XFA_ATTRIBUTEENUM_Row) {
      CXFA_Node* pChildContainer = m_pFormNode->GetNodeItem(
          XFA_NODEITEM_FirstChild, XFA_ObjectType::ContainerNode);
      if (pChildContainer &&
          pChildContainer->GetNodeItem(XFA_NODEITEM_NextSibling,
                                       XFA_ObjectType::ContainerNode)) {
        fContainerHeight = 0;
        bContainerHeightAutoSize = true;
      }
    }
  }
  CXFA_Node* pMarginNode =
      m_pFormNode->GetFirstChildByClass(XFA_Element::Margin);
  FX_FLOAT fLeftInset = 0, fTopInset = 0, fRightInset = 0, fBottomInset = 0;
  if (pMarginNode) {
    fLeftInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_LeftInset).ToUnit(XFA_UNIT_Pt);
    fTopInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_TopInset).ToUnit(XFA_UNIT_Pt);
    fRightInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_RightInset).ToUnit(XFA_UNIT_Pt);
    fBottomInset =
        pMarginNode->GetMeasure(XFA_ATTRIBUTE_BottomInset).ToUnit(XFA_UNIT_Pt);
  }
  FX_FLOAT fContentWidthLimit =
      bContainerWidthAutoSize ? XFA_LAYOUT_FLOAT_MAX
                              : fContainerWidth - fLeftInset - fRightInset;
  FX_FLOAT fContentCalculatedWidth = 0, fContentCalculatedHeight = 0;
  FX_FLOAT fAvailHeight = fHeightLimit - fTopInset - fBottomInset;
  if (fAvailHeight < 0) {
    m_bHasAvailHeight = false;
  }
  fRealHeight = fRealHeight - fTopInset - fBottomInset;
  FX_FLOAT fContentCurRowY = 0;
  CXFA_ContentLayoutItem* pLayoutChild = nullptr;
  if (m_pLayoutItem) {
    if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages_Done &&
        eFlowStrategy != XFA_ATTRIBUTEENUM_Tb) {
      pLayoutChild = (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
      for (CXFA_ContentLayoutItem* pLayoutNext = pLayoutChild; pLayoutNext;
           pLayoutNext = (CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling) {
        if (pLayoutNext->m_sPos.y != pLayoutChild->m_sPos.y) {
          pLayoutChild = pLayoutNext;
        }
      }
    }
    for (CXFA_ContentLayoutItem* pLayoutTempChild =
             (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
         pLayoutTempChild != pLayoutChild;
         pLayoutTempChild =
             (CXFA_ContentLayoutItem*)pLayoutTempChild->m_pNextSibling) {
      if (XFA_ItemLayoutProcessor_IsTakingSpace(
              pLayoutTempChild->m_pFormNode)) {
        FX_FLOAT fChildContentWidth =
            pLayoutTempChild->m_sPos.x + pLayoutTempChild->m_sSize.x;
        FX_FLOAT fChildContentHeight =
            pLayoutTempChild->m_sPos.y + pLayoutTempChild->m_sSize.y;
        if (fContentCalculatedWidth < fChildContentWidth) {
          fContentCalculatedWidth = fChildContentWidth;
        }
        if (fContentCalculatedHeight < fChildContentHeight) {
          fContentCalculatedHeight = fChildContentHeight;
        }
      }
    }
    if (pLayoutChild) {
      fContentCurRowY = pLayoutChild->m_sPos.y;
    } else {
      fContentCurRowY = fContentCalculatedHeight;
    }
  }
  fContentCurRowY += InsertKeepLayoutItems();
  if (m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages_None) {
    XFA_ItemLayoutProcessor_GotoNextContainerNode(
        m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, true);
  }
  fContentCurRowY +=
      XFA_ItemLayoutProcessor_InsertPendingItems(this, m_pFormNode);
  if (m_pCurChildPreprocessor &&
      m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages_Container) {
    if (XFA_ExistContainerKeep(m_pCurChildPreprocessor->GetFormNode(), false)) {
      m_pKeepHeadNode = m_pCurChildNode;
      m_bIsProcessKeep = true;
      m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages_Keep;
    }
  }
  while (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages_Done) {
    FX_FLOAT fContentCurRowHeight = 0;
    FX_FLOAT fContentCurRowAvailWidth = fContentWidthLimit;
    m_fWidthLimite = fContentCurRowAvailWidth;
    CFX_ArrayTemplate<CXFA_ContentLayoutItem*> rgCurLineLayoutItems[3];
    uint8_t uCurHAlignState =
        (eFlowStrategy != XFA_ATTRIBUTEENUM_Rl_tb ? 0 : 2);
    if (pLayoutChild) {
      for (CXFA_ContentLayoutItem* pLayoutNext = pLayoutChild; pLayoutNext;
           pLayoutNext = (CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling) {
        if (!pLayoutNext->m_pNextSibling && m_pCurChildPreprocessor &&
            m_pCurChildPreprocessor->m_pFormNode == pLayoutNext->m_pFormNode) {
          pLayoutNext->m_pNext = m_pCurChildPreprocessor->m_pLayoutItem;
          m_pCurChildPreprocessor->m_pLayoutItem = pLayoutNext;
          break;
        }
        uint8_t uHAlign = XFA_ItemLayoutProcessor_HAlignEnumToInt(
            pLayoutNext->m_pFormNode->GetEnum(XFA_ATTRIBUTE_HAlign));
        rgCurLineLayoutItems[uHAlign].Add(pLayoutNext);
        if (eFlowStrategy == XFA_ATTRIBUTEENUM_Lr_tb) {
          if (uHAlign > uCurHAlignState) {
            uCurHAlignState = uHAlign;
          }
        } else if (uHAlign < uCurHAlignState) {
          uCurHAlignState = uHAlign;
        }
        if (XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutNext->m_pFormNode)) {
          if (pLayoutNext->m_sSize.y > fContentCurRowHeight) {
            fContentCurRowHeight = pLayoutNext->m_sSize.y;
          }
          fContentCurRowAvailWidth -= pLayoutNext->m_sSize.x;
        }
      }
      if ((CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild ==
          pLayoutChild) {
        m_pLayoutItem->m_pFirstChild = nullptr;
      } else {
        CXFA_ContentLayoutItem* pLayoutNext =
            (CXFA_ContentLayoutItem*)m_pLayoutItem->m_pFirstChild;
        for (; pLayoutNext;
             pLayoutNext =
                 (CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling) {
          if ((CXFA_ContentLayoutItem*)pLayoutNext->m_pNextSibling ==
              pLayoutChild) {
            pLayoutNext->m_pNextSibling = nullptr;
            break;
          }
        }
      }
      CXFA_ContentLayoutItem* pLayoutNextTemp =
          (CXFA_ContentLayoutItem*)pLayoutChild;
      while (pLayoutNextTemp) {
        pLayoutNextTemp->m_pParent = nullptr;
        CXFA_ContentLayoutItem* pSaveLayoutNext =
            (CXFA_ContentLayoutItem*)pLayoutNextTemp->m_pNextSibling;
        pLayoutNextTemp->m_pNextSibling = nullptr;
        pLayoutNextTemp = pSaveLayoutNext;
      }
      pLayoutChild = nullptr;
    }
    while (m_pCurChildNode) {
      CXFA_ItemLayoutProcessor* pProcessor = nullptr;
      bool bAddedItemInRow = false;
      fContentCurRowY +=
          XFA_ItemLayoutProcessor_InsertPendingItems(this, m_pFormNode);
      switch (m_nCurChildNodeStage) {
        case XFA_ItemLayoutProcessorStages_Keep:
        case XFA_ItemLayoutProcessorStages_None:
          break;
        case XFA_ItemLayoutProcessorStages_BreakBefore: {
          for (int32_t iIndex = 0; iIndex < m_arrayKeepItems.GetSize();
               iIndex++) {
            CXFA_ContentLayoutItem* pItem = m_arrayKeepItems.GetAt(iIndex);
            m_pLayoutItem->RemoveChild(pItem);
            fContentCalculatedHeight -= pItem->m_sSize.y;
          }
          CXFA_Node* pLeaderNode = nullptr;
          CXFA_Node* pTrailerNode = nullptr;
          bool bCreatePage = false;
          if (bUseBreakControl && m_pPageMgr &&
              m_pPageMgr->ProcessBreakBeforeOrAfter(m_pCurChildNode, true,
                                                    pLeaderNode, pTrailerNode,
                                                    bCreatePage) &&
              m_pFormNode->GetElementType() != XFA_Element::Form &&
              bCreatePage) {
            if (JudgeLeaderOrTrailerForOccur(pLeaderNode)) {
              XFA_ItemLayoutProcessor_AddPendingNode(this, pLeaderNode, true);
            }
            if (JudgeLeaderOrTrailerForOccur(pTrailerNode)) {
              if (m_pFormNode->GetNodeItem(XFA_NODEITEM_Parent)
                          ->GetElementType() == XFA_Element::Form &&
                  !m_pLayoutItem) {
                XFA_ItemLayoutProcessor_AddPendingNode(this, pTrailerNode,
                                                       true);
              } else {
                std::unique_ptr<CXFA_ItemLayoutProcessor> pTempProcessor(
                    new CXFA_ItemLayoutProcessor(pTrailerNode, nullptr));
                XFA_ItemLayoutProcessor_InsertFlowedItem(
                    this, pTempProcessor.get(), bContainerWidthAutoSize,
                    bContainerHeightAutoSize, fContainerHeight, eFlowStrategy,
                    uCurHAlignState, rgCurLineLayoutItems, false,
                    XFA_LAYOUT_FLOAT_MAX, XFA_LAYOUT_FLOAT_MAX, fContentCurRowY,
                    fContentWidthLimit, fContentCurRowAvailWidth,
                    fContentCurRowHeight, bAddedItemInRow, bForceEndPage,
                    pContext);
              }
            }
            XFA_ItemLayoutProcessor_GotoNextContainerNode(
                m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, true);
            bForceEndPage = true;
            bIsManualBreak = true;
            goto SuspendAndCreateNewRow;
          }
        } break;
        case XFA_ItemLayoutProcessorStages_BreakAfter: {
          CXFA_Node* pLeaderNode = nullptr;
          CXFA_Node* pTrailerNode = nullptr;
          bool bCreatePage = false;
          if (bUseBreakControl && m_pPageMgr &&
              m_pPageMgr->ProcessBreakBeforeOrAfter(m_pCurChildNode, false,
                                                    pLeaderNode, pTrailerNode,
                                                    bCreatePage) &&
              m_pFormNode->GetElementType() != XFA_Element::Form) {
            if (JudgeLeaderOrTrailerForOccur(pTrailerNode)) {
              std::unique_ptr<CXFA_ItemLayoutProcessor> pTempProcessor(
                  new CXFA_ItemLayoutProcessor(pTrailerNode, nullptr));
              XFA_ItemLayoutProcessor_InsertFlowedItem(
                  this, pTempProcessor.get(), bContainerWidthAutoSize,
                  bContainerHeightAutoSize, fContainerHeight, eFlowStrategy,
                  uCurHAlignState, rgCurLineLayoutItems, false,
                  XFA_LAYOUT_FLOAT_MAX, XFA_LAYOUT_FLOAT_MAX, fContentCurRowY,
                  fContentWidthLimit, fContentCurRowAvailWidth,
                  fContentCurRowHeight, bAddedItemInRow, bForceEndPage,
                  pContext);
            }
            if (!bCreatePage) {
              if (JudgeLeaderOrTrailerForOccur(pLeaderNode)) {
                CalculateRowChildPosition(
                    rgCurLineLayoutItems, eFlowStrategy,
                    bContainerHeightAutoSize, bContainerWidthAutoSize,
                    fContentCalculatedWidth, fContentCalculatedHeight,
                    fContentCurRowY, fContentCurRowHeight, fContentWidthLimit);
                rgCurLineLayoutItems->RemoveAll();
                std::unique_ptr<CXFA_ItemLayoutProcessor> pTempProcessor(
                    new CXFA_ItemLayoutProcessor(pLeaderNode, nullptr));
                XFA_ItemLayoutProcessor_InsertFlowedItem(
                    this, pTempProcessor.get(), bContainerWidthAutoSize,
                    bContainerHeightAutoSize, fContainerHeight, eFlowStrategy,
                    uCurHAlignState, rgCurLineLayoutItems, false,
                    XFA_LAYOUT_FLOAT_MAX, XFA_LAYOUT_FLOAT_MAX, fContentCurRowY,
                    fContentWidthLimit, fContentCurRowAvailWidth,
                    fContentCurRowHeight, bAddedItemInRow, bForceEndPage,
                    pContext);
              }
            } else {
              if (JudgeLeaderOrTrailerForOccur(pLeaderNode)) {
                XFA_ItemLayoutProcessor_AddPendingNode(this, pLeaderNode, true);
              }
            }
            XFA_ItemLayoutProcessor_GotoNextContainerNode(
                m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, true);
            if (bCreatePage) {
              bForceEndPage = true;
              bIsManualBreak = true;
              if (m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages_Done) {
                bBreakDone = true;
              }
            }
            goto SuspendAndCreateNewRow;
          }
        } break;
        case XFA_ItemLayoutProcessorStages_BookendLeader: {
          CXFA_Node* pLeaderNode = nullptr;
          if (m_pCurChildPreprocessor) {
            pProcessor = m_pCurChildPreprocessor;
            m_pCurChildPreprocessor = nullptr;
          } else if (m_pPageMgr &&
                     m_pPageMgr->ProcessBookendLeaderOrTrailer(
                         m_pCurChildNode, true, pLeaderNode)) {
            pProcessor = new CXFA_ItemLayoutProcessor(pLeaderNode, m_pPageMgr);
          }
          if (pProcessor) {
            if (XFA_ItemLayoutProcessor_InsertFlowedItem(
                    this, pProcessor, bContainerWidthAutoSize,
                    bContainerHeightAutoSize, fContainerHeight, eFlowStrategy,
                    uCurHAlignState, rgCurLineLayoutItems, bUseBreakControl,
                    fAvailHeight, fRealHeight, fContentCurRowY,
                    fContentWidthLimit, fContentCurRowAvailWidth,
                    fContentCurRowHeight, bAddedItemInRow, bForceEndPage,
                    pContext) != XFA_ItemLayoutProcessorResult_Done) {
              goto SuspendAndCreateNewRow;
            } else {
              delete pProcessor;
              pProcessor = nullptr;
            }
          }
        } break;
        case XFA_ItemLayoutProcessorStages_BookendTrailer: {
          CXFA_Node* pTrailerNode = nullptr;
          if (m_pCurChildPreprocessor) {
            pProcessor = m_pCurChildPreprocessor;
            m_pCurChildPreprocessor = nullptr;
          } else if (m_pPageMgr &&
                     m_pPageMgr->ProcessBookendLeaderOrTrailer(
                         m_pCurChildNode, false, pTrailerNode)) {
            pProcessor = new CXFA_ItemLayoutProcessor(pTrailerNode, m_pPageMgr);
          }
          if (pProcessor) {
            if (XFA_ItemLayoutProcessor_InsertFlowedItem(
                    this, pProcessor, bContainerWidthAutoSize,
                    bContainerHeightAutoSize, fContainerHeight, eFlowStrategy,
                    uCurHAlignState, rgCurLineLayoutItems, bUseBreakControl,
                    fAvailHeight, fRealHeight, fContentCurRowY,
                    fContentWidthLimit, fContentCurRowAvailWidth,
                    fContentCurRowHeight, bAddedItemInRow, bForceEndPage,
                    pContext) != XFA_ItemLayoutProcessorResult_Done) {
              goto SuspendAndCreateNewRow;
            } else {
              delete pProcessor;
              pProcessor = nullptr;
            }
          }
        } break;
        case XFA_ItemLayoutProcessorStages_Container:
          ASSERT(m_pCurChildNode->IsContainerNode());
          if (m_pCurChildNode->GetElementType() == XFA_Element::Variables) {
            break;
          }
          if (fContentCurRowY >= fHeightLimit + XFA_LAYOUT_FLOAT_PERCISION &&
              XFA_ItemLayoutProcessor_IsTakingSpace(m_pCurChildNode)) {
            bForceEndPage = true;
            goto SuspendAndCreateNewRow;
          }
          if (m_pCurChildNode->IsContainerNode()) {
            bool bNewRow = false;
            if (m_pCurChildPreprocessor) {
              pProcessor = m_pCurChildPreprocessor;
              m_pCurChildPreprocessor = nullptr;
              bNewRow = true;
            } else {
              pProcessor =
                  new CXFA_ItemLayoutProcessor(m_pCurChildNode, m_pPageMgr);
            }
            XFA_ItemLayoutProcessor_InsertPendingItems(pProcessor,
                                                       m_pCurChildNode);
            XFA_ItemLayoutProcessorResult rs =
                XFA_ItemLayoutProcessor_InsertFlowedItem(
                    this, pProcessor, bContainerWidthAutoSize,
                    bContainerHeightAutoSize, fContainerHeight, eFlowStrategy,
                    uCurHAlignState, rgCurLineLayoutItems, bUseBreakControl,
                    fAvailHeight, fRealHeight, fContentCurRowY,
                    fContentWidthLimit, fContentCurRowAvailWidth,
                    fContentCurRowHeight, bAddedItemInRow, bForceEndPage,
                    pContext, bNewRow);
            switch (rs) {
              case XFA_ItemLayoutProcessorResult_ManualBreak:
                bIsManualBreak = true;
              case XFA_ItemLayoutProcessorResult_PageFullBreak:
                bForceEndPage = true;
              case XFA_ItemLayoutProcessorResult_RowFullBreak:
                goto SuspendAndCreateNewRow;
              case XFA_ItemLayoutProcessorResult_Done:
              default:
                fContentCurRowY += XFA_ItemLayoutProcessor_InsertPendingItems(
                    pProcessor, m_pCurChildNode);
                delete pProcessor;
                pProcessor = nullptr;
            }
          }
          break;
        case XFA_ItemLayoutProcessorStages_Done:
          break;
        default:
          break;
      }
      XFA_ItemLayoutProcessor_GotoNextContainerNode(
          m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, true);
      if (bAddedItemInRow && eFlowStrategy == XFA_ATTRIBUTEENUM_Tb) {
        break;
      } else {
        continue;
      }
    SuspendAndCreateNewRow:
      if (pProcessor) {
        m_pCurChildPreprocessor = pProcessor;
      }
      break;
    }
    CalculateRowChildPosition(rgCurLineLayoutItems, eFlowStrategy,
                              bContainerHeightAutoSize, bContainerWidthAutoSize,
                              fContentCalculatedWidth, fContentCalculatedHeight,
                              fContentCurRowY, fContentCurRowHeight,
                              fContentWidthLimit, bRootForceTb);
    m_fWidthLimite = fContentCurRowAvailWidth;
    if (bForceEndPage) {
      break;
    }
  }
  bool bRetValue = m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages_Done &&
                   m_PendingNodes.empty();
  if (bBreakDone) {
    bRetValue = false;
  }
  XFA_ItemLayoutProcessor_CalculateContainerComponentSizeFromContentSize(
      m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth,
      fContainerWidth, bContainerHeightAutoSize, fContentCalculatedHeight,
      fContainerHeight);
  if (fContainerHeight >= XFA_LAYOUT_FLOAT_PERCISION || m_pLayoutItem ||
      bRetValue) {
    if (!m_pLayoutItem) {
      m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
    }
    if (fContainerHeight < 0) {
      fContainerHeight = 0;
    }
    SetCurrentComponentSize(fContainerWidth, fContainerHeight);
    if (bForceEndPage) {
      m_fUsedSize = 0;
    } else {
      m_fUsedSize += m_pLayoutItem->m_sSize.y;
    }
  }
  return bRetValue
             ? XFA_ItemLayoutProcessorResult_Done
             : (bIsManualBreak ? XFA_ItemLayoutProcessorResult_ManualBreak
                               : XFA_ItemLayoutProcessorResult_PageFullBreak);
}

bool CXFA_ItemLayoutProcessor::CalculateRowChildPosition(
    CFX_ArrayTemplate<CXFA_ContentLayoutItem*> (&rgCurLineLayoutItems)[3],
    XFA_ATTRIBUTEENUM eFlowStrategy,
    bool bContainerHeightAutoSize,
    bool bContainerWidthAutoSize,
    FX_FLOAT& fContentCalculatedWidth,
    FX_FLOAT& fContentCalculatedHeight,
    FX_FLOAT& fContentCurRowY,
    FX_FLOAT fContentCurRowHeight,
    FX_FLOAT fContentWidthLimit,
    bool bRootForceTb) {
  int32_t nGroupLengths[3] = {0, 0, 0};
  FX_FLOAT fGroupWidths[3] = {0, 0, 0};
  int32_t nTotalLength = 0;
  for (int32_t i = 0; i < 3; i++) {
    nGroupLengths[i] = rgCurLineLayoutItems[i].GetSize();
    for (int32_t c = nGroupLengths[i], j = 0; j < c; j++) {
      nTotalLength++;
      if (XFA_ItemLayoutProcessor_IsTakingSpace(
              rgCurLineLayoutItems[i][j]->m_pFormNode)) {
        fGroupWidths[i] += rgCurLineLayoutItems[i][j]->m_sSize.x;
      }
    }
  }
  if (!nTotalLength) {
    if (bContainerHeightAutoSize) {
      FX_FLOAT fNewHeight = fContentCurRowY;
      if (fContentCalculatedHeight > fNewHeight) {
        fContentCalculatedHeight = fNewHeight;
      }
    }
    return false;
  }
  if (!m_pLayoutItem) {
    m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
  }
  if (eFlowStrategy != XFA_ATTRIBUTEENUM_Rl_tb) {
    FX_FLOAT fCurPos;
    fCurPos = 0;
    for (int32_t c = nGroupLengths[0], j = 0; j < c; j++) {
      if (bRootForceTb) {
        FX_FLOAT fAbsoluteX, fAbsoluteY;
        CalculatePositionedContainerPos(rgCurLineLayoutItems[0][j]->m_pFormNode,
                                        rgCurLineLayoutItems[0][j]->m_sSize.x,
                                        rgCurLineLayoutItems[0][j]->m_sSize.y,
                                        fAbsoluteX, fAbsoluteY);
        rgCurLineLayoutItems[0][j]->m_sPos = CFX_PointF(fAbsoluteX, fAbsoluteY);
      } else {
        rgCurLineLayoutItems[0][j]->m_sPos =
            CFX_PointF(fCurPos, fContentCurRowY);
        if (XFA_ItemLayoutProcessor_IsTakingSpace(
                rgCurLineLayoutItems[0][j]->m_pFormNode)) {
          fCurPos += rgCurLineLayoutItems[0][j]->m_sSize.x;
        }
      }
      m_pLayoutItem->AddChild(rgCurLineLayoutItems[0][j]);
      m_fLastRowWidth = fCurPos;
    }
    fCurPos = (fContentWidthLimit + fGroupWidths[0] - fGroupWidths[1] -
               fGroupWidths[2]) /
              2;
    for (int32_t c = nGroupLengths[1], j = 0; j < c; j++) {
      if (bRootForceTb) {
        FX_FLOAT fAbsoluteX, fAbsoluteY;
        CalculatePositionedContainerPos(rgCurLineLayoutItems[1][j]->m_pFormNode,
                                        rgCurLineLayoutItems[1][j]->m_sSize.x,
                                        rgCurLineLayoutItems[1][j]->m_sSize.y,
                                        fAbsoluteX, fAbsoluteY);
        rgCurLineLayoutItems[1][j]->m_sPos = CFX_PointF(fAbsoluteX, fAbsoluteY);
      } else {
        rgCurLineLayoutItems[1][j]->m_sPos =
            CFX_PointF(fCurPos, fContentCurRowY);
        if (XFA_ItemLayoutProcessor_IsTakingSpace(
                rgCurLineLayoutItems[1][j]->m_pFormNode)) {
          fCurPos += rgCurLineLayoutItems[1][j]->m_sSize.x;
        }
      }
      m_pLayoutItem->AddChild(rgCurLineLayoutItems[1][j]);
      m_fLastRowWidth = fCurPos;
    }
    fCurPos = fContentWidthLimit - fGroupWidths[2];
    for (int32_t c = nGroupLengths[2], j = 0; j < c; j++) {
      if (bRootForceTb) {
        FX_FLOAT fAbsoluteX, fAbsoluteY;
        CalculatePositionedContainerPos(rgCurLineLayoutItems[2][j]->m_pFormNode,
                                        rgCurLineLayoutItems[2][j]->m_sSize.x,
                                        rgCurLineLayoutItems[2][j]->m_sSize.y,
                                        fAbsoluteX, fAbsoluteY);
        rgCurLineLayoutItems[2][j]->m_sPos = CFX_PointF(fAbsoluteX, fAbsoluteY);
      } else {
        rgCurLineLayoutItems[2][j]->m_sPos =
            CFX_PointF(fCurPos, fContentCurRowY);
        if (XFA_ItemLayoutProcessor_IsTakingSpace(
                rgCurLineLayoutItems[2][j]->m_pFormNode)) {
          fCurPos += rgCurLineLayoutItems[2][j]->m_sSize.x;
        }
      }
      m_pLayoutItem->AddChild(rgCurLineLayoutItems[2][j]);
      m_fLastRowWidth = fCurPos;
    }
  } else {
    FX_FLOAT fCurPos;
    fCurPos = fGroupWidths[0];
    for (int32_t c = nGroupLengths[0], j = 0; j < c; j++) {
      if (XFA_ItemLayoutProcessor_IsTakingSpace(
              rgCurLineLayoutItems[0][j]->m_pFormNode)) {
        fCurPos -= rgCurLineLayoutItems[0][j]->m_sSize.x;
      }
      rgCurLineLayoutItems[0][j]->m_sPos = CFX_PointF(fCurPos, fContentCurRowY);
      m_pLayoutItem->AddChild(rgCurLineLayoutItems[0][j]);
      m_fLastRowWidth = fCurPos;
    }
    fCurPos = (fContentWidthLimit + fGroupWidths[0] + fGroupWidths[1] -
               fGroupWidths[2]) /
              2;
    for (int32_t c = nGroupLengths[1], j = 0; j < c; j++) {
      if (XFA_ItemLayoutProcessor_IsTakingSpace(
              rgCurLineLayoutItems[1][j]->m_pFormNode)) {
        fCurPos -= rgCurLineLayoutItems[1][j]->m_sSize.x;
      }
      rgCurLineLayoutItems[1][j]->m_sPos = CFX_PointF(fCurPos, fContentCurRowY);
      m_pLayoutItem->AddChild(rgCurLineLayoutItems[1][j]);
      m_fLastRowWidth = fCurPos;
    }
    fCurPos = fContentWidthLimit;
    for (int32_t c = nGroupLengths[2], j = 0; j < c; j++) {
      if (XFA_ItemLayoutProcessor_IsTakingSpace(
              rgCurLineLayoutItems[2][j]->m_pFormNode)) {
        fCurPos -= rgCurLineLayoutItems[2][j]->m_sSize.x;
      }
      rgCurLineLayoutItems[2][j]->m_sPos = CFX_PointF(fCurPos, fContentCurRowY);
      m_pLayoutItem->AddChild(rgCurLineLayoutItems[2][j]);
      m_fLastRowWidth = fCurPos;
    }
  }
  m_fLastRowY = fContentCurRowY;
  fContentCurRowY += fContentCurRowHeight;
  if (bContainerWidthAutoSize) {
    FX_FLOAT fChildSuppliedWidth = fGroupWidths[0];
    if (fContentWidthLimit < XFA_LAYOUT_FLOAT_MAX &&
        fContentWidthLimit > fChildSuppliedWidth) {
      fChildSuppliedWidth = fContentWidthLimit;
    }
    if (fContentCalculatedWidth < fChildSuppliedWidth) {
      fContentCalculatedWidth = fChildSuppliedWidth;
    }
  }
  if (bContainerHeightAutoSize) {
    FX_FLOAT fChildSuppliedHeight = fContentCurRowY;
    if (fContentCalculatedHeight < fChildSuppliedHeight) {
      fContentCalculatedHeight = fChildSuppliedHeight;
    }
  }
  return true;
}
CXFA_Node* CXFA_ItemLayoutProcessor::GetSubformSetParent(
    CXFA_Node* pSubformSet) {
  if (pSubformSet && pSubformSet->GetElementType() == XFA_Element::SubformSet) {
    CXFA_Node* pParent = pSubformSet->GetNodeItem(XFA_NODEITEM_Parent);
    while (pParent) {
      if (pParent->GetElementType() != XFA_Element::SubformSet) {
        return pParent;
      }
      pParent = pParent->GetNodeItem(XFA_NODEITEM_Parent);
    }
  }
  return pSubformSet;
}
void CXFA_ItemLayoutProcessor::DoLayoutField() {
  if (m_pLayoutItem)
    return;

  ASSERT(m_pCurChildNode == XFA_LAYOUT_INVALIDNODE);
  m_pLayoutItem = CreateContentLayoutItem(m_pFormNode);
  if (!m_pLayoutItem) {
    return;
  }
  CXFA_Document* pDocument = m_pFormNode->GetDocument();
  CXFA_FFNotify* pNotify = pDocument->GetNotify();
  FX_FLOAT fHeight = -1;
  FX_FLOAT fWidth = -1;
  pNotify->StartFieldDrawLayout(m_pFormNode, fWidth, fHeight);
  int32_t nRotate =
      FXSYS_round(m_pFormNode->GetMeasure(XFA_ATTRIBUTE_Rotate).GetValue());
  nRotate = XFA_MapRotation(nRotate);
  if (nRotate == 90 || nRotate == 270) {
    FX_FLOAT fTmp = fWidth;
    fWidth = fHeight;
    fHeight = fTmp;
  }
  SetCurrentComponentSize(fWidth, fHeight);
}
XFA_ItemLayoutProcessorResult CXFA_ItemLayoutProcessor::DoLayout(
    bool bUseBreakControl,
    FX_FLOAT fHeightLimit,
    FX_FLOAT fRealHeight,
    CXFA_LayoutContext* pContext) {
  switch (m_pFormNode->GetElementType()) {
    case XFA_Element::Subform:
    case XFA_Element::Area:
    case XFA_Element::ExclGroup:
    case XFA_Element::SubformSet: {
      bool bRootForceTb = false;
      CXFA_Node* pLayoutNode = GetSubformSetParent(m_pFormNode);
      XFA_ATTRIBUTEENUM eLayoutStrategy =
          XFA_ItemLayoutProcessor_GetLayout(pLayoutNode, bRootForceTb);
      switch (eLayoutStrategy) {
        case XFA_ATTRIBUTEENUM_Tb:
        case XFA_ATTRIBUTEENUM_Lr_tb:
        case XFA_ATTRIBUTEENUM_Rl_tb:
          return DoLayoutFlowedContainer(bUseBreakControl, eLayoutStrategy,
                                         fHeightLimit, fRealHeight, pContext,
                                         bRootForceTb);
        case XFA_ATTRIBUTEENUM_Position:
        case XFA_ATTRIBUTEENUM_Row:
        case XFA_ATTRIBUTEENUM_Rl_row:
        default:
          DoLayoutPositionedContainer(pContext);
          m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages_Done;
          return XFA_ItemLayoutProcessorResult_Done;
        case XFA_ATTRIBUTEENUM_Table:
          DoLayoutTableContainer(pLayoutNode);
          m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages_Done;
          return XFA_ItemLayoutProcessorResult_Done;
      }
    }
    case XFA_Element::Draw:
    case XFA_Element::Field:
      DoLayoutField();
      m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages_Done;
      return XFA_ItemLayoutProcessorResult_Done;
    case XFA_Element::ContentArea:
      return XFA_ItemLayoutProcessorResult_Done;
    default:
      return XFA_ItemLayoutProcessorResult_Done;
  }
}
void CXFA_ItemLayoutProcessor::GetCurrentComponentPos(FX_FLOAT& fAbsoluteX,
                                                      FX_FLOAT& fAbsoluteY) {
  ASSERT(m_pLayoutItem);
  fAbsoluteX = m_pLayoutItem->m_sPos.x;
  fAbsoluteY = m_pLayoutItem->m_sPos.y;
}
void CXFA_ItemLayoutProcessor::GetCurrentComponentSize(FX_FLOAT& fWidth,
                                                       FX_FLOAT& fHeight) {
  ASSERT(m_pLayoutItem);
  fWidth = m_pLayoutItem->m_sSize.x;
  fHeight = m_pLayoutItem->m_sSize.y;
}
void CXFA_ItemLayoutProcessor::SetCurrentComponentPos(FX_FLOAT fAbsoluteX,
                                                      FX_FLOAT fAbsoluteY) {
  m_pLayoutItem->m_sPos = CFX_PointF(fAbsoluteX, fAbsoluteY);
}
void CXFA_ItemLayoutProcessor::SetCurrentComponentSize(FX_FLOAT fWidth,
                                                       FX_FLOAT fHeight) {
  m_pLayoutItem->m_sSize = CFX_SizeF(fWidth, fHeight);
}

bool CXFA_ItemLayoutProcessor::JudgeLeaderOrTrailerForOccur(
    CXFA_Node* pFormNode) {
  if (!pFormNode)
    return false;

  CXFA_Node* pTemplate = pFormNode->GetTemplateNode();
  if (!pTemplate)
    pTemplate = pFormNode;

  CXFA_Occur NodeOccur(pTemplate->GetFirstChildByClass(XFA_Element::Occur));
  int32_t iMax = NodeOccur.GetMax();
  if (iMax < 0)
    return true;

  int32_t iCount = m_PendingNodesCount[pTemplate];
  if (iCount >= iMax)
    return false;

  m_PendingNodesCount[pTemplate] = iCount + 1;
  return true;
}
