include/xmloff/xmlexp.hxx                    |    7 +++----
 sc/inc/xmlwrap.hxx                           |    2 +-
 sc/source/filter/xml/xmlwrap.cxx             |    4 ++--
 sd/source/filter/xml/sdxmlwrp.cxx            |    6 +++---
 sw/qa/extras/uiwriter/uiwriter6.cxx          |   12 ++++++------
 sw/source/filter/xml/wrtxml.cxx              |    4 ++--
 sw/source/filter/xml/wrtxml.hxx              |    2 +-
 xmloff/source/style/XMLFontAutoStylePool.cxx |   16 ++++++----------
 8 files changed, 24 insertions(+), 29 deletions(-)

New commits:
commit 8ebe1e51ea9be20dd3e2279359ca0bebc9beb05c
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Sat May 24 01:32:06 2025 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri May 23 23:58:36 2025 +0200

    Related: tdf#166627 Write font-face-src for each mention of embedded font
    
    Before commit e61a179b4ff8ce2072c3c0780628eb38c7a43529 (tdf#166627: embed
    fonts everywhere we emit font data, 2025-05-23),  embedding of fonts only
    happened during export of content.xml, to avoid complexity of shared data
    between different instances of SvXMLExport, created separately per stream.
    
    The said commit introduced a way to pass the data between these instances,
    and embedding now is done by any SvXMLExport instance  that needs to emit
    font-face-decls. Currently, only the first declaration of a used embedded
    font gets its font-face-src.
    
    But this is wrong, when the same embedded font in another stream, where it
    is also used, does not reference its files.  This patch allows all streams
    to emit font-face-src for all fonts used in it. File duplication in ZIP is
    avoided by passing the embedded file information between SvXMLExport, with
    font file hash and its path in ZIP, instead of font names.
    
    Change-Id: I7a62e50c086d8741dbc8aadf61d0f008bad916ff
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185720
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/include/xmloff/xmlexp.hxx b/include/xmloff/xmlexp.hxx
index ce10b5b2b60f..7f9e9dbe5d8c 100644
--- a/include/xmloff/xmlexp.hxx
+++ b/include/xmloff/xmlexp.hxx
@@ -164,9 +164,8 @@ class XMLOFF_DLLPUBLIC SvXMLExport : public 
cppu::WeakImplHelper<
 
     const OUString               msWS;           // " "
 
+    // A map of font hashes and names that were already embedded, including 
previous passes
     std::unordered_map<OString, OUString> m_aEmbeddedFontFiles;
-    // A list of font names that were already embedded, including previous 
passes
-    std::unordered_set<OUString> m_aEmbeddedFontNames;
 
     // Shapes in Writer cannot be named via context menu (#i51726#)
     SvtModuleOptions::EFactory meModelType;
@@ -317,8 +316,8 @@ public:
     // doesn't handle some style-specific content like headers/footers. These 
methods are for
     // passing the "already embedded" information from one instance to another.
 
-    std::vector<OUString> getEmbeddedFontNames() const;
-    void setEmbeddedFontNames(const std::vector<OUString>&);
+    std::unordered_map<OString, OUString> getEmbeddedFontFiles() const;
+    void setEmbeddedFontFiles(const std::unordered_map<OString, OUString>&);
 
     // XExporter
     virtual void SAL_CALL setSourceDocument( const css::uno::Reference< 
css::lang::XComponent >& xDoc ) override;
diff --git a/sc/inc/xmlwrap.hxx b/sc/inc/xmlwrap.hxx
index 618cc995c71c..f7b49cfa37b5 100644
--- a/sc/inc/xmlwrap.hxx
+++ b/sc/inc/xmlwrap.hxx
@@ -63,7 +63,7 @@ class ScXMLImportWrapper
     SfxMedium*      pMedium;
     css::uno::Reference< css::embed::XStorage > xStorage;
 
-    std::vector<OUString> maEmbeddedFontNames;
+    std::unordered_map<OString, OUString> maEmbeddedFontFiles;
 
     css::uno::Reference< css::task::XStatusIndicator> GetStatusIndicator() 
const;
 
