tdf#151746 Fix background export for SVG in Draw

Currently, any background that is added in normal page view does
not display when Draw exports an SVG file. This is because the
background is wrapped in defs tags. This is okay in Impress because
of the presentation engine, but these tags should be removed for Draw.

Additionally, once these tags are removed from SVG export in Draw,
there is a side-effect where the background is drawn on top of the
master page shapes. This has been fixed by wrapping the master page
shapes in defs tags and referencing them later.

Change-Id: I878bea24426fa2dc59868aa595fb90d4c455f473
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200000
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Daniel Lee
2026-05-18 10:22:34 +02:00
committed by Xisco Fauli
parent ff6dea0a32
commit 28d7150170
4 changed files with 76 additions and 25 deletions
+39 -15
View File
@@ -2005,7 +2005,9 @@ bool SVGFilter::implExportPage( std::u16string_view sPageId,
// Slide custom background, if any, is referenced at a different position
// in order to not overlap background objects.
std::unique_ptr<SvXMLElementExport> xDefsExp;
if (!bMaster) // insert the <defs> open tag related to the slide background
// tdf#151746
// Do not use def tags for Draw as it hides the background
if ( !bMaster && mbPresentation ) // insert the <defs> open tag related to the slide background
{
mpSVGExport->AddAttribute(u"class"_ustr, u"SlideBackground"_ustr);
xDefsExp.reset(new SvXMLElementExport(*mpSVGExport, u"defs"_ustr, true, true));
@@ -2047,27 +2049,49 @@ bool SVGFilter::implExportPage( std::u16string_view sPageId,
// into a group element, this group will make up the so named "background objects"
if( bMaster )
{
// background objects id = "bo-" + page id
OUString sBackgroundObjectsId = OUString::Concat("bo-") + sPageId;
mpSVGExport->AddAttribute(u"id"_ustr, sBackgroundObjectsId);
if( !mbPresentation )
// tdf#151746
// For Draw, we want to wrap the Master Background Objects in defs tags so
// they can be drawn on top of the normal page background later
std::unique_ptr<SvXMLElementExport> xDefsExp;
if (!mbPresentation)
{
if( !mVisiblePagePropSet.bAreBackgroundObjectsVisible )
{
mpSVGExport->AddAttribute(u"visibility"_ustr, u"hidden"_ustr);
}
xDefsExp.reset(new SvXMLElementExport(*mpSVGExport, u"defs"_ustr, true, true));
}
mpSVGExport->AddAttribute(u"class"_ustr, u"BackgroundObjects"_ustr);
// insert the <g> open tag related to the Background Objects
SvXMLElementExport aExp2(*mpSVGExport, u"g"_ustr, true, true);
{
// background objects id = "bo-" + page id
OUString sBackgroundObjectsId = OUString::Concat("bo-") + sPageId;
mpSVGExport->AddAttribute(u"id"_ustr, sBackgroundObjectsId);
if (!mbPresentation)
{
if (!mVisiblePagePropSet.bAreBackgroundObjectsVisible)
{
mpSVGExport->AddAttribute(u"visibility"_ustr, u"hidden"_ustr);
}
}
mpSVGExport->AddAttribute(u"class"_ustr, u"BackgroundObjects"_ustr);
// append all shapes that make up the Master Slide
bRet = implExportShapes( xShapes, true ) || bRet;
} // append the </g> closing tag related to the Background Objects
// insert the <g> open tag related to the Background Objects
SvXMLElementExport aExp2(*mpSVGExport, u"g"_ustr, true, true);
// append all shapes that make up the Master Slide
bRet = implExportShapes(xShapes, true) || bRet;
} // append the </g> closing tag related to the Background Objects
} // append the </defs> closing tag related to the Background Objects
else
{
// tdf#151746
// For Draw, we want to reference the Master Background Objects after the normal page
// background but before the shapes that make up the slides
if ( !mMasterPageTargets.empty() && !mbPresentation )
{
std::u16string_view sMasterPageId = implGetValidIDFromInterface(mMasterPageTargets[0]);
OUString sMasterObjectsRef = OUString::Concat("#bo-") + sMasterPageId;
mpSVGExport->AddAttribute(u"href"_ustr, sMasterObjectsRef);
SvXMLElementExport aUseElem(*mpSVGExport, u"use"_ustr, true, true);
}
// append all shapes that make up the Slide
bRet = implExportShapes( xShapes, false ) || bRet;
}
} // append the </g> closing tag related to the Slide/Master_Slide
+1 -1
View File
@@ -52,6 +52,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sd,\
CppunitTest_sd_activex_controls_tests \
CppunitTest_sd_pdf_import_test \
CppunitTest_sd_png_export_tests \
CppunitTest_sd_svg_export_tests \
CppunitTest_sd_filter_eppt \
CppunitTest_sd_shape_import_export_tests \
CppunitTest_sd_a11y \
@@ -65,7 +66,6 @@ endif
ifneq ($(DISABLE_GUI),TRUE)
ifeq ($(OS),LINUX)
$(eval $(call gb_Module_add_slowcheck_targets,sd,\
CppunitTest_sd_svg_export_tests \
CppunitTest_sd_tiledrendering \
CppunitTest_sd_tiledrendering2 \
CppunitTest_sd_lokit_search \
+36 -9
View File
@@ -71,13 +71,13 @@ class SdSVGFilterTest : public UnoApiTest
{
public:
SdSVGFilterTest()
: UnoApiTest(u"/sd/qa/unit/data/odp/"_ustr)
: UnoApiTest(u"/sd/qa/unit/data/"_ustr)
{
}
void testSVGExportTextDecorations()
{
loadFromFile(u"svg-export-text-decorations.odp");
loadFromFile(u"odp/svg-export-text-decorations.odp");
save(TestFilter::SVG_IMPRESS);
xmlDocUniquePtr svgDoc = parseXml(maTempFile);
@@ -100,7 +100,7 @@ public:
void testSVGExportJavascriptURL()
{
loadFromFile(u"textbox-link-javascript.odp");
loadFromFile(u"odp/textbox-link-javascript.odp");
save(TestFilter::SVG_IMPRESS);
xmlDocUniquePtr svgDoc = parseXml(maTempFile);
@@ -115,7 +115,7 @@ public:
void testSVGExportSlideCustomBackground()
{
loadFromFile(u"slide-custom-background.odp");
loadFromFile(u"odp/slide-custom-background.odp");
save(TestFilter::SVG_IMPRESS);
xmlDocUniquePtr svgDoc = parseXml(maTempFile);
@@ -126,7 +126,7 @@ public:
void testSVGExportTextFieldsInMasterPage()
{
loadFromFile(u"text-fields.odp");
loadFromFile(u"odp/text-fields.odp");
save(TestFilter::SVG_IMPRESS);
xmlDocUniquePtr svgDoc = parseXml(maTempFile);
@@ -150,7 +150,7 @@ public:
void testSVGExportEmbeddedVideo()
{
loadFromFile(u"slide-video-thumbnail.odp");
loadFromFile(u"odp/slide-video-thumbnail.odp");
save(TestFilter::SVG_IMPRESS);
xmlDocUniquePtr svgDoc = parseXml(maTempFile);
@@ -181,7 +181,7 @@ public:
void testSVGExportSlideBitmapBackground()
{
loadFromFile(u"slide-bitmap-background.odp");
loadFromFile(u"odp/slide-bitmap-background.odp");
save(TestFilter::SVG_IMPRESS);
xmlDocUniquePtr svgDoc = parseXml(maTempFile);
@@ -210,7 +210,7 @@ public:
void testSVGExportSlideTileBitmapBackground()
{
loadFromFile(u"slide-tile-background.odp");
loadFromFile(u"odp/slide-tile-background.odp");
save(TestFilter::SVG_IMPRESS);
xmlDocUniquePtr svgDoc = parseXml(maTempFile);
@@ -275,7 +275,7 @@ public:
aSettings.SetLanguageTag(aLangISO, true);
Application::SetSettings(aSettings);
loadFromFile(u"text-fields.odp");
loadFromFile(u"odp/text-fields.odp");
save(TestFilter::SVG_IMPRESS);
xmlDocUniquePtr svgDoc = parseXml(maTempFile);
@@ -292,6 +292,32 @@ public:
assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_DEFS[8]/SVG_G[2]/SVG_G[2]/SVG_G[7]/SVG_G/SVG_TEXT/SVG_TSPAN/SVG_TSPAN/SVG_TSPAN ), "class", u"PlaceholderText PageNumber");
}
// tdf#151746
void testSVGExportDrawBackground()
{
loadFromFile(u"odg/tdf151746.odg");
save(TestFilter::SVG_DRAW);
xmlDocUniquePtr svgDoc = parseExportedFile();
CPPUNIT_ASSERT(svgDoc);
// Check that the Master Background Objects are wrapped in defs tags
assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_G[1]/SVG_G ), "class", u"Master_Slide");
assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_G[1]/SVG_G/SVG_G[1] ), "class", u"Background");
assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_G[1]/SVG_G/SVG_DEFS/SVG_G ));
OUString sBgObjsId = getXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_G[1]/SVG_G/SVG_DEFS/SVG_G ), "id");
// Check that the Page Background is not wrapped in defs tags
assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_G[2]/SVG_G/SVG_G/SVG_G/SVG_G), "class", u"Page");
assertXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_G[2]/SVG_G/SVG_G/SVG_G/SVG_G/SVG_G[1]), "class", u"Background");
// Check that the Master Background Objects are referenced correctly
OUString sRef = getXPath(svgDoc, SAL_STRINGIFY( /SVG_SVG/SVG_G[2]/SVG_G/SVG_G/SVG_G/SVG_G/SVG_USE ), "href");
CPPUNIT_ASSERT_MESSAGE("The <use> element has not a valid href attribute: starting '#' not present.", sRef.startsWith("#"));
sRef = sRef.copy(1);
CPPUNIT_ASSERT_EQUAL_MESSAGE("The href attribute for <use> does not match the background objects id attribute: ", sBgObjsId, sRef);
}
CPPUNIT_TEST_SUITE(SdSVGFilterTest);
CPPUNIT_TEST(testSVGExportTextDecorations);
CPPUNIT_TEST(testSVGExportJavascriptURL);
@@ -301,6 +327,7 @@ public:
CPPUNIT_TEST(testSVGExportSlideBitmapBackground);
CPPUNIT_TEST(testSVGExportSlideTileBitmapBackground);
CPPUNIT_TEST(testSVGPlaceholderLocale);
CPPUNIT_TEST(testSVGExportDrawBackground);
CPPUNIT_TEST_SUITE_END();
};
Binary file not shown.