XFA: form pagination

This commit is contained in:
Jakub Melka 2021-12-12 20:10:48 +01:00
parent 38bc1f40fc
commit ecd04a8668
7 changed files with 109 additions and 2 deletions

View File

@ -504,6 +504,7 @@ public:
Annotation = 0x0002, ///< Annotations changed
FormField = 0x0004, ///< Form field content changed
Authorization = 0x0008, ///< Authorization has changed (for example, old document is granted user access, but for new, owner access)
XFA_Pagination = 0x0010, ///< XFA pagination has been performed (this flag can be set only when Reset flag has been set and not any other flag)
};
Q_DECLARE_FLAGS(ModificationFlags, ModificationFlag)

View File

@ -1515,6 +1515,7 @@ public:
void markReset() { m_modificationFlags.setFlag(PDFModifiedDocument::Reset); }
void markAnnotationsChanged() { m_modificationFlags.setFlag(PDFModifiedDocument::Annotation); }
void markFormFieldChanged() { m_modificationFlags.setFlag(PDFModifiedDocument::FormField); }
void markXFAPagination() { m_modificationFlags.setFlag(PDFModifiedDocument::XFA_Pagination); }
private:
const PDFDocument* m_originalDocument;

View File

@ -1668,6 +1668,75 @@ void PDFFormManager::drawXFAForm(const QMatrix& pagePointToDevicePointMatrix,
}
}
void PDFFormManager::performPaging()
{
if (!hasXFAForm() || !m_document)
{
return;
}
std::vector<QSizeF> pageSizes = m_xfaEngine.getPageSizes();
const PDFCatalog* catalog = m_document->getCatalog();
const size_t pageCount = catalog->getPageCount();
std::vector<QSizeF> oldPageSizes;
oldPageSizes.reserve(pageCount);
for (size_t i = 0; i < pageCount; ++i)
{
oldPageSizes.push_back(catalog->getPage(i)->getMediaBox().size());
}
bool changed = pageSizes.size() != oldPageSizes.size();
if (!changed)
{
for (size_t i = 0; i < pageCount; ++i)
{
changed = changed ||
!qFuzzyCompare(pageSizes[i].width(), oldPageSizes[i].width()) ||
!qFuzzyCompare(pageSizes[i].height(), oldPageSizes[i].height());
}
}
if (changed && !oldPageSizes.empty())
{
PDFDocumentModifier modifier(m_document);
modifier.getBuilder()->setFormManager(this);
modifier.markReset();
PDFDocumentBuilder* builder = modifier.getBuilder();
builder->flattenPageTree();
std::vector<PDFObjectReference> pages = builder->getPages();
// Do we have more pages?
if (pages.size() > pageSizes.size())
{
pages.resize(pageSizes.size());
}
// Do we have less pages?
while (pages.size() < pageSizes.size())
{
std::vector<pdf::PDFObjectReference> references = pdf::PDFDocumentBuilder::createReferencesFromObjects(builder->copyFrom(pdf::PDFDocumentBuilder::createObjectsFromReferences({ pages.front() }), *builder->getStorage(), true));
Q_ASSERT(references.size() == 1);
pages.push_back(references.front());
}
Q_ASSERT(pages.size() == pageSizes.size());
for (size_t i = 0; i < pages.size(); ++i)
{
builder->setPageMediaBox(pages[i], QRectF(QPointF(0, 0), pageSizes[i]));
}
builder->setPages(std::move(pages));
if (modifier.finalize())
{
emit documentModified(PDFModifiedDocument(modifier.getDocument(), nullptr, modifier.getFlags()));
}
}
}
void PDFFormManager::clearEditors()
{
qDeleteAll(m_widgetEditors);

View File

@ -687,6 +687,11 @@ public:
QList<PDFRenderError>& errors,
QPainter* painter);
/// Performs paging, when XFA form needs to change page count and size.
/// If some change needs to be done, then signal \p documentModified
/// is emitted.
void performPaging();
virtual int getInputPriority() const override { return FormPriority; }
signals:

View File