diff --git a/sc/source/filter/xml/xmlwrap.cxx b/sc/source/filter/xml/xmlwrap.cxx
index cfeb7a991bad..f6e9d7ef466b 100644
--- a/sc/source/filter/xml/xmlwrap.cxx
+++ b/sc/source/filter/xml/xmlwrap.cxx
@@ -650,7 +650,7 @@ bool ScXMLImportWrapper::ExportToComponent(const 
uno::Reference<uno::XComponentC
         ScXMLExport* pExport = 
static_cast<ScXMLExport*>(dynamic_cast<SvXMLExport*>(xFilter.get()));
         assert(pExport && "can only succeed");
         pExport->SetSharedData(std::move(pSharedData));
-        pExport->setEmbeddedFontNames(maEmbeddedFontNames);
+        pExport->setEmbeddedFontFiles(maEmbeddedFontFiles);
 
         // if there are sheets to copy, get the source stream
         if ( sName == "content.xml" && lcl_HasValidStream(rDoc) && ( 
pExport->getExportFlags() & SvXMLExportFlags::OASIS ) )
@@ -698,7 +698,7 @@ bool ScXMLImportWrapper::ExportToComponent(const 
uno::Reference<uno::XComponentC
         else
             bRet = xFilter->filter( aDescriptor );
 
-        maEmbeddedFontNames = pExport->getEmbeddedFontNames();
+        maEmbeddedFontFiles = pExport->getEmbeddedFontFiles();
         pSharedData = pExport->ReleaseSharedData();
     }
 
diff --git a/sd/source/filter/xml/sdxmlwrp.cxx 
b/sd/source/filter/xml/sdxmlwrp.cxx
index d8cd04671945..caf15884c10f 100644
--- a/sd/source/filter/xml/sdxmlwrp.cxx
+++ b/sd/source/filter/xml/sdxmlwrp.cxx
@@ -896,7 +896,7 @@ bool SdXMLFilter::Export()
             aServices[i].mpStream  = nullptr;
 
             XML_SERVICEMAP* pServices = aServices;
-            std::vector<OUString> aEmbeddedFontNames;
+            std::unordered_map<OString, OUString> maEmbeddedFontFiles;
 
             // doc export
             do
@@ -954,13 +954,13 @@ bool SdXMLFilter::Export()
                         auto pFilter = 
dynamic_cast<SvXMLExport*>(xFilter.get());
                         if (pFilter)
                         {
-                            pFilter->setEmbeddedFontNames(aEmbeddedFontNames);
+                            pFilter->setEmbeddedFontFiles(maEmbeddedFontFiles);
                         }
                         // outputstream will be closed by SAX parser
                         bDocRet = xFilter->filter( aDescriptor );
                         if (pFilter)
                         {
-                            aEmbeddedFontNames = 
pFilter->getEmbeddedFontNames();
+                            maEmbeddedFontFiles = 
pFilter->getEmbeddedFontFiles();
                         }
                     }
                 }
diff --git a/sw/qa/extras/uiwriter/uiwriter6.cxx 
b/sw/qa/extras/uiwriter/uiwriter6.cxx
index 438e588eb0b9..2c0069a7e65a 100644
--- a/sw/qa/extras/uiwriter/uiwriter6.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter6.cxx
@@ -2361,7 +2361,7 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testFontEmbedding)
         assertXPath(pXmlDoc, prefix + "/svg:font-face-src['CASE 2']", 1);
     }
 
-    // Check content - No font-face-src nodes should be present
+    // Check content - font-face-src should be present for all fonts
     pXmlDoc = parseExport(u"content.xml"_ustr);
     CPPUNIT_ASSERT(pXmlDoc);
 
@@ -2371,7 +2371,7 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testFontEmbedding)
     {
         OString prefix = aContentBaseXpath + "/style:font-face[@style:name='" 
+ fontName + "']";
         assertXPath(pXmlDoc, prefix + "['CASE 2']");
-        assertXPath(pXmlDoc, prefix + "/svg:font-face-src['CASE 2']", 0);
+        assertXPath(pXmlDoc, prefix + "/svg:font-face-src['CASE 2']", 1);
     }
 
     // CASE 3 - font embedding enabled, embed only used fonts enabled
@@ -2423,19 +2423,19 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testFontEmbedding)
         assertXPath(pXmlDoc, prefix + "/svg:font-face-src['CASE 3']", 1);
     }
 
-    // Check content - font-face-src should be present only for Carlito fonts
+    // Check content - font-face-src should be present only for Carlito and 
Liberation Serif fonts
+    // Note that the used sets of fonts are different for styles.xml and 
content.xml
     pXmlDoc = parseExport(u"content.xml"_ustr);
     CPPUNIT_ASSERT(pXmlDoc);
 
     assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face['CASE 3']", 6);
-    for (auto fontName : { "Caladea", "Liberation Sans", "Liberation Sans1", 
"Liberation Serif",
-                           "Liberation Serif1" })
+    for (auto fontName : { "Caladea", "Liberation Sans", "Liberation Sans1" })
     {
         OString prefix = aContentBaseXpath + "/style:font-face[@style:name='" 
+ fontName + "']";
         assertXPath(pXmlDoc, prefix + "['CASE 3']");
         assertXPath(pXmlDoc, prefix + "/svg:font-face-src['CASE 3']", 0);
     }
