chart2/export_setup.mk                          |   60 -------------
 include/oox/export/drawingml.hxx                |   14 ++-
 oox/inc/drawingml/misccontexts.hxx              |    4 
 oox/source/core/xmlfilterbase.cxx               |    1 
 oox/source/drawingml/misccontexts.cxx           |   41 +++++++--
 oox/source/export/drawingml.cxx                 |  103 ++++++++++++++++++++++--
 oox/source/token/namespaces-strict.txt          |    1 
 oox/source/token/namespaces.txt                 |    1 
 oox/source/token/tokens.txt                     |    2 
 sd/qa/unit/data/odp/SvgImageTest.odp            |binary
 sd/qa/unit/export-tests.cxx                     |   44 ++++++++++
 sw/qa/extras/globalfilter/data/SvgImageTest.odt |binary
 sw/qa/extras/globalfilter/globalfilter.cxx      |   51 +++++++++++
 sw/qa/extras/ooxmlexport/data/SvgImageTest.odt  |binary
 sw/qa/extras/ooxmlexport/ooxmlexport18.cxx      |   27 ++++++
 sw/source/filter/ww8/docxattributeoutput.cxx    |   16 +++
 test/source/xmltesttools.cxx                    |    2 
 17 files changed, 287 insertions(+), 80 deletions(-)

New commits:
commit 1e7cd7da0b216557f836e3cb031bca47c2364b1e
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Mon Sep 25 09:03:54 2023 +0200
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Dec 10 12:37:35 2023 +0100

    tdf#126084 import svg image from ooxml document that use svgBlip elem.
    
    In an OOXML document the svg image is defined in an svgBlip, which
    is an OOXML extension. This change checks for the svgBlip element
    and imports that instead the normal "blip" element that is still
    provided as a fallback (PNG image).
    
    Add roundtrip SVG image test for ODF and OOXML, Impress and Writer.
    
    testGraphicBlipXLSX test failed after this change, because some
    component was missing. Changed to enable use_rdb for all chart2
    export tests, so issues like this won't happen anymore.
    
    Change-Id: Idf0e754775254d7dcfd0321dfca2ed6d00c42c09
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157238
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>
    (cherry picked from commit 1db193c6c744289139b1df2af0b8defcf974b238)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160384
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Andras Timar <andras.ti...@collabora.com>

diff --git a/chart2/export_setup.mk b/chart2/export_setup.mk
index b2bcf751111e..723df9897c4a 100644
--- a/chart2/export_setup.mk
+++ b/chart2/export_setup.mk
@@ -71,65 +71,7 @@ $(eval $(call gb_CppunitTest_use_sdk_api,chart2_export$(1)))
 
 $(eval $(call gb_CppunitTest_use_ure,chart2_export$(1)))
 $(eval $(call gb_CppunitTest_use_vcl,chart2_export$(1)))
