XFA: break pages at top-level subform

This commit is contained in:
Jakub Melka 2021-12-25 19:04:48 +01:00
parent f53b9f2988
commit 2209c04f48
1 changed files with 76 additions and 19 deletions

View File

@ -10031,6 +10031,8 @@ private:
}
else
{
m_engine->layoutFlow(parameters, true);
// Store final layout
m_engine->m_layout.insert(m_engine->m_layout.end(), std::make_move_iterator(parameters.layout.begin()), std::make_move_iterator(parameters.layout.end()));
}
@ -10057,7 +10059,7 @@ private:
/// Perform flow layout. Does nothing, if layout has positional
/// layout type. Final layout is stored also in the layout parameters.
/// \param layoutParameters Layout parameters
void layoutFlow(LayoutParameters& layoutParameters);
void layoutFlow(LayoutParameters& layoutParameters, bool breakPages);
void addSubformToLayout(LayoutParameters& layoutParameters);
@ -10068,6 +10070,11 @@ private:
bool layoutPositional(LayoutParameters& sourceLayoutParameters,
LayoutParameters& targetLayoutParameters);
void finalizeAndAddLayout(QMarginsF captionMargins,
Layout finalLayout,
LayoutParameters& layoutParameters,
QSizeF nominalContentSize);
LayoutParameters& getLayoutParameters() { return m_layoutParameters.top(); }
const LayoutParameters& getLayoutParameters() const { return m_layoutParameters.top(); }
@ -10163,7 +10170,7 @@ void PDFXFALayoutEngine::layout(LayoutParameters layoutParameters)
// Case 1)
LayoutParameters& currentLayoutParameters = getLayoutParameters();
layoutFlow(layoutParameters);
layoutFlow(layoutParameters, false);
std::vector<Layout>& layouts = currentLayoutParameters.layout;
if (layoutParameters.nodeArea)
@ -10219,7 +10226,27 @@ void PDFXFALayoutEngine::layout(LayoutParameters layoutParameters)
std::make_move_iterator(layoutParameters.tableRows.end()));
}
void PDFXFALayoutEngine::layoutFlow(LayoutParameters& layoutParameters)
void PDFXFALayoutEngine::finalizeAndAddLayout(QMarginsF captionMargins,
Layout finalLayout,
LayoutParameters& layoutParameters,
QSizeF nominalContentSize)
{
finalLayout.translate(layoutParameters.margins.left(), layoutParameters.margins.top());
QSizeF nominalExtentSizeWithoutCaption = nominalContentSize.grownBy(layoutParameters.margins);
QSizeF nominalExtentSize = nominalExtentSizeWithoutCaption.grownBy(captionMargins);
nominalExtentSize = layoutParameters.sizeInfo.adjustNominalExtentSize(nominalExtentSize);
QRectF nominalExtentRegion(QPointF(0, 0), nominalExtentSize);
finalLayout.nominalExtent = nominalExtentRegion;
finalLayout.colSpan = layoutParameters.columnSpan;
if (!finalLayout.items.empty())
{
layoutParameters.layout.emplace_back(std::move(finalLayout));
}
}
void PDFXFALayoutEngine::layoutFlow(LayoutParameters& layoutParameters, bool breakPages)
{
if (layoutParameters.layoutType == xfa::XFA_BaseNode::LAYOUT::Position)
{
@ -10356,9 +10383,10 @@ void PDFXFALayoutEngine::layoutFlow(LayoutParameters& layoutParameters)
}
layoutParameters.layout.clear();
PDFInteger pageOffset = 0;
for (auto& item : layoutsPerPage)
{
const size_t pageIndex = item.first;
const size_t sourcePageIndex = item.first;
std::vector<Layout> layouts = std::move(item.second);
for (Layout& layout : layouts)
@ -10373,6 +10401,7 @@ void PDFXFALayoutEngine::layoutFlow(LayoutParameters& layoutParameters)
break;
case xfa::XFA_BaseNode::LAYOUT::Lr_tb:
// TODO: Implement Lr_Tb
break;
case xfa::XFA_BaseNode::LAYOUT::Rl_row:
@ -10383,6 +10412,7 @@ void PDFXFALayoutEngine::layoutFlow(LayoutParameters& layoutParameters)
}
case xfa::XFA_BaseNode::LAYOUT::Rl_tb:
// TODO: Implement Rl_tb
break;
case xfa::XFA_BaseNode::LAYOUT::Row:
@ -10401,14 +10431,52 @@ void PDFXFALayoutEngine::layoutFlow(LayoutParameters& layoutParameters)
{
// Top-to-bottom layout
Layout finalLayout;
finalLayout.pageIndex = pageIndex;
PDFInteger targetPageIndex = sourcePageIndex + pageOffset;
finalLayout.pageIndex = targetPageIndex;
PDFReal x = 0.0;
PDFReal y = 0.0;
PDFReal h = 0.0;
PDFReal maxW = 0.0;
PDFReal maxH = 0.0;
if (breakPages && targetPageIndex < PDFInteger(m_pages.size()))
{
maxH = m_pages[targetPageIndex].contentBox.height() - layoutParameters.margins.top() - layoutParameters.margins.bottom();
}
for (Layout& layout : layouts)
{
if (breakPages && !qFuzzyIsNull(maxH))
{
PDFReal currentH = h + layout.nominalExtent.height();
if (currentH > maxH)
{
finalizeAndAddLayout(captionMargins, finalLayout, layoutParameters, QSizeF(maxW, y));
// Update page offets and maximal height
++pageOffset;
++targetPageIndex;
if (targetPageIndex < PDFInteger(m_pages.size()))
{
maxH = m_pages[targetPageIndex].contentBox.height() - layoutParameters.margins.top() - layoutParameters.margins.bottom();
}
// Reinitialize final layout
finalLayout = Layout();
finalLayout.pageIndex = targetPageIndex;
// Current item is layouted onto the next page
h = layout.nominalExtent.height();
y = 0.0;
}
else
{
h = currentH;
}
}
layout.translate(x, y);
finalLayout.items.insert(finalLayout.items.end(), layout.items.begin(), layout.items.end());
y += layout.nominalExtent.height();
@ -10416,26 +10484,15 @@ void PDFXFALayoutEngine::layoutFlow(LayoutParameters& layoutParameters)
}
// Translate by margin
finalLayout.translate(layoutParameters.margins.left(), layoutParameters.margins.top());
QSizeF nominalContentSize(maxW, y);
QSizeF nominalExtentSizeWithoutCaption = nominalContentSize.grownBy(layoutParameters.margins);
QSizeF nominalExtentSize = nominalExtentSizeWithoutCaption.grownBy(captionMargins);
nominalExtentSize = layoutParameters.sizeInfo.adjustNominalExtentSize(nominalExtentSize);
QRectF nominalExtentRegion(QPointF(0, 0), nominalExtentSize);
finalLayout.nominalExtent = nominalExtentRegion;
finalLayout.colSpan = layoutParameters.columnSpan;
if (!finalLayout.items.empty())
{
layoutParameters.layout.emplace_back(std::move(finalLayout));
}
finalizeAndAddLayout(captionMargins, finalLayout, layoutParameters, QSizeF(maxW, y));
break;
}
default:
{
Q_ASSERT(false);
break;
}
}
}