// 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 #include #include #include #include "third_party/base/logging.h" #include "third_party/base/ptr_util.h" #include "third_party/base/stl_util.h" #include "xfa/fxfa/cxfa_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_node.h" #include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h" #include "xfa/fxfa/parser/cxfa_occurdata.h" #include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h" #include "xfa/fxfa/parser/xfa_utils.h" namespace { std::vector SeparateStringW(const wchar_t* pStr, int32_t iStrLen, wchar_t delimiter) { std::vector ret; if (!pStr) return ret; if (iStrLen < 0) iStrLen = wcslen(pStr); const wchar_t* pToken = pStr; const wchar_t* pEnd = pStr + iStrLen; while (true) { if (pStr >= pEnd || delimiter == *pStr) { ret.push_back(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: NOTREACHED(); } } CFX_SizeF CalculateContainerSpecifiedSize(CXFA_Node* pFormNode, bool* bContainerWidthAutoSize, bool* bContainerHeightAutoSize) { *bContainerWidthAutoSize = true; *bContainerHeightAutoSize = true; XFA_Element eType = pFormNode->GetElementType(); CFX_SizeF containerSize; if (eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup) { pdfium::Optional wValue = pFormNode->JSNode()->TryMeasure(XFA_Attribute::W, false); if (wValue && wValue->GetValue() > XFA_LAYOUT_FLOAT_PERCISION) { containerSize.width = wValue->ToUnit(XFA_Unit::Pt); *bContainerWidthAutoSize = false; } pdfium::Optional hValue = pFormNode->JSNode()->TryMeasure(XFA_Attribute::H, false); if (hValue && hValue->GetValue() > XFA_LAYOUT_FLOAT_PERCISION) { containerSize.height = hValue->ToUnit(XFA_Unit::Pt); *bContainerHeightAutoSize = false; } } if (*bContainerWidthAutoSize && eType == XFA_Element::Subform) { pdfium::Optional maxW = pFormNode->JSNode()->TryMeasure(XFA_Attribute::MaxW, false); if (maxW && maxW->GetValue() > XFA_LAYOUT_FLOAT_PERCISION) { containerSize.width = maxW->ToUnit(XFA_Unit::Pt); *bContainerWidthAutoSize = false; } pdfium::Optional maxH = pFormNode->JSNode()->TryMeasure(XFA_Attribute::MaxH, false); if (maxH && maxH->GetValue() > XFA_LAYOUT_FLOAT_PERCISION) { containerSize.height = maxH->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); if (bContainerWidthAutoSize) { componentSize.width = fContentCalculatedWidth; if (pMarginNode) { pdfium::Optional leftInset = pMarginNode->JSNode()->TryMeasure(XFA_Attribute::LeftInset, false); if (leftInset) componentSize.width += leftInset->ToUnit(XFA_Unit::Pt); pdfium::Optional rightInset = pMarginNode->JSNode()->TryMeasure(XFA_Attribute::RightInset, false); if (rightInset) componentSize.width += rightInset->ToUnit(XFA_Unit::Pt); } } if (bContainerHeightAutoSize) { componentSize.height = fContentCalculatedHeight; if (pMarginNode) { pdfium::Optional topInset = pMarginNode->JSNode()->TryMeasure(XFA_Attribute::TopInset, false); if (topInset) componentSize.height += topInset->ToUnit(XFA_Unit::Pt); pdfium::Optional bottomInset = pMarginNode->JSNode()->TryMeasure(XFA_Attribute::BottomInset, false); if (bottomInset) componentSize.height += bottomInset->ToUnit(XFA_Unit::Pt); } } return componentSize; } void RelocateTableRowCells(CXFA_ContentLayoutItem* pLayoutRow, const std::vector& 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->JSNode() ->GetMeasure(XFA_Attribute::LeftInset) .ToUnit(XFA_Unit::Pt); fTopInset = pMarginNode->JSNode() ->GetMeasure(XFA_Attribute::TopInset) .ToUnit(XFA_Unit::Pt); fRightInset = pMarginNode->JSNode() ->GetMeasure(XFA_Attribute::RightInset) .ToUnit(XFA_Unit::Pt); fBottomInset = pMarginNode->JSNode() ->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(pLayoutRow->m_pFirstChild); pLayoutChild; pLayoutChild = static_cast( pLayoutChild->m_pNextSibling)) { int32_t nOriginalColSpan = pLayoutChild->m_pFormNode->JSNode()->GetInteger(XFA_Attribute::ColSpan); int32_t nColSpan = nOriginalColSpan; float fColSpanWidth = 0; if (nColSpan == -1 || nCurrentColIdx + nColSpan > pdfium::CollectionSize(rgSpecifiedColumnWidths)) { nColSpan = pdfium::CollectionSize(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->JSNode()->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->JSNode()->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->JSNode()->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->JSNode() ->GetMeasure(XFA_Attribute::LeftInset) .ToUnit(XFA_Unit::Pt); fTopInset = pMarginNode->JSNode() ->GetMeasure(XFA_Attribute::TopInset) .ToUnit(XFA_Unit::Pt); fRightInset = pMarginNode->JSNode() ->GetMeasure(XFA_Attribute::RightInset) .ToUnit(XFA_Unit::Pt); fBottomInset = pMarginNode->JSNode() ->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->JSNode()->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->JSNode() ->GetMeasure(XFA_Attribute::LeftInset) .ToUnit(XFA_Unit::Pt); fRightInset = pMarginNode->JSNode() ->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->JSNode()->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( 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; pdfium::Optional layoutMode = pFormNode->JSNode()->TryEnum(XFA_Attribute::Layout, false); if (layoutMode) return *layoutMode; 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_Attribute eKeepType = XFA_Attribute::Previous; if (!bPreFind) eKeepType = XFA_Attribute::Next; pdfium::Optional previous = pKeep->JSNode()->TryEnum(eKeepType, false); if (previous) { if (*previous == XFA_AttributeEnum::ContentArea || *previous == 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; pdfium::Optional next = pKeep->JSNode()->TryEnum(eKeepType, false); if (!next) return false; if (*next == XFA_AttributeEnum::ContentArea || *next == 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->JSNode()->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 sIterator( pGenerateNode); for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode; pNode = sIterator.MoveToNext()) { CXFA_ContentLayoutItem* pCurLayoutItem = static_cast(pNode->JSNode()->GetLayoutItem()); 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, true); } 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 (&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->JSNode()->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(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->JSNode()->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->JSNode()->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->JSNode() ->GetMeasure(XFA_Attribute::TopInset) .ToUnit(XFA_Unit::Pt); fCurBottomMargin = pMarginNode->JSNode() ->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->JSNode()->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->JSNode()->GetMeasure(XFA_Attribute::X).ToUnit(XFA_Unit::Pt), pNode->JSNode()->GetMeasure(XFA_Attribute::Y).ToUnit(XFA_Unit::Pt)); int32_t nRotate = XFA_MapRotation(pNode->JSNode()->GetInteger(XFA_Attribute::Rotate)) / 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 = static_cast( m_pFormNode->JSNode()->GetLayoutItem()); } 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 = static_cast( pFormNode->JSNode()->GetLayoutItem()); if (pPrevLayoutItem) { while (pPrevLayoutItem->m_pNext) pPrevLayoutItem = pPrevLayoutItem->m_pNext; pPrevLayoutItem->m_pNext = pLayoutItem; pLayoutItem->m_pPrev = pPrevLayoutItem; } else { pFormNode->JSNode()->SetLayoutItem(pLayoutItem); } return pLayoutItem; } float CXFA_ItemLayoutProcessor::FindSplitPos(float fProposedSplitPos) { ASSERT(m_pLayoutItem); XFA_AttributeEnum eLayout = m_pFormNode->JSNode() ->TryEnum(XFA_Attribute::Layout, true) .value_or(XFA_AttributeEnum::Position); 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->JSNode() ->TryEnum(XFA_Attribute::Layout, true) .value_or(XFA_AttributeEnum::Position); 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->JSNode() ->GetMeasure(XFA_Attribute::TopInset) .ToUnit(XFA_Unit::Pt); fCurBottomMargin = pMarginNode->JSNode() ->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 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(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->JSNode() ->TryEnum(XFA_Attribute::Presence, true) .value_or(XFA_AttributeEnum::Visible); 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(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->JSNode() ->TryEnum(XFA_Attribute::Layout, true) .value_or(XFA_AttributeEnum::Position) != 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( m_pCurChildNode, m_pPageMgr); if (pContext && pContext->m_prgSpecifiedColumnWidths) { int32_t iColSpan = m_pCurChildNode->JSNode()->GetInteger(XFA_Attribute::ColSpan); if (iColSpan <= pdfium::CollectionSize( *pContext->m_prgSpecifiedColumnWidths) - iColIndex) { pContext->m_fCurColumnWidth = 0; pContext->m_bCurColumnWidthAvaiable = true; if (iColSpan == -1) { iColSpan = pdfium::CollectionSize( *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->JSNode() ->GetMeasure(XFA_Attribute::LeftInset) .ToUnit(XFA_Unit::Pt); fRightInset = pMarginNode->JSNode() ->GetMeasure(XFA_Attribute::RightInset) .ToUnit(XFA_Unit::Pt); } float fContentWidthLimit = bContainerWidthAutoSize ? FLT_MAX : containerSize.width - fLeftInset - fRightInset; WideString wsColumnWidths = pLayoutNode->JSNode()->GetCData(XFA_Attribute::ColumnWidths); if (!wsColumnWidths.IsEmpty()) { 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.AsStringView()).ToUnit(XFA_Unit::Pt)); } } int32_t iSpecifiedColumnCount = pdfium::CollectionSize(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( 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 rgRowItems; std::vector rgRowItemsSpan; std::vector rgRowItemsWidth; for (auto* pLayoutChild = static_cast(m_pLayoutItem->m_pFirstChild); pLayoutChild; pLayoutChild = static_cast( 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->JSNode()->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->JSNode()->GetInteger( XFA_Attribute::ColSpan); rgRowItemsSpan.push_back(iColSpan); rgRowItemsWidth.push_back(pRowLayoutCell->m_sSize.width); } } iRowCount = pdfium::CollectionSize(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->JSNode()->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( 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->JSNode()->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->JSNode()->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->JSNode()->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* 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 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* 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 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->JSNode()->SetBindingNode(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, true); if (pTrailerNode && pFormNode) pFormNode->RemoveChild(pTrailerNode, true); 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->JSNode() ->GetMeasure(XFA_Attribute::LeftInset) .ToUnit(XFA_Unit::Pt); fTopInset = pMarginNode->JSNode() ->GetMeasure(XFA_Attribute::TopInset) .ToUnit(XFA_Unit::Pt); fRightInset = pMarginNode->JSNode() ->GetMeasure(XFA_Attribute::RightInset) .ToUnit(XFA_Unit::Pt); fBottomInset = pMarginNode->JSNode() ->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 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->JSNode()->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 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(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( 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(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( 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( 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( 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; 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 (&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(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 = XFA_MapRotation(m_pFormNode->JSNode()->GetInteger(XFA_Attribute::Rotate)); 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; int32_t iMax = CXFA_OccurData(pTemplate->GetFirstChildByClass(XFA_Element::Occur)) .GetMax(); if (iMax < 0) return true; int32_t iCount = m_PendingNodesCount[pTemplate]; if (iCount >= iMax) return false; m_PendingNodesCount[pTemplate] = iCount + 1; return true; }