-
-$(eval $(call gb_CppunitTest_use_components,chart2_export$(1),\
-    basic/util/sb \
-    animations/source/animcore/animcore \
-    chart2/source/controller/chartcontroller \
-    chart2/source/chartcore \
-    comphelper/util/comphelp \
-    configmgr/source/configmgr \
-    dbaccess/util/dba \
-    embeddedobj/util/embobj \
-    emfio/emfio \
-    eventattacher/source/evtatt \
-    filter/source/config/cache/filterconfig1 \
-    filter/source/odfflatxml/odfflatxml \
-    filter/source/storagefilterdetect/storagefd \
-    filter/source/xmlfilteradaptor/xmlfa \
-    filter/source/xmlfilterdetect/xmlfd \
-    forms/util/frm \
-    framework/util/fwk \
-    i18npool/util/i18npool \
-    linguistic/source/lng \
-    oox/util/oox \
-    package/source/xstor/xstor \
-    package/util/package2 \
-    sax/source/expatwrap/expwrap \
-    sc/util/sc \
-    sc/util/scd \
-    sc/util/scfilt \
-    sw/util/sw \
-    sw/util/swd \
-    sw/util/msword \
-    sd/util/sd \
-    sd/util/sdd \
-    $(call gb_Helper_optional,SCRIPTING, \
-           sc/util/vbaobj) \
-    scaddins/source/analysis/analysis \
-    scaddins/source/datefunc/date \
-    scripting/source/basprov/basprov \
-    scripting/util/scriptframe \
-    sfx2/util/sfx \
-    sot/util/sot \
-    svl/source/fsstor/fsstorage \
-    svl/util/svl \
-       svtools/util/svt \
-    svx/util/svx \
-    svx/util/svxcore \
-    toolkit/util/tk \
-    vcl/vcl.common \
-    ucb/source/core/ucb1 \
-    ucb/source/ucp/file/ucpfile1 \
-    ucb/source/ucp/tdoc/ucptdoc1 \
-    unotools/util/utl \
-    unoxml/source/rdf/unordf \
-    unoxml/source/service/unoxml \
-    uui/util/uui \
-    writerfilter/util/writerfilter \
-    xmloff/util/xo \
-    xmlscript/util/xmlscript \
-))
+$(eval $(call gb_CppunitTest_use_rdb,chart2_export$(1),services))
 
 $(eval $(call gb_CppunitTest_use_uiconfigs,chart2_export$(1), \
     modules/swriter \
diff --git a/oox/inc/drawingml/misccontexts.hxx 
b/oox/inc/drawingml/misccontexts.hxx
index c79816282ae7..1b7f05444ac7 100644
--- a/oox/inc/drawingml/misccontexts.hxx
+++ b/oox/inc/drawingml/misccontexts.hxx
@@ -102,7 +102,8 @@ class BlipExtensionContext final : public 
::oox::core::ContextHandler2
 public:
     explicit            BlipExtensionContext(
                             ::oox::core::ContextHandler2Helper const & rParent,
-                            BlipFillProperties& rBlipProps );
+                                BlipFillProperties& rBlipProps,
+                                model::BlipFill* pBlipFill);
     virtual             ~BlipExtensionContext() override;
 
     virtual ::oox::core::ContextHandlerRef
@@ -112,6 +113,7 @@ public:
 
 private:
     BlipFillProperties& mrBlipProps;
+    model::BlipFill* mpBlipFill;
 };
 
 
diff --git a/oox/source/core/xmlfilterbase.cxx 
b/oox/source/core/xmlfilterbase.cxx
index c2911a756047..9ed0cc4e6151 100644
--- a/oox/source/core/xmlfilterbase.cxx
+++ b/oox/source/core/xmlfilterbase.cxx
@@ -148,6 +148,7 @@ const Sequence< beans::Pair< OUString, sal_Int32 > >& 
NamespaceIds()
              NMSP_c15},
             
{"http://schemas.microsoft.com/office/spreadsheetml/2015/revision2";,
              NMSP_xr2},
+            {"http://schemas.microsoft.com/office/drawing/2016/SVG/main";, 
NMSP_asvg},
         };
     return SINGLETON;
 };
