mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
XFA: processing pages (bugfixing)
This commit is contained in:
@ -21,6 +21,7 @@
|
|||||||
#include <QDomElement>
|
#include <QDomElement>
|
||||||
#include <QDomDocument>
|
#include <QDomDocument>
|
||||||
|
|
||||||
|
#include <stack>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
@ -85,6 +86,21 @@ private:
|
|||||||
std::shared_ptr<Value> m_value;
|
std::shared_ptr<Value> m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class XFA_ParagraphSettings
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
PDFReal getFontEmSize() const;
|
||||||
|
void setFontEmSize(const PDFReal& fontEmSize);
|
||||||
|
|
||||||
|
PDFReal getFontSpaceSize() const;
|
||||||
|
void setFontSpaceSize(const PDFReal& fontSpaceSize);
|
||||||
|
|
||||||
|
private:
|
||||||
|
PDFReal m_fontEmSize = 0.0;
|
||||||
|
PDFReal m_fontSpaceSize = 0.0;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename Value>
|
template<typename Value>
|
||||||
using XFA_Attribute = PDFXFAValueHolder<Value, XFA_InplaceTag>;
|
using XFA_Attribute = PDFXFAValueHolder<Value, XFA_InplaceTag>;
|
||||||
|
|
||||||
@ -131,6 +147,8 @@ public:
|
|||||||
constexpr PDFReal getValue() const { return m_value; }
|
constexpr PDFReal getValue() const { return m_value; }
|
||||||
constexpr Type getType() const { return m_type; }
|
constexpr Type getType() const { return m_type; }
|
||||||
|
|
||||||
|
PDFReal getValuePt(const XFA_ParagraphSettings* paragraphSettings) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PDFReal m_value;
|
PDFReal m_value;
|
||||||
Type m_type;
|
Type m_type;
|
||||||
@ -288,9 +306,19 @@ public:
|
|||||||
const Container& container,
|
const Container& container,
|
||||||
const Containers&... containers)
|
const Containers&... containers)
|
||||||
{
|
{
|
||||||
for (const auto& node : container)
|
if constexpr (std::is_convertible<Container, const xfa::XFA_AbstractNode*>::value)
|
||||||
{
|
{
|
||||||
nodes.push_back(node.getValue());
|
if (container)
|
||||||
|
{
|
||||||
|
nodes.push_back(container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (const auto& node : container)
|
||||||
|
{
|
||||||
|
nodes.push_back(node.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addNodesToContainer(nodes, containers...);
|
addNodesToContainer(nodes, containers...);
|
||||||
@ -328,6 +356,56 @@ void XFA_AbstractNode::setOrderFromElement(const QDomElement& element)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFReal XFA_ParagraphSettings::getFontEmSize() const
|
||||||
|
{
|
||||||
|
return m_fontEmSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XFA_ParagraphSettings::setFontEmSize(const PDFReal& fontEmSize)
|
||||||
|
{
|
||||||
|
m_fontEmSize = fontEmSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFReal XFA_ParagraphSettings::getFontSpaceSize() const
|
||||||
|
{
|
||||||
|
return m_fontSpaceSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void XFA_ParagraphSettings::setFontSpaceSize(const PDFReal& fontSpaceSize)
|
||||||
|
{
|
||||||
|
m_fontSpaceSize = fontSpaceSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFReal XFA_Measurement::getValuePt(const XFA_ParagraphSettings* paragraphSettings) const
|
||||||
|
{
|
||||||
|
switch (m_type)
|
||||||
|
{
|
||||||
|
case pdf::xfa::XFA_Measurement::in:
|
||||||
|
return m_value * 72.0;
|
||||||
|
|
||||||
|
case pdf::xfa::XFA_Measurement::cm:
|
||||||
|
return m_value / 2.54 * 72.0;
|
||||||
|
|
||||||
|
case pdf::xfa::XFA_Measurement::mm:
|
||||||
|
return m_value / 25.4 * 72.0;
|
||||||
|
|
||||||
|
case pdf::xfa::XFA_Measurement::pt:
|
||||||
|
return m_value;
|
||||||
|
|
||||||
|
case pdf::xfa::XFA_Measurement::em:
|
||||||
|
return paragraphSettings ? m_value * paragraphSettings->getFontEmSize() : 0.0;
|
||||||
|
|
||||||
|
case pdf::xfa::XFA_Measurement::percent:
|
||||||
|
return paragraphSettings ? m_value * paragraphSettings->getFontSpaceSize() : 0.0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xfa
|
} // namespace xfa
|
||||||
|
|
||||||
/* START GENERATED CODE */
|
/* START GENERATED CODE */
|
||||||
@ -9454,60 +9532,134 @@ private:
|
|||||||
|
|
||||||
struct PageInfo
|
struct PageInfo
|
||||||
{
|
{
|
||||||
|
const xfa::XFA_pageArea* pageArea = nullptr;
|
||||||
PDFInteger pageIndex = 0;
|
PDFInteger pageIndex = 0;
|
||||||
PDFInteger contentBoxIndex = 0;
|
PDFInteger contentBoxIndex = 0;
|
||||||
QRectF mediaBox;
|
QRectF mediaBox;
|
||||||
QRectF contentBox;
|
QRectF contentBox;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LayoutParameters
|
||||||
|
{
|
||||||
|
xfa::XFA_BaseNode::PRESENCE presence = xfa::XFA_BaseNode::PRESENCE::Visible;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LayoutParametersStackGuard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit inline LayoutParametersStackGuard(PDFXFALayoutEngine* engine) :
|
||||||
|
m_engine(engine)
|
||||||
|
{
|
||||||
|
if (m_engine->m_layoutParameters.empty())
|
||||||
|
{
|
||||||
|
m_engine->m_layoutParameters.push(LayoutParameters());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_engine->m_layoutParameters.push(m_engine->m_layoutParameters.top());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~LayoutParametersStackGuard()
|
||||||
|
{
|
||||||
|
m_engine->m_layoutParameters.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PDFXFALayoutEngine* m_engine;
|
||||||
|
};
|
||||||
|
|
||||||
|
LayoutParameters& getLayoutParameters() { return m_layoutParameters.top(); }
|
||||||
|
|
||||||
std::vector<PageInfo> m_pages;
|
std::vector<PageInfo> m_pages;
|
||||||
|
std::stack<LayoutParameters> m_layoutParameters;
|
||||||
size_t m_currentPageIndex = 0;
|
size_t m_currentPageIndex = 0;
|
||||||
size_t m_maximalPageCount = 128;
|
size_t m_maximalPageCount = 128;
|
||||||
};
|
};
|
||||||
|
|
||||||
void PDFXFALayoutEngine::visit(const xfa::XFA_pageArea* node)
|
void PDFXFALayoutEngine::visit(const xfa::XFA_pageArea* node)
|
||||||
{
|
{
|
||||||
switch (node->getOddOrEven())
|
auto isPageAddPossible = [this, node]()
|
||||||
{
|
{
|
||||||
case pdf::xfa::XFA_BaseNode::ODDOREVEN::Any:
|
switch (node->getOddOrEven())
|
||||||
break;
|
|
||||||
|
|
||||||
case pdf::xfa::XFA_BaseNode::ODDOREVEN::Even:
|
|
||||||
{
|
{
|
||||||
// Can we add even page (old page must be odd)
|
case pdf::xfa::XFA_BaseNode::ODDOREVEN::Any:
|
||||||
if (m_pages.empty() || m_pages.back().pageIndex % 2 == 0)
|
break;
|
||||||
|
|
||||||
|
case pdf::xfa::XFA_BaseNode::ODDOREVEN::Even:
|
||||||
{
|
{
|
||||||
return;
|
// Can we add even page (old page must be odd)
|
||||||
|
if (m_pages.empty() || m_pages.back().pageIndex % 2 == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case pdf::xfa::XFA_BaseNode::ODDOREVEN::Odd:
|
||||||
|
{
|
||||||
|
// Can we add even page (old page must be odd)
|
||||||
|
if (m_pages.empty() && m_pages.back().pageIndex % 2 == 1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case pdf::xfa::XFA_BaseNode::ODDOREVEN::Odd:
|
return true;
|
||||||
{
|
};
|
||||||
// Can we add even page (old page must be odd)
|
|
||||||
if (m_pages.empty() && m_pages.back().pageIndex % 2 == 1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const PDFInteger max = getPageOrPageSetMaxOccurenceCount(node->getOccur());
|
const PDFInteger max = getPageOrPageSetMaxOccurenceCount(node->getOccur());
|
||||||
for (PDFInteger i = 0; i < max && !isMaximalPageCountReached(); ++i)
|
for (PDFInteger i = 0; i < max; ++i)
|
||||||
{
|
{
|
||||||
|
if (isMaximalPageCountReached() || !isPageAddPossible())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<xfa::XFA_Node<xfa::XFA_contentArea>>& contentAreas = node->getContentArea();
|
||||||
|
if (contentAreas.empty())
|
||||||
|
{
|
||||||
|
// Content area is empty... nothing to process at all.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const xfa::XFA_medium* medium = node->getMedium();
|
||||||
|
if (!medium)
|
||||||
|
{
|
||||||
|
// Page doesn't contain medium - which is required, so we will
|
||||||
|
// stop processing.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PDFReal shortPageSize = medium->getShort().getValuePt(nullptr);
|
||||||
|
const PDFReal longPageSize = medium->getLong().getValuePt(nullptr);
|
||||||
|
const bool paperOrientationPortrait = medium->getOrientation() == xfa::XFA_medium::ORIENTATION::Portrait;
|
||||||
|
QSizeF pageSize = paperOrientationPortrait ? QSizeF(shortPageSize, longPageSize) : QSizeF(longPageSize, shortPageSize);
|
||||||
|
|
||||||
|
PageInfo pageInfo;
|
||||||
|
pageInfo.pageIndex = m_pages.empty() ? 1 : m_pages.back().pageIndex + 1;
|
||||||
|
pageInfo.mediaBox = QRectF(QPointF(0, 0), pageSize);
|
||||||
|
pageInfo.contentBoxIndex = 0;
|
||||||
|
pageInfo.pageArea = node;
|
||||||
|
|
||||||
|
for (const auto& contentAreaNode : contentAreas)
|
||||||
|
{
|
||||||
|
const xfa::XFA_contentArea* contentArea = contentAreaNode.getValue();
|
||||||
|
|
||||||
|
const PDFReal x = contentArea->getX().getValuePt(nullptr);
|
||||||
|
const PDFReal y = contentArea->getY().getValuePt(nullptr);
|
||||||
|
const PDFReal w = contentArea->getW().getValuePt(nullptr);
|
||||||
|
const PDFReal h = contentArea->getH().getValuePt(nullptr);
|
||||||
|
|
||||||
|
pageInfo.contentBox = QRectF(x, y, w, h);
|
||||||
|
m_pages.push_back(pageInfo);
|
||||||
|
|
||||||
|
++pageInfo.contentBoxIndex;
|
||||||
|
}
|
||||||
|
xfa::XFA_AbstractNode::acceptOrdered(this, node->getArea(), node->getDraw(), node->getExclGroup(), node->getField(), node->getSubform());
|
||||||
}
|
}
|
||||||
/* const XFA_desc* getDesc() const { return m_desc.getValue(); }
|
|
||||||
const XFA_extras* getExtras() const { return m_extras.getValue(); }
|
|
||||||
const XFA_medium* getMedium() const { return m_medium.getValue(); }
|
|
||||||
const XFA_occur* getOccur() const { return m_occur.getValue(); }
|
|
||||||
const std::vector<XFA_Node<XFA_area>>& getArea() const { return m_area; }
|
|
||||||
const std::vector<XFA_Node<XFA_contentArea>>& getContentArea() const { return m_contentArea; }
|
|
||||||
const std::vector<XFA_Node<XFA_draw>>& getDraw() const { return m_draw; }
|
|
||||||
const std::vector<XFA_Node<XFA_exclGroup>>& getExclGroup() const { return m_exclGroup; }
|
|
||||||
const std::vector<XFA_Node<XFA_field>>& getField() const { return m_field; }
|
|
||||||
const std::vector<XFA_Node<XFA_subform>>& getSubform() const { return m_subform; }*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFXFALayoutEngine::visit(const xfa::XFA_pageSet* node)
|
void PDFXFALayoutEngine::visit(const xfa::XFA_pageSet* node)
|
||||||
@ -9550,6 +9702,48 @@ void PDFXFALayoutEngine::visit(const xfa::XFA_subformSet* node)
|
|||||||
|
|
||||||
void PDFXFALayoutEngine::visit(const xfa::XFA_subform* node)
|
void PDFXFALayoutEngine::visit(const xfa::XFA_subform* node)
|
||||||
{
|
{
|
||||||
|
switch (node->getPresence())
|
||||||
|
{
|
||||||
|
case xfa::XFA_BaseNode::PRESENCE::Visible:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case xfa::XFA_BaseNode::PRESENCE::Hidden:
|
||||||
|
case xfa::XFA_BaseNode::PRESENCE::Inactive:
|
||||||
|
return;
|
||||||
|
|
||||||
|
case xfa::XFA_BaseNode::PRESENCE::Invisible:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutParametersStackGuard guard(this);
|
||||||
|
getLayoutParameters().presence = node->getPresence();
|
||||||
|
|
||||||
|
// Handle break before
|
||||||
|
handleBreak(node->getBreak(), true);
|
||||||
|
handleBreak(node->getBreakBefore());
|
||||||
|
|
||||||
|
// Perform layout, layout subforms so many times
|
||||||
|
const PDFInteger occurenceCount = getOccurenceCount(node->getOccur());
|
||||||
|
for (PDFInteger index = 0; index < occurenceCount; ++index)
|
||||||
|
{
|
||||||
|
xfa::XFA_AbstractNode::acceptOrdered(this,
|
||||||
|
node->getSubform(),
|
||||||
|
node->getSubformSet(),
|
||||||
|
node->getField(),
|
||||||
|
node->getExclGroup(),
|
||||||
|
node->getDraw(),
|
||||||
|
node->getArea(),
|
||||||
|
node->getPageSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle break after
|
||||||
|
handleBreak(node->getBreak(), false);
|
||||||
|
handleBreak(node->getBreakAfter());
|
||||||
|
|
||||||
|
/*
|
||||||
|
const XFA_border* getBorder() const { return m_border.getValue(); }
|
||||||
|
const XFA_margin* getMargin() const { return m_margin.getValue(); }
|
||||||
|
const XFA_para* getPara() const { return m_para.getValue(); }*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFXFALayoutEngine::moveToNextArea(ContentAreaScope scope)
|
void PDFXFALayoutEngine::moveToNextArea(ContentAreaScope scope)
|
||||||
|
Reference in New Issue
Block a user