@ -9679,8 +9679,11 @@ public:
using LayoutItems = std::vector<LayoutItem>;
void setLayoutItems(PDFInteger pageIndex, LayoutItems layoutItems) { m_layout.layoutItems[pageIndex] = std::move(layoutItems); }
void setParagraphSettings(std::vector<xfa::XFA_ParagraphSettings> paragraphSettings) { m_layout.paragraphSettings = std::move(paragraphSettings); }
std::vector<QSizeF> getPageSizes() const { return m_layout.pageSizes; }
inline void setPageSizes(std::vector<QSizeF> pageSizes) { m_layout.pageSizes = std::move(pageSizes); }
inline void setLayoutItems(PDFInteger pageIndex, LayoutItems layoutItems) { m_layout.layoutItems[pageIndex] = std::move(layoutItems); }
inline void setParagraphSettings(std::vector<xfa::XFA_ParagraphSettings> paragraphSettings) { m_layout.paragraphSettings = std::move(paragraphSettings); }
void draw(const QMatrix& pagePointToDevicePointMatrix,
const PDFPage* page,
@ -9691,6 +9694,7 @@ private:
struct Layout
{
std::vector<QSizeF> pageSizes;
std::map<PDFInteger, LayoutItems> layoutItems;
std::vector<xfa::XFA_ParagraphSettings> paragraphSettings;
};
@ -10648,6 +10652,7 @@ void PDFXFALayoutEngine::performLayout(PDFXFAEngineImpl* engine, const xfa::XFA_
node->accept(this);
std::vector<QSizeF> pageSizes;
std::map<PDFInteger, std::vector<Layout>> layoutPerPage;
for (Layout& layout : m_layout)
@ -10661,6 +10666,8 @@ void PDFXFALayoutEngine::performLayout(PDFXFAEngineImpl* engine, const xfa::XFA_
layoutPerPage[layout.pageIndex].emplace_back(std::move(layout));
}
pageSizes.reserve(layoutPerPage.size());
PDFInteger pageIndex = 0;
for (const auto& layoutSinglePage : layoutPerPage)
{
@ -10688,9 +10695,13 @@ void PDFXFALayoutEngine::performLayout(PDFXFAEngineImpl* engine, const xfa::XFA_
}
}
const PageInfo& pageInfo = m_pages.at(layoutSinglePage.first);
pageSizes.push_back(pageInfo.mediaBox.size());
engine->setLayoutItems(pageIndex++, std::move(layoutItems));
}
engine->setPageSizes(std::move(pageSizes));
engine->setParagraphSettings(std::move(m_paragraphSettings));
}
@ -11364,6 +11375,11 @@ void PDFXFAEngine::setDocument(const PDFModifiedDocument& document, PDFForm* for
m_impl->setDocument(document, form);
}
std::vector<QSizeF> PDFXFAEngine::getPageSizes() const
{
return m_impl->getPageSizes();
}
void PDFXFAEngine::draw(const QMatrix& pagePointToDevicePointMatrix,
const PDFPage* page,
QList<PDFRenderError>& errors,
@ -11381,6 +11397,13 @@ PDFXFAEngineImpl::PDFXFAEngineImpl() :
void PDFXFAEngineImpl::setDocument(const PDFModifiedDocument& document, PDFForm* form)
{
if (document.hasFlag(PDFModifiedDocument::XFA_Pagination))
{
// Do nothing - pagination of XFA was performed,
// nothing else has changed.
return;
}
if (m_document != document || document.hasReset())
{
m_document = document;

View File

@ -38,6 +38,9 @@ public:
void setDocument(const PDFModifiedDocument& document, PDFForm* form);
/// Returns list of page sizes (after paging is complete)
std::vector<QSizeF> getPageSizes() const;
/// Draws XFA form
/// \param pagePointToDevicePointMatrix Page point to device point matrix
/// \param page Page

View File

@ -1562,6 +1562,11 @@ void PDFProgramController::onDocumentReadingFinished()
pdf::PDFModifiedDocument document(m_pdfDocument.data(), m_optionalContentActivity);
setDocument(document);
if (m_formManager)
{
m_formManager->performPaging();
}
pdf::PDFDocumentRequirements requirements = pdf::PDFDocumentRequirements::parse(&m_pdfDocument->getStorage(), m_pdfDocument->getCatalog()->getRequirements());
constexpr pdf::PDFDocumentRequirements::Requirements requirementFlags = pdf::PDFDocumentRequirements::Requirements(pdf::PDFDocumentRequirements::OCInteract |
pdf::PDFDocumentRequirements::OCAutoStates |