-    for (auto fontName : { "Carlito" })
+    for (auto fontName : { "Carlito", "Liberation Serif", "Liberation Serif1" 
})
     {
         OString prefix = aContentBaseXpath + "/style:font-face[@style:name='" 
+ fontName + "']";
         assertXPath(pXmlDoc, prefix + "['CASE 3']");
diff --git a/sw/source/filter/xml/wrtxml.cxx b/sw/source/filter/xml/wrtxml.cxx
index 66faa6342428..2f5e049ea581 100644
--- a/sw/source/filter/xml/wrtxml.cxx
+++ b/sw/source/filter/xml/wrtxml.cxx
@@ -579,12 +579,12 @@ bool SwXMLWriter::WriteThroughComponent(
     if (pFilter)
     {
         pFilter->SetLibreOfficeKitNotifier(SfxViewShell::Current());
-        pFilter->setEmbeddedFontNames(maEmbeddedFontNames);
+        pFilter->setEmbeddedFontFiles(maEmbeddedFontFiles);
     }
     bool result = xFilter->filter( rMediaDesc );
     if (pFilter)
     {
-        maEmbeddedFontNames = pFilter->getEmbeddedFontNames();
+        maEmbeddedFontFiles = pFilter->getEmbeddedFontFiles();
     }
     return result;
 }
diff --git a/sw/source/filter/xml/wrtxml.hxx b/sw/source/filter/xml/wrtxml.hxx
index 850de4780db9..57a8c31980fe 100644
--- a/sw/source/filter/xml/wrtxml.hxx
+++ b/sw/source/filter/xml/wrtxml.hxx
@@ -53,7 +53,7 @@ public:
     virtual ErrCodeMsg Write( SwPaM&, SfxMedium&, const OUString* ) override;
 
 private:
-    std::vector<OUString> maEmbeddedFontNames;
+    std::unordered_map<OString, OUString> maEmbeddedFontFiles;
 
     // helper methods to write XML streams
 
diff --git a/xmloff/source/style/XMLFontAutoStylePool.cxx 
b/xmloff/source/style/XMLFontAutoStylePool.cxx
index e2050423b047..3034aef14ee9 100644
--- a/xmloff/source/style/XMLFontAutoStylePool.cxx
+++ b/xmloff/source/style/XMLFontAutoStylePool.cxx
@@ -425,10 +425,8 @@ void SvXMLExport::exportFonts(const 
std::vector<XMLFontAutoStylePoolEntry_Impl*>
 
         SvXMLElementExport aElement(*this, XML_NAMESPACE_STYLE, XML_FONT_FACE, 
true, true);
 
-        // When embedding is requested, and embedded only is not set or font 
is used, and the font
-        // was not embedded already in a different pass
-        if (bEmbedFonts && (!bEmbedUsedOnly || 
aUsedFontNames.contains(pEntry->GetFamilyName()))
-            && !m_aEmbeddedFontNames.contains(pEntry->GetName()))
+        // When embedding is requested, and embedded only is not set or font 
is used
+        if (bEmbedFonts && (!bEmbedUsedOnly || 
aUsedFontNames.contains(pEntry->GetFamilyName())))
         {
             const bool bExportFlat(getExportFlags() & 
SvXMLExportFlags::EMBEDDED);
 
@@ -467,7 +465,6 @@ void SvXMLExport::exportFonts(const 
std::vector<XMLFontAutoStylePoolEntry_Impl*>
             }
             if (!aEmbeddedFonts.empty())
             {
-                m_aEmbeddedFontNames.insert(pEntry->GetName());
                 SvXMLElementExport fontFaceSrc(*this, XML_NAMESPACE_SVG, 
XML_FONT_FACE_SRC, true, true);
                 for (EmbeddedFontInfo const & rEmbeddedFont : aEmbeddedFonts)
                 {
@@ -516,15 +513,14 @@ void SvXMLExport::exportFonts(const 
std::vector<XMLFontAutoStylePoolEntry_Impl*>
     }
 }
 
-std::vector<OUString> SvXMLExport::getEmbeddedFontNames() const
+std::unordered_map<OString, OUString> SvXMLExport::getEmbeddedFontFiles() const
 {
-    return std::vector(m_aEmbeddedFontNames.begin(), 
m_aEmbeddedFontNames.end());
+    return m_aEmbeddedFontFiles;
 }
 
-void SvXMLExport::setEmbeddedFontNames(const std::vector<OUString>& newNames)
+void SvXMLExport::setEmbeddedFontFiles(const std::unordered_map<OString, 
OUString>& value)
 {
-    m_aEmbeddedFontNames.clear();
-    m_aEmbeddedFontNames.insert(newNames.begin(), newNames.end());
+    m_aEmbeddedFontFiles = value;
 }
 
 void XMLFontAutoStylePool::exportXML()

Reply via email to