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 4ae705794f3ecaeb2f238a50f4fc4d50ebdb7590 Author: Mike Kaganski <[email protected]> AuthorDate: Thu Feb 12 19:11:29 2026 +0500 Commit: Adolfo Jayme Barrientos <[email protected]> CommitDate: Fri Feb 13 04:51:04 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/+/199303 Reviewed-by: Adolfo Jayme Barrientos <[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 cdae01a52184..5d534dc490a6 100644 --- a/sd/qa/unit/import-tests2.cxx +++ b/sd/qa/unit/import-tests2.cxx @@ -2298,6 +2298,37 @@ CPPUNIT_TEST_FIXTURE(SdImportTest2, testTdf169524) CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nLeftMargin); } +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 9e9a0ff55024..9675810e3f76 100644 --- a/xmloff/source/draw/ximpshap.cxx +++ b/xmloff/source/draw/ximpshap.cxx @@ -2246,7 +2246,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
