diff options
Diffstat (limited to 'xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp')
-rw-r--r-- | xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp | 2792 |
1 files changed, 2792 insertions, 0 deletions
diff --git a/xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp b/xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp new file mode 100644 index 0000000000..50be211bb6 --- /dev/null +++ b/xfa/fxfa/parser/cxfa_itemlayoutprocessor.cpp @@ -0,0 +1,2792 @@ +// 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/cxfa_itemlayoutprocessor.h" + +#include <algorithm> +#include <memory> +#include <utility> +#include <vector> + +#include "third_party/base/ptr_util.h" +#include "third_party/base/stl_util.h" +#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_layoutcontext.h" +#include "xfa/fxfa/parser/cxfa_layoutpagemgr.h" +#include "xfa/fxfa/parser/cxfa_localemgr.h" +#include "xfa/fxfa/parser/cxfa_measurement.h" +#include "xfa/fxfa/parser/cxfa_occur.h" +#include "xfa/fxfa/parser/xfa_object.h" +#include "xfa/fxfa/parser/xfa_utils.h" + +namespace { + +std::vector<CFX_WideString> SeparateStringW(const wchar_t* pStr, + int32_t iStrLen, + wchar_t delimiter) { + std::vector<CFX_WideString> ret; + if (!pStr) + return ret; + if (iStrLen < 0) + iStrLen = FXSYS_wcslen(pStr); + + const wchar_t* pToken = pStr; + const wchar_t* pEnd = pStr + iStrLen; + while (true) { + if (pStr >= pEnd || delimiter == *pStr) { + ret.push_back(CFX_WideString(pToken, pStr - pToken)); + pToken = pStr + 1; + if (pStr >= pEnd) + break; + } + pStr++; + } + return ret; +} + +void UpdateWidgetSize(CXFA_ContentLayoutItem* pLayoutItem, + float* fWidth, + float* fHeight) { + CXFA_Node* pNode = pLayoutItem->m_pFormNode; + 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.width; + if (*fHeight < -XFA_LAYOUT_FLOAT_PERCISION) + *fHeight = pLayoutItem->m_sSize.height; + break; + } + case XFA_Element::Draw: + case XFA_Element::Field: { + pNode->GetDocument()->GetNotify()->StartFieldDrawLayout(pNode, *fWidth, + *fHeight); + break; + } + default: + ASSERT(false); + } +} + +CFX_SizeF CalculateContainerSpecifiedSize(CXFA_Node* pFormNode, + bool* bContainerWidthAutoSize, + bool* bContainerHeightAutoSize) { + *bContainerWidthAutoSize = true; + *bContainerHeightAutoSize = true; + + XFA_Element eType = pFormNode->GetElementType(); + CXFA_Measurement mTmpValue; + CFX_SizeF containerSize; + if ((eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup) && + pFormNode->TryMeasure(XFA_ATTRIBUTE_W, mTmpValue, false) && + mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) { + containerSize.width = mTmpValue.ToUnit(XFA_UNIT_Pt); + *bContainerWidthAutoSize = false; + } + if ((eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup) && + pFormNode->TryMeasure(XFA_ATTRIBUTE_H, mTmpValue, false) && + mTmpValue.GetValue() > XFA_LAYOUT_FLOAT_PERCISION) { + containerSize.height = 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) { + containerSize.width = 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) { + containerSize.height = mTmpValue.ToUnit(XFA_UNIT_Pt); + *bContainerHeightAutoSize = false; + } + return containerSize; +} + +CFX_SizeF CalculateContainerComponentSizeFromContentSize( + CXFA_Node* pFormNode, + bool bContainerWidthAutoSize, + float fContentCalculatedWidth, + bool bContainerHeightAutoSize, + float fContentCalculatedHeight, + const CFX_SizeF& currentContainerSize) { + CFX_SizeF componentSize = currentContainerSize; + CXFA_Node* pMarginNode = pFormNode->GetFirstChildByClass(XFA_Element::Margin); + CXFA_Measurement mTmpValue; + if (bContainerWidthAutoSize) { + componentSize.width = fContentCalculatedWidth; + if (pMarginNode) { + if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_LeftInset, mTmpValue, false)) + componentSize.width += mTmpValue.ToUnit(XFA_UNIT_Pt); + if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_RightInset, mTmpValue, false)) + componentSize.width += mTmpValue.ToUnit(XFA_UNIT_Pt); + } + } + + if (bContainerHeightAutoSize) { + componentSize.height = fContentCalculatedHeight; + if (pMarginNode) { + if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_TopInset, mTmpValue, false)) + componentSize.height += mTmpValue.ToUnit(XFA_UNIT_Pt); + if (pMarginNode->TryMeasure(XFA_ATTRIBUTE_BottomInset, mTmpValue, + false)) { + componentSize.height += mTmpValue.ToUnit(XFA_UNIT_Pt); + } + } + } + return componentSize; +} + +void RelocateTableRowCells(CXFA_ContentLayoutItem* pLayoutRow, + const std::vector<float>& rgSpecifiedColumnWidths, + XFA_ATTRIBUTEENUM eLayout) { + bool bContainerWidthAutoSize = true; + bool bContainerHeightAutoSize = true; + CFX_SizeF containerSize = CalculateContainerSpecifiedSize( + pLayoutRow->m_pFormNode, &bContainerWidthAutoSize, + &bContainerHeightAutoSize); + CXFA_Node* pMarginNode = + pLayoutRow->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin); + float fLeftInset = 0; + float fTopInset = 0; + float fRightInset = 0; + float 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); + } + + float fContentWidthLimit = + bContainerWidthAutoSize ? FLT_MAX + : containerSize.width - fLeftInset - fRightInset; + float fContentCurrentHeight = + pLayoutRow->m_sSize.height - fTopInset - fBottomInset; + float fContentCalculatedWidth = 0; + float fContentCalculatedHeight = 0; + float fCurrentColX = 0; + int32_t nCurrentColIdx = 0; + bool bMetWholeRowCell = false; + + for (auto* pLayoutChild = + static_cast<CXFA_ContentLayoutItem*>(pLayoutRow->m_pFirstChild); + pLayoutChild; pLayoutChild = static_cast<CXFA_ContentLayoutItem*>( + pLayoutChild->m_pNextSibling)) { + int32_t nOriginalColSpan = + pLayoutChild->m_pFormNode->GetInteger(XFA_ATTRIBUTE_ColSpan); + int32_t nColSpan = nOriginalColSpan; + float fColSpanWidth = 0; + if (nColSpan == -1 || + nCurrentColIdx + nColSpan > + pdfium::CollectionSize<int32_t>(rgSpecifiedColumnWidths)) { + nColSpan = pdfium::CollectionSize<int32_t>(rgSpecifiedColumnWidths) - + 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.height); + } + if (nOriginalColSpan == -1) + bMetWholeRowCell = true; + + pLayoutChild->m_sPos = CFX_PointF(fCurrentColX, 0); + pLayoutChild->m_sSize.width = fColSpanWidth; + if (!XFA_ItemLayoutProcessor_IsTakingSpace(pLayoutChild->m_pFormNode)) + continue; + + fCurrentColX += fColSpanWidth; + nCurrentColIdx += nColSpan; + float fNewHeight = bContainerHeightAutoSize ? -1 : fContentCurrentHeight; + UpdateWidgetSize(pLayoutChild, &fColSpanWidth, &fNewHeight); + pLayoutChild->m_sSize.height = fNewHeight; + if (bContainerHeightAutoSize) { + fContentCalculatedHeight = + std::max(fContentCalculatedHeight, pLayoutChild->m_sSize.height); + } + } + + if (bContainerHeightAutoSize) { + for (CXFA_ContentLayoutItem* pLayoutChild = + (CXFA_ContentLayoutItem*)pLayoutRow->m_pFirstChild; + pLayoutChild; + pLayoutChild = (CXFA_ContentLayoutItem*)pLayoutChild->m_pNextSibling) { + UpdateWidgetSize(pLayoutChild, &pLayoutChild->m_sSize.width, + &fContentCalculatedHeight); + float fOldChildHeight = pLayoutChild->m_sSize.height; + pLayoutChild->m_sSize.height = fContentCalculatedHeight; + CXFA_Node* pParaNode = + pLayoutChild->m_pFormNode->GetFirstChildByClass(XFA_Element::Para); + if (pParaNode && pLayoutChild->m_pFirstChild) { + 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) { + float fChildSuppliedWidth = fCurrentColX; + if (fContentWidthLimit < FLT_MAX && + fContentWidthLimit > fChildSuppliedWidth) { + fChildSuppliedWidth = fContentWidthLimit; + } + fContentCalculatedWidth = + std::max(fContentCalculatedWidth, fChildSuppliedWidth); + } else { + fContentCalculatedWidth = containerSize.width - 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.width; + } + } + pLayoutRow->m_sSize = CalculateContainerComponentSizeFromContentSize( + pLayoutRow->m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth, + bContainerHeightAutoSize, fContentCalculatedHeight, containerSize); +} + +void UpdatePendingItemLayout(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: + RelocateTableRowCells(pLayoutItem, pProcessor->m_rgSpecifiedColumnWidths, + eLayout); + break; + default: + break; + } +} + +void AddTrailerBeforeSplit(CXFA_ItemLayoutProcessor* pProcessor, + float fSplitPos, + CXFA_ContentLayoutItem* pTrailerLayoutItem, + bool bUseInherited) { + if (!pTrailerLayoutItem) + return; + + float fHeight = pTrailerLayoutItem->m_sSize.height; + if (bUseInherited) { + 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; + } + + UpdatePendingItemLayout(pProcessor, pTrailerLayoutItem); + CXFA_Node* pMarginNode = + pProcessor->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin); + float fLeftInset = 0; + float fTopInset = 0; + float fRightInset = 0; + float 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.width += + pTrailerLayoutItem->m_sSize.width; + pProcessor->m_pLayoutItem->AddChild(pTrailerLayoutItem); + return; + } + + 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_Right: + pTrailerLayoutItem->m_sPos.x = pProcessor->m_pLayoutItem->m_sSize.width - + fRightInset - + pTrailerLayoutItem->m_sSize.width; + break; + case XFA_ATTRIBUTEENUM_Center: + pTrailerLayoutItem->m_sPos.x = + (pProcessor->m_pLayoutItem->m_sSize.width - fLeftInset - fRightInset - + pTrailerLayoutItem->m_sSize.width) / + 2; + break; + case XFA_ATTRIBUTEENUM_Left: + default: + pTrailerLayoutItem->m_sPos.x = fLeftInset; + break; + } + pProcessor->m_pLayoutItem->m_sSize.height += fHeight; + pProcessor->m_pLayoutItem->AddChild(pTrailerLayoutItem); +} + +void AddLeaderAfterSplit(CXFA_ItemLayoutProcessor* pProcessor, + CXFA_ContentLayoutItem* pLeaderLayoutItem) { + UpdatePendingItemLayout(pProcessor, pLeaderLayoutItem); + + CXFA_Node* pMarginNode = + pProcessor->m_pFormNode->GetFirstChildByClass(XFA_Element::Margin); + float fLeftInset = 0; + 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); + } + + float fHeight = pLeaderLayoutItem->m_sSize.height; + 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_Right: + pLeaderLayoutItem->m_sPos.x = pProcessor->m_pLayoutItem->m_sSize.width - + fRightInset - + pLeaderLayoutItem->m_sSize.width; + break; + case XFA_ATTRIBUTEENUM_Center: + pLeaderLayoutItem->m_sPos.x = + (pProcessor->m_pLayoutItem->m_sSize.width - fLeftInset - fRightInset - + pLeaderLayoutItem->m_sSize.width) / + 2; + break; + case XFA_ATTRIBUTEENUM_Left: + default: + pLeaderLayoutItem->m_sPos.x = fLeftInset; + break; + } + pProcessor->m_pLayoutItem->m_sSize.height += fHeight; + pProcessor->m_pLayoutItem->AddChild(pLeaderLayoutItem); +} + +void AddPendingNode(CXFA_ItemLayoutProcessor* pProcessor, + CXFA_Node* pPendingNode, + bool bBreakPending) { + pProcessor->m_PendingNodes.push_back(pPendingNode); + pProcessor->m_bBreakPending = bBreakPending; +} + +float InsertPendingItems(CXFA_ItemLayoutProcessor* pProcessor, + CXFA_Node* pCurChildNode) { + 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()) { + auto pPendingProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>( + pProcessor->m_PendingNodes.front(), nullptr); + pProcessor->m_PendingNodes.pop_front(); + pPendingProcessor->DoLayout(false, FLT_MAX, FLT_MAX, nullptr); + CXFA_ContentLayoutItem* pPendingLayoutItem = + pPendingProcessor->HasLayoutItem() + ? pPendingProcessor->ExtractLayoutItem() + : nullptr; + if (pPendingLayoutItem) { + AddLeaderAfterSplit(pProcessor, pPendingLayoutItem); + if (pProcessor->m_bBreakPending) + fTotalHeight += pPendingLayoutItem->m_sSize.height; + } + } + return fTotalHeight; +} + +XFA_ATTRIBUTEENUM 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; +} + +bool 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_ATTRIBUTE eKeepType = XFA_ATTRIBUTE_Next; + if (!bPreFind) + eKeepType = XFA_ATTRIBUTE_Previous; + + XFA_ATTRIBUTEENUM eNext; + if (!pKeep->TryEnum(eKeepType, eNext, false)) + return false; + if (eNext == XFA_ATTRIBUTEENUM_ContentArea || + eNext == XFA_ATTRIBUTEENUM_PageArea) { + return true; + } + return false; +} + +bool 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; +} + +void 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); +} + +uint8_t 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; + } +} + +XFA_ItemLayoutProcessorResult InsertFlowedItem( + CXFA_ItemLayoutProcessor* pThis, + CXFA_ItemLayoutProcessor* pProcessor, + bool bContainerWidthAutoSize, + bool bContainerHeightAutoSize, + float fContainerHeight, + XFA_ATTRIBUTEENUM eFlowStrategy, + uint8_t* uCurHAlignState, + std::vector<CXFA_ContentLayoutItem*> (&rgCurLineLayoutItems)[3], + bool bUseBreakControl, + float fAvailHeight, + float fRealHeight, + float fContentWidthLimit, + float* fContentCurRowY, + float* fContentCurRowAvailWidth, + float* fContentCurRowHeight, + bool* bAddedItemInRow, + bool* bForceEndPage, + CXFA_LayoutContext* pLayoutContext, + bool bNewRow) { + bool bTakeSpace = + XFA_ItemLayoutProcessor_IsTakingSpace(pProcessor->m_pFormNode); + uint8_t uHAlign = + 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 bIsOwnSplit = + pProcessor->m_pFormNode->GetIntact() == XFA_ATTRIBUTEENUM_None; + bool bUseRealHeight = + bTakeSpace && bContainerHeightAutoSize && bIsOwnSplit && + pProcessor->m_pFormNode->GetNodeItem(XFA_NODEITEM_Parent)->GetIntact() == + XFA_ATTRIBUTEENUM_None; + bool bIsTransHeight = bTakeSpace; + if (bIsTransHeight && !bIsOwnSplit) { + bool bRootForceTb = false; + XFA_ATTRIBUTEENUM eLayoutStrategy = + 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 : FLT_MAX, + bIsTransHeight ? fRealHeight - *fContentCurRowY : FLT_MAX, + pLayoutContext); + pProcessor->m_ePreProcessRs = eRetValue; + } else { + eRetValue = pProcessor->m_ePreProcessRs; + pProcessor->m_ePreProcessRs = XFA_ItemLayoutProcessorResult::Done; + } + if (pProcessor->HasLayoutItem() == false) + return eRetValue; + + CFX_SizeF childSize = pProcessor->GetCurrentComponentSize(); + if (bUseRealHeight && fRealHeight < XFA_LAYOUT_FLOAT_PERCISION) { + fRealHeight = FLT_MAX; + fAvailHeight = FLT_MAX; + } + if (bTakeSpace && (childSize.width > + *fContentCurRowAvailWidth + XFA_LAYOUT_FLOAT_PERCISION) && + (fContentWidthLimit - *fContentCurRowAvailWidth > + XFA_LAYOUT_FLOAT_PERCISION)) { + return XFA_ItemLayoutProcessorResult::RowFullBreak; + } + + 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) { + auto pOverflowLeaderProcessor = + pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pOverflowTrailerNode, + nullptr); + pOverflowLeaderProcessor->DoLayout(false, FLT_MAX, FLT_MAX, nullptr); + pTrailerLayoutItem = + pOverflowLeaderProcessor->HasLayoutItem() + ? pOverflowLeaderProcessor->ExtractLayoutItem() + : nullptr; + } + + bIsAddTrailerHeight = + bUseInherited + ? pThis->IsAddNewRowForTrailer(pTrailerLayoutItem) + : pProcessor->IsAddNewRowForTrailer(pTrailerLayoutItem); + if (bIsAddTrailerHeight) { + childSize.height += pTrailerLayoutItem->m_sSize.height; + bIsAddTrailerHeight = true; + } + } + } + } + + if (!bTakeSpace || + *fContentCurRowY + childSize.height <= + 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) + AddTrailerBeforeSplit(pProcessor, childSize.height, + pTrailerLayoutItem, false); + if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode)) + AddPendingNode(pProcessor, pOverflowLeaderNode, false); + + pProcessor->m_bUseInheriated = false; + } else { + if (bIsAddTrailerHeight) + childSize.height -= pTrailerLayoutItem->m_sSize.height; + + pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode, + pOverflowTrailerNode, + pTrailerLayoutItem, pFormNode); + } + + CXFA_ContentLayoutItem* pChildLayoutItem = + pProcessor->ExtractLayoutItem(); + if (ExistContainerKeep(pProcessor->m_pFormNode, false) && + pProcessor->m_pFormNode->GetIntact() == XFA_ATTRIBUTEENUM_None) { + pThis->m_arrayKeepItems.push_back(pChildLayoutItem); + } else { + pThis->m_arrayKeepItems.clear(); + } + rgCurLineLayoutItems[uHAlign].push_back(pChildLayoutItem); + *bAddedItemInRow = true; + if (bTakeSpace) { + *fContentCurRowAvailWidth -= childSize.width; + *fContentCurRowHeight = + std::max(*fContentCurRowHeight, childSize.height); + } + return XFA_ItemLayoutProcessorResult::Done; + } + + if (eRetValue == XFA_ItemLayoutProcessorResult::PageFullBreak) { + if (pProcessor->m_bUseInheriated) { + if (pTrailerLayoutItem) { + AddTrailerBeforeSplit(pProcessor, childSize.height, + pTrailerLayoutItem, false); + } + if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode)) + AddPendingNode(pProcessor, pOverflowLeaderNode, false); + + pProcessor->m_bUseInheriated = false; + } else { + if (bIsAddTrailerHeight) + childSize.height -= pTrailerLayoutItem->m_sSize.height; + + pProcessor->ProcessUnUseOverFlow(pOverflowLeaderNode, + pOverflowTrailerNode, + pTrailerLayoutItem, pFormNode); + } + } + rgCurLineLayoutItems[uHAlign].push_back(pProcessor->ExtractLayoutItem()); + *bAddedItemInRow = true; + *fContentCurRowAvailWidth -= childSize.width; + *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height); + return eRetValue; + } + + XFA_ItemLayoutProcessorResult eResult; + if (pThis->ProcessKeepForSplit( + pThis, pProcessor, eRetValue, &rgCurLineLayoutItems[uHAlign], + fContentCurRowAvailWidth, fContentCurRowHeight, fContentCurRowY, + bAddedItemInRow, bForceEndPage, &eResult)) { + return eResult; + } + + *bForceEndPage = true; + 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].push_back(pProcessor->ExtractLayoutItem()); + *bAddedItemInRow = true; + if (bTakeSpace) { + *fContentCurRowAvailWidth -= childSize.width; + *fContentCurRowHeight = + std::max(*fContentCurRowHeight, childSize.height); + } + 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) { + 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)) { + AddPendingNode(pProcessor, pOverflowLeaderNode, false); + } + } + + if (pProcessor->m_pLayoutItem->m_pNextSibling) { + childSize = pProcessor->GetCurrentComponentSize(); + rgCurLineLayoutItems[uHAlign].push_back(pProcessor->ExtractLayoutItem()); + *bAddedItemInRow = true; + if (bTakeSpace) { + *fContentCurRowAvailWidth -= childSize.width; + *fContentCurRowHeight = + std::max(*fContentCurRowHeight, childSize.height); + } + } + return XFA_ItemLayoutProcessorResult::PageFullBreak; + } + + if (*fContentCurRowY <= XFA_LAYOUT_FLOAT_PERCISION) { + childSize = pProcessor->GetCurrentComponentSize(); + if (pProcessor->m_pPageMgr->GetNextAvailContentHeight(childSize.height)) { + 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].push_back(pProcessor->ExtractLayoutItem()); + *bAddedItemInRow = true; + if (bTakeSpace) { + *fContentCurRowAvailWidth -= childSize.width; + *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height); + } + if (eRetValue == XFA_ItemLayoutProcessorResult::Done) + *bForceEndPage = false; + + return eRetValue; + } + + 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) + AddTrailerBeforeSplit(pProcessor, fSplitPos, pTrailerLayoutItem, false); + if (pProcessor->JudgeLeaderOrTrailerForOccur(pOverflowLeaderNode)) + AddPendingNode(pProcessor, pOverflowLeaderNode, false); + + return XFA_ItemLayoutProcessorResult::PageFullBreak; + } + + if (eRetValue != XFA_ItemLayoutProcessorResult::Done) + return XFA_ItemLayoutProcessorResult::PageFullBreak; + + 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; +} + +bool FindLayoutItemSplitPos(CXFA_ContentLayoutItem* pLayoutItem, + float fCurVerticalOffset, + float* fProposedSplitPos, + bool* bAppChange, + bool bCalculateMargin) { + CXFA_Node* pFormNode = pLayoutItem->m_pFormNode; + if (*fProposedSplitPos <= fCurVerticalOffset + XFA_LAYOUT_FLOAT_PERCISION || + *fProposedSplitPos > fCurVerticalOffset + pLayoutItem->m_sSize.height - + XFA_LAYOUT_FLOAT_PERCISION) { + return false; + } + + switch (pFormNode->GetIntact()) { + case XFA_ATTRIBUTEENUM_None: { + bool bAnyChanged = false; + CXFA_Document* pDocument = pFormNode->GetDocument(); + CXFA_FFNotify* pNotify = pDocument->GetNotify(); + 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; + { + 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; + } + } + } + float fRelSplitPos = *fProposedSplitPos - fCurBottomMargin; + for (CXFA_ContentLayoutItem* pChildItem = + (CXFA_ContentLayoutItem*)pLayoutItem->m_pFirstChild; + pChildItem; + pChildItem = (CXFA_ContentLayoutItem*)pChildItem->m_pNextSibling) { + 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; + } + case XFA_ATTRIBUTEENUM_ContentArea: + case XFA_ATTRIBUTEENUM_PageArea: { + *fProposedSplitPos = fCurVerticalOffset; + return true; + } + default: + return false; + } +} + +CFX_PointF CalculatePositionedContainerPos(CXFA_Node* pNode, + const CFX_SizeF& size) { + 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}}; + + CFX_PointF pos(pNode->GetMeasure(XFA_ATTRIBUTE_X).ToUnit(XFA_UNIT_Pt), + 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]; + switch (nAbsoluteAnchorType / 3) { + case 1: + pos.y -= size.height / 2; + break; + case 2: + pos.y -= size.height; + break; + default: + break; + } + switch (nAbsoluteAnchorType % 3) { + case 1: + pos.x -= size.width / 2; + break; + case 2: + pos.x -= size.width; + break; + default: + break; + } + return pos; +} + +} // namespace + +CXFA_ItemLayoutProcessor::CXFA_ItemLayoutProcessor(CXFA_Node* pNode, + CXFA_LayoutPageMgr* pPageMgr) + : m_pFormNode(pNode), + m_pLayoutItem(nullptr), + m_pCurChildNode(XFA_LAYOUT_INVALIDNODE), + m_fUsedSize(0), + m_pPageMgr(pPageMgr), + m_bBreakPending(true), + m_fLastRowWidth(0), + m_fLastRowY(0), + m_bUseInheriated(false), + m_ePreProcessRs(XFA_ItemLayoutProcessorResult::Done), + m_bKeepBreakFinish(false), + m_bIsProcessKeep(false), + m_pKeepHeadNode(nullptr), + m_pKeepTailNode(nullptr), + m_pOldLayoutItem(nullptr), + m_pCurChildPreprocessor(nullptr), + m_nCurChildNodeStage(XFA_ItemLayoutProcessorStages::None), + m_fWidthLimite(0), + 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; +} + +float CXFA_ItemLayoutProcessor::FindSplitPos(float fProposedSplitPos) { + ASSERT(m_pLayoutItem); + XFA_ATTRIBUTEENUM eLayout = m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout); + bool bCalculateMargin = eLayout != XFA_ATTRIBUTEENUM_Position; + 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, + float fSplitPos) { + 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.width = pLayoutItem->m_sSize.width; + pSecondLayoutItem->m_sPos.y = 0; + pSecondLayoutItem->m_sSize.height = pLayoutItem->m_sSize.height - fSplitPos; + pLayoutItem->m_sSize.height -= pSecondLayoutItem->m_sSize.height; + if (pLayoutItem->m_pFirstChild) + pSecondLayoutItem->m_sSize.height += fCurTopMargin; + + if (pSecondParent) { + pSecondParent->AddChild(pSecondLayoutItem); + if (fCurTopMargin > 0 && pLayoutItem->m_pFirstChild) { + pSecondParent->m_sSize.height += fCurTopMargin; + CXFA_ContentLayoutItem* pParentItem = + (CXFA_ContentLayoutItem*)pSecondParent->m_pParent; + while (pParentItem) { + pParentItem->m_sSize.height += 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; + + float lHeightForKeep = 0; + float fAddMarginHeight = 0; + std::vector<CXFA_ContentLayoutItem*> keepLayoutItems; + 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 (!ExistContainerKeep(pChildItem->m_pFormNode, true)) { + pChildItem->m_sPos.y -= fSplitPos - fCurBottomMargin; + pChildItem->m_sPos.y += lHeightForKeep; + pChildItem->m_sPos.y += fAddMarginHeight; + pSecondLayoutItem->AddChild(pChildItem); + continue; + } + if (lHeightForKeep < XFA_LAYOUT_FLOAT_PERCISION) { + for (auto* pPreItem : keepLayoutItems) { + 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.height > lHeightForKeep) { + pPreItem->m_sPos.y = lHeightForKeep; + lHeightForKeep += pPreItem->m_sSize.height; + pSecondLayoutItem->m_sSize.height += pPreItem->m_sSize.height; + if (pSecondParent) + pSecondParent->m_sSize.height += pPreItem->m_sSize.height; + } + pSecondLayoutItem->AddChild(pPreItem); + } + } + pChildItem->m_sPos.y -= fSplitPos; + pChildItem->m_sPos.y += lHeightForKeep; + pChildItem->m_sPos.y += fAddMarginHeight; + pSecondLayoutItem->AddChild(pChildItem); + continue; + } + if (fSplitPos + XFA_LAYOUT_FLOAT_PERCISION >= + fCurTopMargin + fCurBottomMargin + pChildItem->m_sPos.y + + pChildItem->m_sSize.height) { + pLayoutItem->AddChild(pChildItem); + if (ExistContainerKeep(pChildItem->m_pFormNode, false)) + keepLayoutItems.push_back(pChildItem); + else + keepLayoutItems.clear(); + continue; + } + + float fOldHeight = pSecondLayoutItem->m_sSize.height; + SplitLayoutItem( + pChildItem, pSecondLayoutItem, + fSplitPos - fCurTopMargin - fCurBottomMargin - pChildItem->m_sPos.y); + fAddMarginHeight = pSecondLayoutItem->m_sSize.height - fOldHeight; + pLayoutItem->AddChild(pChildItem); + } +} + +void CXFA_ItemLayoutProcessor::SplitLayoutItem(float fSplitPos) { + ASSERT(m_pLayoutItem); + SplitLayoutItem(m_pLayoutItem, nullptr, fSplitPos); +} + +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; +} + +void CXFA_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 && + 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 && + 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 && + FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage, + false)) { + return; + } + } else { + CXFA_Node* pBreakAfterNode = + pCurActionNode->GetNodeItem(XFA_NODEITEM_NextSibling); + if (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()) + DeleteLayoutGeneratedNode(pSaveNode); + } + if (!pNextChildContainer) + goto NoMoreChildContainer; + + bool bLastKeep = false; + if (ProcessKeepNodesForCheckNext(pCurActionNode, nCurStage, + pNextChildContainer, bLastKeep)) { + return; + } + if (!m_bKeepBreakFinish && !bLastKeep && + 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 (ExistContainerKeep(pNextContainer, false)) + bNextKeep = true; + + if (bNextKeep && !bCanSplit) { + if (!m_bIsProcessKeep && !m_bKeepBreakFinish) { + m_pKeepHeadNode = pNextContainer; + m_bIsProcessKeep = true; + } + return false; + } + + if (m_bIsProcessKeep && m_pKeepHeadNode) { + m_pKeepTailNode = pNextContainer; + if (!m_bKeepBreakFinish && + FindBreakNode(pNextContainer->GetNodeItem(XFA_NODEITEM_FirstChild), + pCurActionNode, &nCurStage, true)) { + return true; + } + + 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); + return FindBreakNode(pBreakAfterNode, pCurActionNode, &nCurStage, 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; +} + +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 (GotoNextContainerNode(pCurChildNode, nCurChildNodeStage, pFormNode, + false); + pCurChildNode; GotoNextContainerNode(pCurChildNode, nCurChildNodeStage, + pFormNode, false)) { + if (nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container) + continue; + if (pCurChildNode->GetElementType() == XFA_Element::Variables) + continue; + + auto pProcessor = + pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pCurChildNode, nullptr); + pProcessor->DoLayout(false, FLT_MAX, FLT_MAX, nullptr); + if (!pProcessor->HasLayoutItem()) + continue; + + pProcessor->SetCurrentComponentPos(CalculatePositionedContainerPos( + pCurChildNode, pProcessor->GetCurrentComponentSize())); + CXFA_LayoutItem* pProcessItem = pProcessor->ExtractLayoutItem(); + if (!pBeforeItem) + pPageAreaLayoutItem->AddHeadChild(pProcessItem); + else + pPageAreaLayoutItem->InsertChild(pBeforeItem, pProcessItem); + + pBeforeItem = pProcessItem; + } + + 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) + continue; + + 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); + bool bContainerWidthAutoSize = true; + bool bContainerHeightAutoSize = true; + CFX_SizeF containerSize = CalculateContainerSpecifiedSize( + m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize); + + float fContentCalculatedWidth = 0; + float fContentCalculatedHeight = 0; + float fHiddenContentCalculatedWidth = 0; + float fHiddenContentCalculatedHeight = 0; + if (m_pCurChildNode == XFA_LAYOUT_INVALIDNODE) { + GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, + false); + } + + int32_t iColIndex = 0; + for (; m_pCurChildNode; GotoNextContainerNode( + m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false)) { + if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container) + continue; + if (m_pCurChildNode->GetElementType() == XFA_Element::Variables) + continue; + + auto pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>( + m_pCurChildNode, m_pPageMgr); + if (pContext && pContext->m_prgSpecifiedColumnWidths) { + int32_t iColSpan = m_pCurChildNode->GetInteger(XFA_ATTRIBUTE_ColSpan); + if (iColSpan <= pdfium::CollectionSize<int32_t>( + *pContext->m_prgSpecifiedColumnWidths) - + iColIndex) { + pContext->m_fCurColumnWidth = 0; + pContext->m_bCurColumnWidthAvaiable = true; + if (iColSpan == -1) { + iColSpan = pdfium::CollectionSize<int32_t>( + *pContext->m_prgSpecifiedColumnWidths); + } + for (int32_t i = 0; iColIndex + i < iColSpan; ++i) { + pContext->m_fCurColumnWidth += + (*pContext->m_prgSpecifiedColumnWidths)[iColIndex + i]; + } + if (pContext->m_fCurColumnWidth == 0) + pContext->m_bCurColumnWidthAvaiable = false; + + iColIndex += iColSpan >= 0 ? iColSpan : 0; + } + } + + pProcessor->DoLayout(false, FLT_MAX, FLT_MAX, pContext); + if (!pProcessor->HasLayoutItem()) + continue; + + CFX_SizeF size = pProcessor->GetCurrentComponentSize(); + bool bChangeParentSize = false; + if (XFA_ItemLayoutProcessor_IsTakingSpace(m_pCurChildNode)) + bChangeParentSize = true; + + CFX_PointF absolutePos; + if (!bIgnoreXY) + absolutePos = CalculatePositionedContainerPos(m_pCurChildNode, size); + + pProcessor->SetCurrentComponentPos(absolutePos); + if (bContainerWidthAutoSize) { + float fChildSuppliedWidth = absolutePos.x + size.width; + if (bChangeParentSize) { + fContentCalculatedWidth = + std::max(fContentCalculatedWidth, fChildSuppliedWidth); + } else { + if (fHiddenContentCalculatedWidth < fChildSuppliedWidth && + m_pCurChildNode->GetElementType() != XFA_Element::Subform) { + fHiddenContentCalculatedWidth = fChildSuppliedWidth; + } + } + } + + if (bContainerHeightAutoSize) { + float fChildSuppliedHeight = absolutePos.y + size.height; + if (bChangeParentSize) { + fContentCalculatedHeight = + std::max(fContentCalculatedHeight, fChildSuppliedHeight); + } else { + if (fHiddenContentCalculatedHeight < fChildSuppliedHeight && + m_pCurChildNode->GetElementType() != XFA_Element::Subform) { + fHiddenContentCalculatedHeight = fChildSuppliedHeight; + } + } + } + m_pLayoutItem->AddChild(pProcessor->ExtractLayoutItem()); + } + + 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; + + containerSize = CalculateContainerComponentSizeFromContentSize( + m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth, + bContainerHeightAutoSize, fContentCalculatedHeight, containerSize); + SetCurrentComponentSize(containerSize); +} + +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); + bool bContainerWidthAutoSize = true; + bool bContainerHeightAutoSize = true; + CFX_SizeF containerSize = CalculateContainerSpecifiedSize( + m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize); + float fContentCalculatedWidth = 0; + float fContentCalculatedHeight = 0; + CXFA_Node* pMarginNode = + m_pFormNode->GetFirstChildByClass(XFA_Element::Margin); + float fLeftInset = 0; + 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); + } + + float fContentWidthLimit = + bContainerWidthAutoSize ? FLT_MAX + : containerSize.width - fLeftInset - fRightInset; + CFX_WideStringC wsColumnWidths; + if (pLayoutNode->TryCData(XFA_ATTRIBUTE_ColumnWidths, wsColumnWidths)) { + auto widths = SeparateStringW(wsColumnWidths.c_str(), + wsColumnWidths.GetLength(), L' '); + for (auto& width : widths) { + width.TrimLeft(L' '); + if (width.IsEmpty()) + continue; + + m_rgSpecifiedColumnWidths.push_back( + CXFA_Measurement(width.AsStringC()).ToUnit(XFA_UNIT_Pt)); + } + } + + int32_t iSpecifiedColumnCount = + pdfium::CollectionSize<int32_t>(m_rgSpecifiedColumnWidths); + CXFA_LayoutContext layoutContext; + layoutContext.m_prgSpecifiedColumnWidths = &m_rgSpecifiedColumnWidths; + CXFA_LayoutContext* pLayoutContext = + iSpecifiedColumnCount > 0 ? &layoutContext : nullptr; + if (m_pCurChildNode == XFA_LAYOUT_INVALIDNODE) { + GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, + false); + } + + for (; m_pCurChildNode; GotoNextContainerNode( + m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, false)) { + layoutContext.m_bCurColumnWidthAvaiable = false; + layoutContext.m_fCurColumnWidth = 0; + if (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Container) + continue; + + auto pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>( + m_pCurChildNode, m_pPageMgr); + pProcessor->DoLayout(false, FLT_MAX, FLT_MAX, pLayoutContext); + if (!pProcessor->HasLayoutItem()) + continue; + + m_pLayoutItem->AddChild(pProcessor->ExtractLayoutItem()); + } + + int32_t iRowCount = 0; + int32_t iColCount = 0; + { + std::vector<CXFA_ContentLayoutItem*> rgRowItems; + std::vector<int32_t> rgRowItemsSpan; + std::vector<float> rgRowItemsWidth; + for (auto* pLayoutChild = + static_cast<CXFA_ContentLayoutItem*>(m_pLayoutItem->m_pFirstChild); + pLayoutChild; pLayoutChild = static_cast<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.push_back(pRowLayoutCell); + int32_t iColSpan = + pRowLayoutCell->m_pFormNode->GetInteger(XFA_ATTRIBUTE_ColSpan); + rgRowItemsSpan.push_back(iColSpan); + rgRowItemsWidth.push_back(pRowLayoutCell->m_sSize.width); + } + } + + iRowCount = pdfium::CollectionSize<int32_t>(rgRowItems); + 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.width : 0; + } + CXFA_ContentLayoutItem* pCell = rgRowItems[i]; + if (!pCell) + continue; + + bMoreColumns = true; + if (rgRowItemsSpan[i] != 1) + continue; + + if (iColCount >= iSpecifiedColumnCount) { + int32_t c = iColCount + 1 - pdfium::CollectionSize<int32_t>( + m_rgSpecifiedColumnWidths); + for (int32_t j = 0; j < c; j++) + m_rgSpecifiedColumnWidths.push_back(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) + continue; + + float fFinalColumnWidth = 0.0f; + if (pdfium::IndexInBounds(m_rgSpecifiedColumnWidths, iColCount)) + fFinalColumnWidth = m_rgSpecifiedColumnWidths[iColCount]; + + for (int32_t i = 0; i < iRowCount; ++i) { + if (!rgRowItems[i]) + continue; + --rgRowItemsSpan[i]; + rgRowItemsWidth[i] -= fFinalColumnWidth; + } + ++iColCount; + } + } + + 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) { + 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_Center: + pLayoutChild->m_sPos.x = + (fContentWidthLimit - pLayoutChild->m_sSize.width) / 2; + break; + case XFA_ATTRIBUTEENUM_Right: + pLayoutChild->m_sPos.x = + fContentWidthLimit - pLayoutChild->m_sSize.width; + break; + case XFA_ATTRIBUTEENUM_Left: + default: + pLayoutChild->m_sPos.x = 0; + break; + } + } + + if (bContainerWidthAutoSize) { + float fChildSuppliedWidth = + pLayoutChild->m_sPos.x + pLayoutChild->m_sSize.width; + if (fContentWidthLimit < FLT_MAX && + fContentWidthLimit > fChildSuppliedWidth) { + fChildSuppliedWidth = fContentWidthLimit; + } + fContentCalculatedWidth = + std::max(fContentCalculatedWidth, fChildSuppliedWidth); + } + fCurrentRowY += pLayoutChild->m_sSize.height; + } + + if (bContainerHeightAutoSize) + fContentCalculatedHeight = std::max(fContentCalculatedHeight, fCurrentRowY); + + containerSize = CalculateContainerComponentSizeFromContentSize( + m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth, + bContainerHeightAutoSize, fContentCalculatedHeight, containerSize); + SetCurrentComponentSize(containerSize); +} + +bool CXFA_ItemLayoutProcessor::IsAddNewRowForTrailer( + CXFA_ContentLayoutItem* pTrailerItem) { + if (!pTrailerItem) + return false; + + float fWidth = pTrailerItem->m_sSize.width; + XFA_ATTRIBUTEENUM eLayout = m_pFormNode->GetEnum(XFA_ATTRIBUTE_Layout); + return eLayout == XFA_ATTRIBUTEENUM_Tb || m_fWidthLimite <= fWidth; +} + +float CXFA_ItemLayoutProcessor::InsertKeepLayoutItems() { + if (m_arrayKeepItems.empty()) + return 0; + + if (!m_pLayoutItem) { + m_pLayoutItem = CreateContentLayoutItem(m_pFormNode); + m_pLayoutItem->m_sSize.clear(); + } + + float fTotalHeight = 0; + for (auto iter = m_arrayKeepItems.rbegin(); iter != m_arrayKeepItems.rend(); + iter++) { + AddLeaderAfterSplit(this, *iter); + fTotalHeight += (*iter)->m_sSize.height; + } + m_arrayKeepItems.clear(); + + return fTotalHeight; +} + +bool CXFA_ItemLayoutProcessor::ProcessKeepForSplit( + CXFA_ItemLayoutProcessor* pParentProcessor, + CXFA_ItemLayoutProcessor* pChildProcessor, + XFA_ItemLayoutProcessorResult eRetValue, + std::vector<CXFA_ContentLayoutItem*>* rgCurLineLayoutItem, + float* fContentCurRowAvailWidth, + float* fContentCurRowHeight, + 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) + return false; + + if (!ExistContainerKeep(pParentProcessor->m_pCurChildNode, true)) + return false; + + CFX_SizeF childSize = pChildProcessor->GetCurrentComponentSize(); + std::vector<CXFA_ContentLayoutItem*> keepLayoutItems; + if (pParentProcessor->JudgePutNextPage(pParentProcessor->m_pLayoutItem, + childSize.height, &keepLayoutItems)) { + m_arrayKeepItems.clear(); + + for (auto* item : keepLayoutItems) { + pParentProcessor->m_pLayoutItem->RemoveChild(item); + *fContentCurRowY -= item->m_sSize.height; + m_arrayKeepItems.push_back(item); + } + *bAddedItemInRow = true; + *bForceEndPage = true; + *result = XFA_ItemLayoutProcessorResult::PageFullBreak; + return true; + } + + rgCurLineLayoutItem->push_back(pChildProcessor->ExtractLayoutItem()); + *bAddedItemInRow = true; + *fContentCurRowAvailWidth -= childSize.width; + *fContentCurRowHeight = std::max(*fContentCurRowHeight, childSize.height); + *result = eRetValue; + + return true; +} + +bool CXFA_ItemLayoutProcessor::JudgePutNextPage( + CXFA_ContentLayoutItem* pParentLayoutItem, + float fChildHeight, + std::vector<CXFA_ContentLayoutItem*>* pKeepItems) { + if (!pParentLayoutItem) + return false; + + float fItemsHeight = 0; + for (CXFA_ContentLayoutItem* pChildLayoutItem = + (CXFA_ContentLayoutItem*)pParentLayoutItem->m_pFirstChild; + pChildLayoutItem; + pChildLayoutItem = + (CXFA_ContentLayoutItem*)pChildLayoutItem->m_pNextSibling) { + if (ExistContainerKeep(pChildLayoutItem->m_pFormNode, false)) { + pKeepItems->push_back(pChildLayoutItem); + fItemsHeight += pChildLayoutItem->m_sSize.height; + } else { + pKeepItems->clear(); + fItemsHeight = 0; + } + } + fItemsHeight += fChildHeight; + return m_pPageMgr->GetNextAvailContentHeight(fItemsHeight); +} + +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); +} + +XFA_ItemLayoutProcessorResult CXFA_ItemLayoutProcessor::DoLayoutFlowedContainer( + bool bUseBreakControl, + XFA_ATTRIBUTEENUM eFlowStrategy, + float fHeightLimit, + float fRealHeight, + CXFA_LayoutContext* pContext, + bool bRootForceTb) { + m_bHasAvailHeight = true; + bool bBreakDone = false; + bool bContainerWidthAutoSize = true; + bool bContainerHeightAutoSize = true; + bool bForceEndPage = false; + bool bIsManualBreak = false; + if (m_pCurChildPreprocessor) { + m_pCurChildPreprocessor->m_ePreProcessRs = + XFA_ItemLayoutProcessorResult::Done; + } + + CFX_SizeF containerSize = CalculateContainerSpecifiedSize( + m_pFormNode, &bContainerWidthAutoSize, &bContainerHeightAutoSize); + if (pContext && pContext->m_bCurColumnWidthAvaiable) { + bContainerWidthAutoSize = false; + containerSize.width = pContext->m_fCurColumnWidth; + } + if (!bContainerHeightAutoSize) + containerSize.height -= m_fUsedSize; + + if (!bContainerHeightAutoSize) { + CXFA_Node* pParentNode = m_pFormNode->GetNodeItem(XFA_NODEITEM_Parent); + bool bFocrTb = false; + if (pParentNode && + 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)) { + containerSize.height = 0; + bContainerHeightAutoSize = true; + } + } + } + + CXFA_Node* pMarginNode = + m_pFormNode->GetFirstChildByClass(XFA_Element::Margin); + float fLeftInset = 0; + float fTopInset = 0; + float fRightInset = 0; + float 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); + } + float fContentWidthLimit = + bContainerWidthAutoSize ? FLT_MAX + : containerSize.width - fLeftInset - fRightInset; + float fContentCalculatedWidth = 0; + float fContentCalculatedHeight = 0; + float fAvailHeight = fHeightLimit - fTopInset - fBottomInset; + if (fAvailHeight < 0) + m_bHasAvailHeight = false; + + fRealHeight = fRealHeight - fTopInset - fBottomInset; + 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)) + continue; + + fContentCalculatedWidth = std::max( + fContentCalculatedWidth, + pLayoutTempChild->m_sPos.x + pLayoutTempChild->m_sSize.width); + fContentCalculatedHeight = std::max( + fContentCalculatedHeight, + pLayoutTempChild->m_sPos.y + pLayoutTempChild->m_sSize.height); + } + + if (pLayoutChild) + fContentCurRowY = pLayoutChild->m_sPos.y; + else + fContentCurRowY = fContentCalculatedHeight; + } + + fContentCurRowY += InsertKeepLayoutItems(); + if (m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::None) { + GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, + true); + } + + fContentCurRowY += InsertPendingItems(this, m_pFormNode); + if (m_pCurChildPreprocessor && + m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::Container) { + if (ExistContainerKeep(m_pCurChildPreprocessor->GetFormNode(), false)) { + m_pKeepHeadNode = m_pCurChildNode; + m_bIsProcessKeep = true; + m_nCurChildNodeStage = XFA_ItemLayoutProcessorStages::Keep; + } + } + + while (m_nCurChildNodeStage != XFA_ItemLayoutProcessorStages::Done) { + float fContentCurRowHeight = 0; + float fContentCurRowAvailWidth = fContentWidthLimit; + m_fWidthLimite = fContentCurRowAvailWidth; + std::vector<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 = HAlignEnumToInt( + pLayoutNext->m_pFormNode->GetEnum(XFA_ATTRIBUTE_HAlign)); + rgCurLineLayoutItems[uHAlign].push_back(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.height > fContentCurRowHeight) + fContentCurRowHeight = pLayoutNext->m_sSize.height; + fContentCurRowAvailWidth -= pLayoutNext->m_sSize.width; + } + } + + 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) { + std::unique_ptr<CXFA_ItemLayoutProcessor> pProcessor; + bool bAddedItemInRow = false; + fContentCurRowY += InsertPendingItems(this, m_pFormNode); + switch (m_nCurChildNodeStage) { + case XFA_ItemLayoutProcessorStages::Keep: + case XFA_ItemLayoutProcessorStages::None: + break; + case XFA_ItemLayoutProcessorStages::BreakBefore: { + for (auto* item : m_arrayKeepItems) { + m_pLayoutItem->RemoveChild(item); + fContentCalculatedHeight -= item->m_sSize.height; + } + + 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) { + break; + } + + if (JudgeLeaderOrTrailerForOccur(pLeaderNode)) + AddPendingNode(this, pLeaderNode, true); + + if (JudgeLeaderOrTrailerForOccur(pTrailerNode)) { + if (m_pFormNode->GetNodeItem(XFA_NODEITEM_Parent) + ->GetElementType() == XFA_Element::Form && + !m_pLayoutItem) { + AddPendingNode(this, pTrailerNode, true); + } else { + auto pTempProcessor = + pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pTrailerNode, + nullptr); + InsertFlowedItem( + this, pTempProcessor.get(), bContainerWidthAutoSize, + bContainerHeightAutoSize, containerSize.height, eFlowStrategy, + &uCurHAlignState, rgCurLineLayoutItems, false, FLT_MAX, + FLT_MAX, fContentWidthLimit, &fContentCurRowY, + &fContentCurRowAvailWidth, &fContentCurRowHeight, + &bAddedItemInRow, &bForceEndPage, pContext, false); + } + } + GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, + m_pFormNode, true); + bForceEndPage = true; + bIsManualBreak = true; + goto SuspendAndCreateNewRow; + } + 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) { + break; + } + + if (JudgeLeaderOrTrailerForOccur(pTrailerNode)) { + auto pTempProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>( + pTrailerNode, nullptr); + InsertFlowedItem( + this, pTempProcessor.get(), bContainerWidthAutoSize, + bContainerHeightAutoSize, containerSize.height, eFlowStrategy, + &uCurHAlignState, rgCurLineLayoutItems, false, FLT_MAX, FLT_MAX, + fContentWidthLimit, &fContentCurRowY, &fContentCurRowAvailWidth, + &fContentCurRowHeight, &bAddedItemInRow, &bForceEndPage, + pContext, false); + } + if (!bCreatePage) { + if (JudgeLeaderOrTrailerForOccur(pLeaderNode)) { + CalculateRowChildPosition( + rgCurLineLayoutItems, eFlowStrategy, bContainerHeightAutoSize, + bContainerWidthAutoSize, &fContentCalculatedWidth, + &fContentCalculatedHeight, &fContentCurRowY, + fContentCurRowHeight, fContentWidthLimit, false); + rgCurLineLayoutItems->clear(); + auto pTempProcessor = + pdfium::MakeUnique<CXFA_ItemLayoutProcessor>(pLeaderNode, + nullptr); + InsertFlowedItem( + this, pTempProcessor.get(), bContainerWidthAutoSize, + bContainerHeightAutoSize, containerSize.height, eFlowStrategy, + &uCurHAlignState, rgCurLineLayoutItems, false, FLT_MAX, + FLT_MAX, fContentWidthLimit, &fContentCurRowY, + &fContentCurRowAvailWidth, &fContentCurRowHeight, + &bAddedItemInRow, &bForceEndPage, pContext, false); + } + } else { + if (JudgeLeaderOrTrailerForOccur(pLeaderNode)) + AddPendingNode(this, pLeaderNode, true); + } + + GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, + m_pFormNode, true); + if (bCreatePage) { + bForceEndPage = true; + bIsManualBreak = true; + if (m_nCurChildNodeStage == XFA_ItemLayoutProcessorStages::Done) + bBreakDone = true; + } + goto SuspendAndCreateNewRow; + } + case XFA_ItemLayoutProcessorStages::BookendLeader: { + CXFA_Node* pLeaderNode = nullptr; + if (m_pCurChildPreprocessor) { + pProcessor.reset(m_pCurChildPreprocessor); + m_pCurChildPreprocessor = nullptr; + } else if (m_pPageMgr && + m_pPageMgr->ProcessBookendLeaderOrTrailer( + m_pCurChildNode, true, pLeaderNode)) { + pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>( + pLeaderNode, m_pPageMgr); + } + + if (pProcessor) { + if (InsertFlowedItem( + this, pProcessor.get(), bContainerWidthAutoSize, + bContainerHeightAutoSize, containerSize.height, + eFlowStrategy, &uCurHAlignState, rgCurLineLayoutItems, + bUseBreakControl, fAvailHeight, fRealHeight, + fContentWidthLimit, &fContentCurRowY, + &fContentCurRowAvailWidth, &fContentCurRowHeight, + &bAddedItemInRow, &bForceEndPage, pContext, + false) != XFA_ItemLayoutProcessorResult::Done) { + goto SuspendAndCreateNewRow; + } else { + pProcessor.reset(); + } + } + break; + } + case XFA_ItemLayoutProcessorStages::BookendTrailer: { + CXFA_Node* pTrailerNode = nullptr; + if (m_pCurChildPreprocessor) { + pProcessor.reset(m_pCurChildPreprocessor); + m_pCurChildPreprocessor = nullptr; + } else if (m_pPageMgr && + m_pPageMgr->ProcessBookendLeaderOrTrailer( + m_pCurChildNode, false, pTrailerNode)) { + pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>( + pTrailerNode, m_pPageMgr); + } + if (pProcessor) { + if (InsertFlowedItem( + this, pProcessor.get(), bContainerWidthAutoSize, + bContainerHeightAutoSize, containerSize.height, + eFlowStrategy, &uCurHAlignState, rgCurLineLayoutItems, + bUseBreakControl, fAvailHeight, fRealHeight, + fContentWidthLimit, &fContentCurRowY, + &fContentCurRowAvailWidth, &fContentCurRowHeight, + &bAddedItemInRow, &bForceEndPage, pContext, + false) != XFA_ItemLayoutProcessorResult::Done) { + goto SuspendAndCreateNewRow; + } else { + pProcessor.reset(); + } + } + 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()) + break; + + bool bNewRow = false; + if (m_pCurChildPreprocessor) { + pProcessor.reset(m_pCurChildPreprocessor); + m_pCurChildPreprocessor = nullptr; + bNewRow = true; + } else { + pProcessor = pdfium::MakeUnique<CXFA_ItemLayoutProcessor>( + m_pCurChildNode, m_pPageMgr); + } + + InsertPendingItems(pProcessor.get(), m_pCurChildNode); + XFA_ItemLayoutProcessorResult rs = InsertFlowedItem( + this, pProcessor.get(), bContainerWidthAutoSize, + bContainerHeightAutoSize, containerSize.height, eFlowStrategy, + &uCurHAlignState, rgCurLineLayoutItems, bUseBreakControl, + fAvailHeight, fRealHeight, fContentWidthLimit, &fContentCurRowY, + &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 += + InsertPendingItems(pProcessor.get(), m_pCurChildNode); + pProcessor.reset(); + } + break; + } + case XFA_ItemLayoutProcessorStages::Done: + break; + default: + break; + } + GotoNextContainerNode(m_pCurChildNode, m_nCurChildNodeStage, m_pFormNode, + true); + if (bAddedItemInRow && eFlowStrategy == XFA_ATTRIBUTEENUM_Tb) + break; + else + continue; + SuspendAndCreateNewRow: + if (pProcessor) + m_pCurChildPreprocessor = pProcessor.release(); + 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; + + containerSize = CalculateContainerComponentSizeFromContentSize( + m_pFormNode, bContainerWidthAutoSize, fContentCalculatedWidth, + bContainerHeightAutoSize, fContentCalculatedHeight, containerSize); + + if (containerSize.height >= XFA_LAYOUT_FLOAT_PERCISION || m_pLayoutItem || + bRetValue) { + if (!m_pLayoutItem) + m_pLayoutItem = CreateContentLayoutItem(m_pFormNode); + containerSize.height = std::max(containerSize.height, 0.f); + + SetCurrentComponentSize(containerSize); + if (bForceEndPage) + m_fUsedSize = 0; + else + m_fUsedSize += m_pLayoutItem->m_sSize.height; + } + + return bRetValue + ? XFA_ItemLayoutProcessorResult::Done + : (bIsManualBreak ? XFA_ItemLayoutProcessorResult::ManualBreak + : XFA_ItemLayoutProcessorResult::PageFullBreak); +} + +bool CXFA_ItemLayoutProcessor::CalculateRowChildPosition( + std::vector<CXFA_ContentLayoutItem*> (&rgCurLineLayoutItems)[3], + XFA_ATTRIBUTEENUM eFlowStrategy, + bool bContainerHeightAutoSize, + bool bContainerWidthAutoSize, + float* fContentCalculatedWidth, + float* fContentCalculatedHeight, + float* fContentCurRowY, + float fContentCurRowHeight, + float fContentWidthLimit, + bool bRootForceTb) { + int32_t nGroupLengths[3] = {0, 0, 0}; + float fGroupWidths[3] = {0, 0, 0}; + int32_t nTotalLength = 0; + for (int32_t i = 0; i < 3; i++) { + nGroupLengths[i] = pdfium::CollectionSize<int32_t>(rgCurLineLayoutItems[i]); + 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.width; + } + } + } + if (!nTotalLength) { + if (bContainerHeightAutoSize) { + *fContentCalculatedHeight = + std::min(*fContentCalculatedHeight, *fContentCurRowY); + } + return false; + } + if (!m_pLayoutItem) + m_pLayoutItem = CreateContentLayoutItem(m_pFormNode); + + if (eFlowStrategy != XFA_ATTRIBUTEENUM_Rl_tb) { + float fCurPos; + fCurPos = 0; + for (int32_t c = nGroupLengths[0], j = 0; j < c; j++) { + if (bRootForceTb) { + rgCurLineLayoutItems[0][j]->m_sPos = CalculatePositionedContainerPos( + rgCurLineLayoutItems[0][j]->m_pFormNode, + rgCurLineLayoutItems[0][j]->m_sSize); + } 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.width; + } + } + 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) { + rgCurLineLayoutItems[1][j]->m_sPos = CalculatePositionedContainerPos( + rgCurLineLayoutItems[1][j]->m_pFormNode, + rgCurLineLayoutItems[1][j]->m_sSize); + } 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.width; + } + } + 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) { + rgCurLineLayoutItems[2][j]->m_sPos = CalculatePositionedContainerPos( + rgCurLineLayoutItems[2][j]->m_pFormNode, + rgCurLineLayoutItems[2][j]->m_sSize); + } 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.width; + } + } + m_pLayoutItem->AddChild(rgCurLineLayoutItems[2][j]); + m_fLastRowWidth = fCurPos; + } + } else { + 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.width; + } + 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.width; + } + 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.width; + } + 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) { + float fChildSuppliedWidth = fGroupWidths[0]; + if (fContentWidthLimit < FLT_MAX && + fContentWidthLimit > fChildSuppliedWidth) { + fChildSuppliedWidth = fContentWidthLimit; + } + *fContentCalculatedWidth = + std::max(*fContentCalculatedWidth, fChildSuppliedWidth); + } + if (bContainerHeightAutoSize) { + *fContentCalculatedHeight = + std::max(*fContentCalculatedHeight, *fContentCurRowY); + } + 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(); + CFX_SizeF size(-1, -1); + pNotify->StartFieldDrawLayout(m_pFormNode, size.width, size.height); + + int32_t nRotate = + FXSYS_round(m_pFormNode->GetMeasure(XFA_ATTRIBUTE_Rotate).GetValue()); + nRotate = XFA_MapRotation(nRotate); + if (nRotate == 90 || nRotate == 270) + std::swap(size.width, size.height); + + SetCurrentComponentSize(size); +} + +XFA_ItemLayoutProcessorResult CXFA_ItemLayoutProcessor::DoLayout( + bool bUseBreakControl, + float fHeightLimit, + 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 = 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; + } +} + +CFX_SizeF CXFA_ItemLayoutProcessor::GetCurrentComponentSize() { + return CFX_SizeF(m_pLayoutItem->m_sSize.width, m_pLayoutItem->m_sSize.height); +} + +void CXFA_ItemLayoutProcessor::SetCurrentComponentPos(const CFX_PointF& pos) { + m_pLayoutItem->m_sPos = pos; +} + +void CXFA_ItemLayoutProcessor::SetCurrentComponentSize(const CFX_SizeF& size) { + m_pLayoutItem->m_sSize = size; +} + +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; +} |