diff --git a/oox/source/drawingml/misccontexts.cxx 
b/oox/source/drawingml/misccontexts.cxx
index 25058d392600..e5b52c2de30d 100644
--- a/oox/source/drawingml/misccontexts.cxx
+++ b/oox/source/drawingml/misccontexts.cxx
@@ -366,7 +366,7 @@ ContextHandlerRef BlipContext::onCreateContext(
             return new DuotoneContext( *this, mrBlipProps );
 
         case A_TOKEN( extLst ):
-            return new BlipExtensionContext( *this, mrBlipProps );
+            return new BlipExtensionContext(*this, mrBlipProps, mpBlipFill);
 
         case A_TOKEN( lum ):
         {
@@ -595,9 +595,10 @@ SimpleFillPropertiesContext::~SimpleFillPropertiesContext()
     mrColor = getBestSolidColor();
 }
 
-BlipExtensionContext::BlipExtensionContext( ContextHandler2Helper const & 
rParent, BlipFillProperties& rBlipProps ) :
-    ContextHandler2( rParent ),
-    mrBlipProps( rBlipProps )
+BlipExtensionContext::BlipExtensionContext(ContextHandler2Helper const & 
rParent, BlipFillProperties& rBlipProps, model::BlipFill* pBlipFill)
+    : ContextHandler2(rParent)
+    , mrBlipProps(rBlipProps)
+    , mpBlipFill(pBlipFill)
 {
 }
 
@@ -605,16 +606,36 @@ BlipExtensionContext::~BlipExtensionContext()
 {
 }
 
-ContextHandlerRef BlipExtensionContext::onCreateContext(
-        sal_Int32 nElement, const AttributeList& )
+ContextHandlerRef BlipExtensionContext::onCreateContext(sal_Int32 nElement, 
const AttributeList& rAttribs)
 {
     switch( nElement )
     {
-        case A_TOKEN( ext ):
-            return new BlipExtensionContext( *this, mrBlipProps );
+        case A_TOKEN(ext):
+            return new BlipExtensionContext(*this, mrBlipProps, mpBlipFill);
+
+        case OOX_TOKEN(a14, imgProps):
+            return new ArtisticEffectContext(*this, mrBlipProps.maEffect);
+
+        // Import the SVG Blip
+        case OOX_TOKEN(asvg, svgBlip):
+        {
+            if (rAttribs.hasAttribute(R_TOKEN(embed)))
+            {
+                OUString aFragmentPath = 
getFragmentPathFromRelId(rAttribs.getStringDefaulted(R_TOKEN(embed)));
+                if (!aFragmentPath.isEmpty())
+                {
+                    // Read the graphic from the fragment path
+                    auto xGraphic = 
getFilter().getGraphicHelper().importEmbeddedGraphic(aFragmentPath);
 
-        case OOX_TOKEN( a14, imgProps ):
-            return new ArtisticEffectContext( *this, mrBlipProps.maEffect );
+                    // Overwrite the fill graphic with the one contining SVG
+                    mrBlipProps.mxFillGraphic = xGraphic;
+                    if (mpBlipFill)
+                        mpBlipFill->mxGraphic = xGraphic;
+                }
+            }
+            // TODO - link
+        }
+        break;
     }
     return nullptr;
 }
diff --git a/sd/qa/unit/data/odp/SvgImageTest.odp 
b/sd/qa/unit/data/odp/SvgImageTest.odp
new file mode 100644
index 000000000000..38b92df80896
Binary files /dev/null and b/sd/qa/unit/data/odp/SvgImageTest.odp differ
diff --git a/sd/qa/unit/export-tests.cxx b/sd/qa/unit/export-tests.cxx
index 029ee7267054..1c4bf622876a 100644
--- a/sd/qa/unit/export-tests.cxx
+++ b/sd/qa/unit/export-tests.cxx
@@ -103,6 +103,7 @@ public:
     void testCellProperties();
     void testUserTableStyles();
     void testTdf153179();
+    void testSvgImageSupport();
 
     CPPUNIT_TEST_SUITE(SdExportTest);
 
@@ -156,6 +157,7 @@ public:
     CPPUNIT_TEST(testCellProperties);
     CPPUNIT_TEST(testUserTableStyles);
     CPPUNIT_TEST(testTdf153179);
+    CPPUNIT_TEST(testSvgImageSupport);
     CPPUNIT_TEST_SUITE_END();
 
     virtual void registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) override
@@ -1858,6 +1860,48 @@ void SdExportTest::testTdf153179()
     CPPUNIT_ASSERT_EQUAL(sal_Int32(1), getPage(0)->getCount());
 }
 
