sd/qa/unit/data/odp/tdf168109.fodp | 65 +++++++++++++++++++++++++++++++++++++ sd/qa/unit/import-tests2.cxx | 31 +++++++++++++++++ xmloff/source/draw/ximpbody.cxx | 5 +- xmloff/source/draw/ximpnote.cxx | 17 +++++++++ xmloff/source/draw/ximpnote.hxx | 11 +++++- xmloff/source/draw/ximpshap.cxx | 2 - xmloff/source/draw/ximpshap.hxx | 5 ++ 7 files changed, 130 insertions(+), 6 deletions(-)
New commits: commit 5a288cb885ac3483173c447101864b037a216a67 Author: Mike Kaganski <[email protected]> AuthorDate: Thu Feb 12 19:11:29 2026 +0500 Commit: Miklos Vajna <[email protected]> CommitDate: Fri Feb 13 09:24:30 2026 +0100 tdf#168109: Ignore draw:page-number attribute for notes' thumbnails ODF 1.4 Part 3 sect. 19.203 draw:page-number tells: > For thumbnails on notes pages, the value of this attribute is fixed > to the drawing page of a notes page. As further clarified in OASIS ODF TC call from 2025-11-24 for issue OFFICE-4178, that wording shall be improved to unambiguously point to exactly the drawing page of the respective notes page. This means, that for thumbnail of DrawingPage's notes page, the actual value of the attribute is unimportant. As the bugdoc shows, the attribute may be missing. It may also possibly have wrong number. In any case, we should not break the default correct reference established between the thumbnail object and respective DrawingPage, when thumbnail was created. This change implements just that. For SdXMLPageShapeContext, it adds a new method ignorePageNumber, which sets mnPageNumber to -1. Given that this value corresponds to draw:page-number, having XML type positiveInteger, this special value is safe and cannot coincide with any valid value there. Its meaning is "do not set the shape's page number", which will keep the mentioned original reference. ignorePageNumber is only called in the context of DrawingPage/notes page: the "ignore" flag is passed through SdXMLNotesContext from SdXMLDrawPageContext::createFastChildContext. For notes of master page, handled in SdXMLMasterPageContext::createFastChildContext, no change is done. Change-Id: I39ef16d4e0ceda89b38ee994c908157e93c119a2 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199283 Reviewed-by: Mike Kaganski <[email protected]> Tested-by: Jenkins (cherry picked from commit 5a0d14eb62dcccfd8f6185b9f493d6e1ff3f4bf1) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199298 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/sd/qa/unit/data/odp/tdf168109.fodp b/sd/qa/unit/data/odp/tdf168109.fodp new file mode 100644 index 000000000000..9a38821214a3 --- /dev/null +++ b/sd/qa/unit/data/odp/tdf168109.fodp @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.presentation"> + <office:styles> + <style:style style:name="standard" style:family="graphic"> + <style:graphic-properties draw:fill="none"/> + </style:style> + </office:styles> + <office:body> + <office:presentation> + <draw:page> + <draw:frame svg:width="20cm" svg:height="3cm" svg:x="5mm" svg:y="5mm" presentation:class="title"> + <draw:text-box> + <text:p>Slide One</text:p> + </draw:text-box> + </draw:frame> + <draw:frame svg:width="20cm" svg:height="9cm" svg:x="5mm" svg:y="4cm" presentation:class="outline"> + <draw:text-box> + <text:list> + <text:list-item> + <text:p>One</text:p> + </text:list-item> + <text:list-item> + <text:p>Two</text:p> + </text:list-item> + </text:list> + </draw:text-box> + </draw:frame> + <presentation:notes> + <!-- First case: the 'draw:page-number' attribute is missing --> + <draw:page-thumbnail svg:width="20cm" svg:height="11cm" svg:x="5mm" svg:y="5mm" presentation:class="page"/> + <draw:frame svg:width="20cm" svg:height="13cm" svg:x="5mm" svg:y="12cm"> + <draw:text-box/> + </draw:frame> + </presentation:notes> + </draw:page> + <draw:page> + <draw:frame svg:width="20cm" svg:height="3cm" svg:x="5mm" svg:y="5mm" presentation:class="title"> + <draw:text-box> + <text:p>Slide Two</text:p> + </draw:text-box> + </draw:frame> + <draw:frame svg:width="20cm" svg:height="9cm" svg:x="5mm" svg:y="4cm" presentation:class="outline"> + <draw:text-box> + <text:list> + <text:list-item> + <text:p>Foo</text:p> + </text:list-item> + <text:list-item> + <text:p>Bar</text:p> + </text:list-item> + </text:list> + </draw:text-box> + </draw:frame> + <presentation:notes> + <!-- Second case: the 'draw:page-number' attribute is wrong --> + <draw:page-thumbnail svg:width="20cm" svg:height="11cm" svg:x="5mm" svg:y="5mm" draw:page-number="1" presentation:class="page"/> + <draw:frame svg:width="20cm" svg:height="13cm" svg:x="5mm" svg:y="12cm"> + <draw:text-box/> + </draw:frame> + </presentation:notes> + </draw:page> + </office:presentation> + </office:body> +</office:document> \ No newline at end of file diff --git a/sd/qa/unit/import-tests2.cxx b/sd/qa/unit/import-tests2.cxx index 9371ecd7baf8..37f6a367949a 100644 --- a/sd/qa/unit/import-tests2.cxx +++ b/sd/qa/unit/import-tests2.cxx @@ -2249,6 +2249,37 @@ CPPUNIT_TEST_FIXTURE(SdImportTest2, testTdf169524) CPPUNIT_ASSERT_EQUAL(sal_Int32(18073), nHeight); } +CPPUNIT_TEST_FIXTURE(SdImportTest2, testTdf168109) +{ + createSdImpressDoc("odp/tdf168109.fodp"); + + // Slide 1 + { + auto xPage = getPage(0).queryThrow<presentation::XPresentationPage>(); + auto xNotesPage = xPage->getNotesPage(); + auto xThumbnail = getShape(0, xNotesPage); + auto xDescriptor = xThumbnail.queryThrow<drawing::XShapeDescriptor>(); + + CPPUNIT_ASSERT_EQUAL(u"com.sun.star.presentation.PageShape"_ustr, + xDescriptor->getShapeType()); + CPPUNIT_ASSERT_EQUAL(uno::Any(sal_Int32(1)), + xThumbnail->getPropertyValue(u"PageNumber"_ustr)); + } + + // Slide 2 + { + auto xPage = getPage(1).queryThrow<presentation::XPresentationPage>(); + auto xNotesPage = xPage->getNotesPage(); + auto xThumbnail = getShape(0, xNotesPage); + auto xDescriptor = xThumbnail.queryThrow<drawing::XShapeDescriptor>(); + + CPPUNIT_ASSERT_EQUAL(u"com.sun.star.presentation.PageShape"_ustr, + xDescriptor->getShapeType()); + CPPUNIT_ASSERT_EQUAL(uno::Any(sal_Int32(2)), + xThumbnail->getPropertyValue(u"PageNumber"_ustr)); + } +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpbody.cxx b/xmloff/source/draw/ximpbody.cxx index f1f19a156ffa..591832735414 100644 --- a/xmloff/source/draw/ximpbody.cxx +++ b/xmloff/source/draw/ximpbody.cxx @@ -247,8 +247,9 @@ css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLDrawPageContext: uno::Reference< drawing::XDrawPage > xNotesDrawPage = xPresPage->getNotesPage(); if(xNotesDrawPage.is()) { - // presentation:notes inside draw:page context - return new SdXMLNotesContext( GetSdImport(), xAttrList, xNotesDrawPage); + // presentation:notes inside draw:page context. Inside notes, thumbnails + // are fixed to this page, and actual page number attribute must be ignored + return new SdXMLNotesContext(GetSdImport(), xAttrList, xNotesDrawPage, true); } } } diff --git a/xmloff/source/draw/ximpnote.cxx b/xmloff/source/draw/ximpnote.cxx index d855e85bf4ad..9035648cb9ed 100644 --- a/xmloff/source/draw/ximpnote.cxx +++ b/xmloff/source/draw/ximpnote.cxx @@ -18,6 +18,7 @@ */ #include "ximpnote.hxx" +#include "ximpshap.hxx" #include <xmloff/xmlnamespace.hxx> using namespace ::com::sun::star; @@ -25,8 +26,9 @@ using namespace ::xmloff::token; SdXMLNotesContext::SdXMLNotesContext( SdXMLImport& rImport, const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList, - uno::Reference<drawing::XShapes> const& rShapes) + uno::Reference<drawing::XShapes> const& rShapes, bool ignorePageNumberInThumbnail) : SdXMLGenericPageContext(rImport, xAttrList, rShapes) + , mbIgnorePageNumberInThumbnail(ignorePageNumberInThumbnail) { OUString sStyleName, sPageMasterName; @@ -89,4 +91,17 @@ SdXMLNotesContext::SdXMLNotesContext( SdXMLNotesContext::~SdXMLNotesContext() {} +uno::Reference<xml::sax::XFastContextHandler> SdXMLNotesContext::createFastChildContext( + sal_Int32 nElement, const uno::Reference<xml::sax::XFastAttributeList>& xAttrList) +{ + auto pContext = SdXMLGenericPageContext::createFastChildContext(nElement, xAttrList); + if (nElement == XML_ELEMENT(DRAW, XML_PAGE_THUMBNAIL) && mbIgnorePageNumberInThumbnail) + { + assert(dynamic_cast<SdXMLPageShapeContext*>(pContext.get())); + auto pPageShapeContext = static_cast<SdXMLPageShapeContext*>(pContext.get()); + pPageShapeContext->ignorePageNumber(); + } + return pContext; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpnote.hxx b/xmloff/source/draw/ximpnote.hxx index d7fe276b84eb..2048fc36ea62 100644 --- a/xmloff/source/draw/ximpnote.hxx +++ b/xmloff/source/draw/ximpnote.hxx @@ -29,8 +29,17 @@ class SdXMLNotesContext : public SdXMLGenericPageContext public: SdXMLNotesContext( SdXMLImport& rImport, const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, - css::uno::Reference< css::drawing::XShapes > const & rShapes); + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool ignorePageNumberInThumbnail = false); virtual ~SdXMLNotesContext() override; + + // XFastContextHandler + virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) override; + +private: + bool mbIgnorePageNumberInThumbnail; }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpshap.cxx b/xmloff/source/draw/ximpshap.cxx index 7b00b3ec94ff..e585716deabf 100644 --- a/xmloff/source/draw/ximpshap.cxx +++ b/xmloff/source/draw/ximpshap.cxx @@ -2247,7 +2247,7 @@ void SdXMLPageShapeContext::startFastElement (sal_Int32 nElement, SetTransformation(); uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); - if(xPropSet.is()) + if (xPropSet.is() && mnPageNumber >= 0) // mnPageNumber < 0 means "ignore" { uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); static constexpr OUString aPageNumberStr(u"PageNumber"_ustr); diff --git a/xmloff/source/draw/ximpshap.hxx b/xmloff/source/draw/ximpshap.hxx index 6a00cb252e5f..640cf26fdb5b 100644 --- a/xmloff/source/draw/ximpshap.hxx +++ b/xmloff/source/draw/ximpshap.hxx @@ -340,7 +340,7 @@ public: virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; }; -// draw:page context +// draw:thumbnail context class SdXMLPageShapeContext : public SdXMLShapeContext { @@ -359,6 +359,9 @@ public: // this is called from the parent group for each unparsed attribute in the attribute list virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; + + // Do not try to set page number to the thumbnail (keep the default association) + void ignorePageNumber() { mnPageNumber = -1; } }; // draw:caption context