+void SdExportTest::testSvgImageSupport()
+{
+    for (std::u16string_view rFormat : { u"impress8", u"Impress Office Open 
XML" })
+    {
+        // Load the original file
+        createSdImpressDoc("odp/SvgImageTest.odp");
+        // Save into the target format
+        saveAndReload(OUString(rFormat));
+
+        const OString sFailedMessage = "Failed on filter: " + 
OUString(rFormat).toUtf8();
+
+        // Check whether SVG graphic was exported as expected
+        uno::Reference<drawing::XDrawPagesSupplier> 
xDrawPagesSupplier(mxComponent,
+                                                                       
uno::UNO_QUERY_THROW);
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(1),
+                                     
xDrawPagesSupplier->getDrawPages()->getCount());
+        uno::Reference<drawing::XDrawPage> xDrawPage(
+            xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xDrawPage.is());
+
+        // Get the image
+        uno::Reference<drawing::XShape> xImage(xDrawPage->getByIndex(0), 
uno::UNO_QUERY);
+        uno::Reference<beans::XPropertySet> xPropertySet(xImage, 
uno::UNO_QUERY_THROW);
+
+        // Convert to a XGraphic
+        uno::Reference<graphic::XGraphic> xGraphic;
+        xPropertySet->getPropertyValue("Graphic") >>= xGraphic;
+        CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is());
+
+        // Access the Graphic
+        Graphic aGraphic(xGraphic);
+
+        // Check if it contian a VectorGraphicData struct
+        auto pVectorGraphic = aGraphic.getVectorGraphicData();
+        CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pVectorGraphic);
+
+        // Which should be of type SVG, which means we have a SVG file
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 
VectorGraphicDataType::Svg,
+                                     pVectorGraphic->getType());
+    }
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SdExportTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/qa/extras/globalfilter/data/SvgImageTest.odt 
b/sw/qa/extras/globalfilter/data/SvgImageTest.odt
new file mode 100644
index 000000000000..3b37fe7998ef
Binary files /dev/null and b/sw/qa/extras/globalfilter/data/SvgImageTest.odt 
differ
diff --git a/sw/qa/extras/globalfilter/globalfilter.cxx 
b/sw/qa/extras/globalfilter/globalfilter.cxx
index 43b6afdad443..2683bc227ded 100644
--- a/sw/qa/extras/globalfilter/globalfilter.cxx
+++ b/sw/qa/extras/globalfilter/globalfilter.cxx
@@ -41,7 +41,10 @@
 class Test : public SwModelTestBase
 {
 public:
-    Test() : SwModelTestBase("/sw/qa/extras/globalfilter/data/") {}
+    Test() : SwModelTestBase("/sw/qa/extras/globalfilter/data/")
+    {
+        skipValidation();
+    }
 
     void testEmbeddedGraphicRoundtrip();
     void testLinkedGraphicRT();
@@ -67,6 +70,7 @@ public:
     void testDropDownFormField();
     void testDateFormField();
     void testDateFormFieldCharacterFormatting();
+    void testSvgImageSupport();
 
     CPPUNIT_TEST_SUITE(Test);
     CPPUNIT_TEST(testEmbeddedGraphicRoundtrip);
@@ -90,6 +94,7 @@ public:
     CPPUNIT_TEST(testDropDownFormField);
     CPPUNIT_TEST(testDateFormField);
     CPPUNIT_TEST(testDateFormFieldCharacterFormatting);
+    CPPUNIT_TEST(testSvgImageSupport);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -1767,6 +1772,50 @@ void Test::testDateFormFieldCharacterFormatting()
     }
 }
 
+void Test::testSvgImageSupport()
+{
+    OUString aFilterNames[] = {
+        "writer8",
+        "Office Open XML Text",
+    };
+
+    for (OUString const & rFilterName : aFilterNames)
+    {
+        // Use case to import a document containing a SVG image, export in 
target format, import and check if the
+        // SVG image is present and as expected in the document
+
+        // Import ODT file
+        createSwDoc("SvgImageTest.odt");
+
+        // Export the document in target format and import again
+        saveAndReload(rFilterName);
+
+        // Prepare fail message (writing which import/export filter was used)
+        const OString sFailedMessage = "Failed on filter: " + 
rFilterName.toUtf8();
+
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 1, getShapes());
+
+        // Get the image
+        uno::Reference<drawing::XShape> xImage(getShape(1), uno::UNO_QUERY);
+        uno::Reference<beans::XPropertySet> xPropertySet(xImage, 
uno::UNO_QUERY_THROW);
+
+        // Convert to a XGraphic
+        uno::Reference<graphic::XGraphic> xGraphic;
+        xPropertySet->getPropertyValue("Graphic") >>= xGraphic;
+        CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), xGraphic.is());
+
+        // Access the Graphic
+        Graphic aGraphic(xGraphic);
+
+        // Check if it contian a VectorGraphicData struct
+        auto pVectorGraphic = aGraphic.getVectorGraphicData();
+        CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pVectorGraphic);
+
+        // Which should be of type SVG, which means we have a SVG file
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), 
VectorGraphicDataType::Svg, pVectorGraphic->getType());
+    }
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(Test);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
commit 1372b6e33d0ce3e831ca553c5148655e97615d84
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Sun Dec 3 13:21:35 2023 +0900
Commit:     Andras Timar <andras.ti...@collabora.com>
CommitDate: Sun Dec 10 12:37:25 2023 +0100

    tdf#126084 support writing SVG images into OOXML using the MS OOXML 
extension
    
    SVG files aren't supported in OOXML, but we can write it using the
    MS OOXML extension, which is supported in the latest MSO versions.
    
    For now this only implements the support in the exporter.
    
    Change-Id: I688180fb5772f3999c2ee3020bc234f90d57cc2f
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157237
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>
    (cherry picked from commit bfbbf06bcea4d58117c14fd3f3b8743a3714f97e)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160383
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Andras Timar <andras.ti...@collabora.com>

diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx
index 70827d256b8d..0b76af607fb3 100644
--- a/include/oox/export/drawingml.hxx
+++ b/include/oox/export/drawingml.hxx
@@ -259,16 +259,25 @@ private:
     DocumentType meDocumentType;
 
     OUString writeNewEntryToStorage(const Graphic& rGraphic, bool 
bRelPathToMedia);
+    OUString writeNewSvgEntryToStorage(const Graphic& rGraphic, bool 
bRelPathToMedia);
 
 public:
+    enum class TypeHint
+    {
+        Detect,
+        SVG
+    };
+
     GraphicExport(sax_fastparser::FSHelperPtr pFS, ::oox::core::XmlFilterBase* 
pFilterBase, DocumentType eDocumentType)
         : mpFS(pFS)
         , mpFilterBase(pFilterBase)
         , meDocumentType(eDocumentType)
     {}
 
-    OUString writeToStorage(Graphic const& rGraphic, bool bRelPathToMedia = 
false);
+    OUString writeToStorage(Graphic const& rGraphic, bool bRelPathToMedia = 
false, TypeHint eHint = TypeHint::Detect);
+
     void writeBlip(Graphic const& rGraphic, std::vector<model::BlipEffect> 
const& rEffects, bool bRelPathToMedia = false);
+    void writeSvgExtension(OUString const& rSvgRelId);
 };
 
 class OOX_DLLPUBLIC DrawingML
@@ -352,7 +361,7 @@ public:
 
     void SetBackgroundDark(bool bIsDark) { mbIsBackgroundDark = bIsDark; }
     /// If bRelPathToMedia is true add "../" to image folder path while adding 
the image relationship
-    OUString writeGraphicToStorage(const Graphic &rGraphic , bool 
bRelPathToMedia = false);
+    OUString writeGraphicToStorage(const Graphic &rGraphic , bool 
bRelPathToMedia = false, GraphicExport::TypeHint eHint = 
GraphicExport::TypeHint::Detect);
 
     void WriteColor( ::Color nColor, sal_Int32 nAlpha = MAX_PERCENT );
     void WriteColor( const OUString& sColorSchemeName, const 
css::uno::Sequence< css::beans::PropertyValue >& aTransformations, sal_Int32 
nAlpha = MAX_PERCENT );
@@ -514,6 +523,7 @@ public:
                                         const char* sRelationshipType,
                                         OUString* pRelationshipId );
 
+    std::shared_ptr<GraphicExport> createGraphicExport();
 };
 
 }
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index 0bb2272d6ecf..e876f545c4ff 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -1266,12 +1266,34 @@ OUString DrawingML::GetRelationCompPrefix() const
     return OUString(getRelationCompPrefix(meDocumentType));
 }
 
+void GraphicExport::writeSvgExtension(OUString const& rSvgRelId)
+{
+    if (rSvgRelId.isEmpty())
+        return;
+
+    mpFS->startElementNS(XML_a, XML_extLst);
+    mpFS->startElementNS(XML_a, XML_ext, XML_uri, 
"{96DAC541-7B7A-43D3-8B79-37D633B846F1}");
+    mpFS->singleElementNS(XML_asvg, XML_svgBlip,
+            FSNS(XML_xmlns, XML_asvg), 
mpFilterBase->getNamespaceURL(OOX_NS(asvg)),
+            FSNS(XML_r, XML_embed), rSvgRelId);
+    mpFS->endElementNS(XML_a, XML_ext);
+    mpFS->endElementNS( XML_a, XML_extLst);
+}
+
 void GraphicExport::writeBlip(Graphic const& rGraphic, 
std::vector<model::BlipEffect> const& rEffects, bool bRelPathToMedia)
 {
     OUString sRelId = writeToStorage(rGraphic, bRelPathToMedia);
 
     mpFS->startElementNS(XML_a, XML_blip, FSNS(XML_r, XML_embed), sRelId);
 
+    auto const& rVectorGraphicDataPtr = rGraphic.getVectorGraphicData();
+
+    if (rVectorGraphicDataPtr && rVectorGraphicDataPtr->getType() == 
VectorGraphicDataType::Svg)
+    {
+        OUString sSvgRelId = writeToStorage(rGraphic, bRelPathToMedia, 
TypeHint::SVG);
+        writeSvgExtension(sSvgRelId);
+    }
+
     for (auto const& rEffect : rEffects)
     {
         switch (rEffect.meType)
@@ -1497,19 +1519,72 @@ OUString GraphicExport::writeNewEntryToStorage(const 
Graphic& rGraphic, bool bRe
     return sPath;
 }
 
-OUString GraphicExport::writeToStorage(const Graphic& rGraphic , bool 
bRelPathToMedia)
+namespace
+{
+BitmapChecksum makeChecksumUniqueForSVG(BitmapChecksum const& rChecksum)
+{
+    // need to modify the checksum so we know it's for SVG - just invert it
+    return ~rChecksum;
+}
+
+} // end anonymous namespace
+
+OUString GraphicExport::writeNewSvgEntryToStorage(const Graphic& rGraphic, 
bool bRelPathToMedia)
+{
+    OUString sMediaType = "image/svg";
+    OUString aExtension = "svg";
+
+    GfxLink const& rLink = rGraphic.GetGfxLink();
+    if (rLink.GetType() != GfxLinkType::NativeSvg)
+        return OUString();
+
+    const void* aData = rLink.GetData();
+    std::size_t nDataSize = rLink.GetDataSize();
+
+    GraphicExportCache& rGraphicExportCache = GraphicExportCache::get();
+    auto sImageCountString = 
OUString::number(rGraphicExportCache.nextImageCount());
+
+    OUString sComponentDir(getComponentDir(meDocumentType));
+
+    OUString sImagePath = sComponentDir + "/media/image" + sImageCountString + 
"." + aExtension;
+
+    Reference<XOutputStream> xOutStream = 
mpFilterBase->openFragmentStream(sImagePath, sMediaType);
+    xOutStream->writeBytes(Sequence<sal_Int8>(static_cast<const 
sal_Int8*>(aData), nDataSize));
+    xOutStream->closeOutput();
+
+    OUString sRelationCompPrefix;
+    if (bRelPathToMedia)
+        sRelationCompPrefix = "../";
+    else
+        sRelationCompPrefix = getRelationCompPrefix(meDocumentType);
+
+    OUString sPath = sRelationCompPrefix + "media/image" + sImageCountString + 
"." + aExtension;
+
+    
rGraphicExportCache.addExportGraphics(makeChecksumUniqueForSVG(rGraphic.GetChecksum()),
 sPath);
+
+    return sPath;
+}
+
+OUString GraphicExport::writeToStorage(const Graphic& rGraphic, bool 
bRelPathToMedia, TypeHint eHint)
 {
     OUString sPath;
 
+    auto aChecksum = rGraphic.GetChecksum();
+    if (eHint == TypeHint::SVG)
+        aChecksum = makeChecksumUniqueForSVG(aChecksum);
+
     GraphicExportCache& rGraphicExportCache = GraphicExportCache::get();
-    sPath = rGraphicExportCache.findExportGraphics(rGraphic.GetChecksum());
+    sPath = rGraphicExportCache.findExportGraphics(aChecksum);
 
     if (sPath.isEmpty())
     {
-        sPath = writeNewEntryToStorage(rGraphic, bRelPathToMedia);
+        if (eHint == TypeHint::SVG)
+            sPath = writeNewSvgEntryToStorage(rGraphic, bRelPathToMedia);
+        else
+            sPath = writeNewEntryToStorage(rGraphic, bRelPathToMedia);
 
         if (sPath.isEmpty())
-            return OUString(); // couldn't store - just return empty string
+            return OUString(); // couldn't store
     }
 
     OUString sRelId = mpFilterBase->addRelation(mpFS->getOutputStream(), 
oox::getRelationship(Relationship::IMAGE), sPath);
@@ -1517,10 +1592,15 @@ OUString GraphicExport::writeToStorage(const Graphic& 
rGraphic , bool bRelPathTo
     return sRelId;
 }
 
-OUString DrawingML::writeGraphicToStorage( const Graphic& rGraphic , bool 
bRelPathToMedia )
+std::shared_ptr<GraphicExport> DrawingML::createGraphicExport()
+{
+    return std::make_shared<GraphicExport>(mpFS, mpFB, meDocumentType);
+}
+
+OUString DrawingML::writeGraphicToStorage(const Graphic& rGraphic , bool 
bRelPathToMedia, GraphicExport::TypeHint eHint)
 {
     GraphicExport aExporter(mpFS, mpFB, meDocumentType);
-    return aExporter.writeToStorage(rGraphic, bRelPathToMedia);
+    return aExporter.writeToStorage(rGraphic, bRelPathToMedia, eHint);
 }
 
 void DrawingML::WriteMediaNonVisualProperties(const 
css::uno::Reference<css::drawing::XShape>& xShape)
@@ -1684,10 +1764,21 @@ void 
DrawingML::WriteXGraphicBlip(uno::Reference<beans::XPropertySet> const & rX
         return;
 
     Graphic aGraphic(rxGraphic);
+
     sRelId = writeGraphicToStorage(aGraphic, bRelPathToMedia);
 
     mpFS->startElementNS(XML_a, XML_blip, FSNS(XML_r, XML_embed), sRelId);
 
+    auto pVectorGraphicDataPtr = aGraphic.getVectorGraphicData();
+
+    if (pVectorGraphicDataPtr && pVectorGraphicDataPtr->getType() == 
VectorGraphicDataType::Svg)
+    {
+        GraphicExport aExporter(mpFS, mpFB, meDocumentType);
+        OUString sSvgRelId =  aExporter.writeToStorage(aGraphic, 
bRelPathToMedia, GraphicExport::TypeHint::SVG);
+        if (!sSvgRelId.isEmpty())
+            aExporter.writeSvgExtension(sSvgRelId);
+    }
+
     WriteImageBrightnessContrastTransparence(rXPropSet);
 
     WriteArtisticEffect(rXPropSet);
diff --git a/oox/source/token/namespaces-strict.txt 
b/oox/source/token/namespaces-strict.txt
index 59631432eb2f..f537ddbd3a05 100644
--- a/oox/source/token/namespaces-strict.txt
+++ b/oox/source/token/namespaces-strict.txt
@@ -93,6 +93,7 @@ xr2                     
http://schemas.microsoft.com/office/spreadsheetml/2015/r
 # extlst namespaces
 
 adec                    
http://schemas.microsoft.com/office/drawing/2017/decorative
+asvg                    
http://schemas.microsoft.com/office/drawing/2016/SVG/main
 
 # xls14Lst for features introduced by excel 2010
 xls14Lst               
http://schemas.microsoft.com/office/spreadsheetml/2009/9/main
diff --git a/oox/source/token/namespaces.txt b/oox/source/token/namespaces.txt
index 0790c65d8817..94eb86870b6b 100644
--- a/oox/source/token/namespaces.txt
+++ b/oox/source/token/namespaces.txt
@@ -93,6 +93,7 @@ xr2                     
http://schemas.microsoft.com/office/spreadsheetml/2015/r
 # extlst namespaces
 
 adec                    
http://schemas.microsoft.com/office/drawing/2017/decorative
+asvg                    
http://schemas.microsoft.com/office/drawing/2016/SVG/main
 
 # xls14Lst for features introduced by excel 2010
 xls14Lst               
http://schemas.microsoft.com/office/spreadsheetml/2009/9/main
diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt
index eb5239d8a8ac..2f62737f1c70 100644
--- a/oox/source/token/tokens.txt
+++ b/oox/source/token/tokens.txt
@@ -682,6 +682,7 @@ aspectratio
 assign
 asst
 asteriskTotals
+asvg
 atEnd
 atLeast
 atMost
@@ -5091,6 +5092,7 @@ suppressTopSpacing
 suppressTopSpacingWP
 surface3DChart
 surfaceChart
+svgBlip
 swAng
 swCell
 swapBordersFacingPages
diff --git a/sw/qa/extras/ooxmlexport/data/SvgImageTest.odt 
b/sw/qa/extras/ooxmlexport/data/SvgImageTest.odt
new file mode 100644
index 000000000000..3b37fe7998ef
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/SvgImageTest.odt 
differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx
index 4f812c643f5c..58dcc17bc3c2 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx
@@ -745,6 +745,33 @@ DECLARE_OOXMLEXPORT_TEST(testTdf155736, 
"tdf155736_PageNumbers_footer.docx")
     CPPUNIT_ASSERT_EQUAL(OUString("Page * of *"), 
parseDump("/root/page[2]/footer/txt/text()"));
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testSvgExtensionsSupport)
+{
+    loadAndSave("SvgImageTest.odt");
+
+    xmlDocUniquePtr pXmlDocRels = parseExport("word/_rels/document.xml.rels");
+
+    // Check we have 2 relationships - one for PNG and one for SVG files
+    assertXPath(pXmlDocRels,
+                
"/rels:Relationships/rels:Relationship[@Target='media/image1.png']", "Id",
+                "rId2");
+
+    assertXPath(pXmlDocRels,
+                
"/rels:Relationships/rels:Relationship[@Target='media/image2.svg']", "Id",
+                "rId3");
+
+    // Check there is the extension present
+    xmlDocUniquePtr pXmlDocContent = parseExport("word/document.xml");
+
+    OString aPath(
+        
"/w:document/w:body/w:p/w:r/w:drawing/wp:anchor/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip");
+    assertXPath(pXmlDocContent, aPath, "embed", "rId2");
+
+    assertXPath(pXmlDocContent, aPath + "/a:extLst/a:ext", "uri",
+                "{96DAC541-7B7A-43D3-8B79-37D633B846F1}");
+    assertXPath(pXmlDocContent, aPath + "/a:extLst/a:ext/asvg:svgBlip", 
"embed", "rId3");
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index af1a940dad71..3ae94d3c6e69 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -52,6 +52,7 @@
 #include <oox/token/relationship.hxx>
 #include <oox/export/vmlexport.hxx>
 #include <oox/ole/olehelper.hxx>
+#include <oox/export/drawingml.hxx>
 
 #include <editeng/autokernitem.hxx>
 #include <editeng/unoprnms.hxx>
@@ -5074,6 +5075,7 @@ void DocxAttributeOutput::FlyFrameGraphic( const 
SwGrfNode* pGrfNode, const Size
     const SwFrameFormat* pFrameFormat = pGrfNode ? pGrfNode->GetFlyFormat() : 
pOLEFrameFormat;
     // create the relation ID
     OString aRelId;
+    OUString sSvgRelId;
     sal_Int32 nImageType;
     if ( pGrfNode && pGrfNode->IsLinkedFile() )
     {
@@ -5109,9 +5111,14 @@ void DocxAttributeOutput::FlyFrameGraphic( const 
SwGrfNode* pGrfNode, const Size
             aGraphic = *pOLENode->GetGraphic();
 
         m_rDrawingML.SetFS(m_pSerializer); // to be sure that we write to the 
right stream
-        OUString aImageId = m_rDrawingML.writeGraphicToStorage(aGraphic, 
false);
+        auto pGraphicExport = m_rDrawingML.createGraphicExport();
+        OUString aImageId = pGraphicExport->writeToStorage(aGraphic, false);
         aRelId = OUStringToOString(aImageId, RTL_TEXTENCODING_UTF8);
 
+        if (aGraphic.getVectorGraphicData() && 
aGraphic.getVectorGraphicData()->getType() == VectorGraphicDataType::Svg)
+        {
+            sSvgRelId = pGraphicExport->writeToStorage(aGraphic, false, 
drawingml::GraphicExport::TypeHint::SVG);
+        }
         nImageType = XML_embed;
     }
 
@@ -5261,6 +5268,13 @@ void DocxAttributeOutput::FlyFrameGraphic( const 
SwGrfNode* pGrfNode, const Size
         else if (nMode == GraphicDrawMode::Watermark) //watermark has a 
brightness/luminance of 0,5 and contrast of -0.7 in LibreOffice
             m_pSerializer->singleElementNS( XML_a, XML_lum, XML_bright, 
OString::number(70000), XML_contrast, OString::number(-70000) );
     }
+
+    if (!sSvgRelId.isEmpty())
+    {
+        auto pGraphicExport = m_rDrawingML.createGraphicExport();
+        pGraphicExport->writeSvgExtension(sSvgRelId);
+    }
+
     m_pSerializer->endElementNS( XML_a, XML_blip );
 
     if (xShapePropSet)
diff --git a/test/source/xmltesttools.cxx b/test/source/xmltesttools.cxx
index db743e5688aa..1c462c94a089 100644
--- a/test/source/xmltesttools.cxx
+++ b/test/source/xmltesttools.cxx
@@ -447,6 +447,8 @@ void 
XmlTestTools::registerOOXMLNamespaces(xmlXPathContextPtr& pXmlXpathCtx)
                        
BAD_CAST("http://schemas.microsoft.com/office/drawing/2012/chart";));
     xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("xr2"),
                        
BAD_CAST("http://schemas.microsoft.com/office/spreadsheetml/2015/revision2";));
+    xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("asvg"),
+                       
BAD_CAST("http://schemas.microsoft.com/office/drawing/2016/SVG/main";));
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to