include/xmloff/XMLFontAutoStylePool.hxx | 24 - include/xmloff/xmlexp.hxx | 25 + sc/inc/xmlwrap.hxx | 2 sc/source/filter/xml/xmlexprt.hxx | 6 sc/source/filter/xml/xmlfonte.cxx | 29 -- sc/source/filter/xml/xmlwrap.cxx | 2 sd/source/filter/xml/sdxmlwrp.cxx | 12 sw/qa/extras/odfexport/data/font_used_in_header_only.fodt | 45 +++ sw/qa/extras/odfexport/odfexport2.cxx | 42 ++ sw/qa/extras/uiwriter/uiwriter6.cxx | 157 +++++----- sw/source/filter/xml/wrtxml.cxx | 8 sw/source/filter/xml/wrtxml.hxx | 5 sw/source/filter/xml/xmlexp.hxx | 5 sw/source/filter/xml/xmlfonte.cxx | 46 +-- xmloff/source/draw/sdxmlexp.cxx | 61 +--- xmloff/source/draw/sdxmlexp_impl.hxx | 11 xmloff/source/style/XMLFontAutoStylePool.cxx | 202 ++++++-------- 17 files changed, 392 insertions(+), 290 deletions(-)
New commits: commit 7a3d121a6bdeb8d3c3ff68cf08394d9889a6bca3 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Sat May 24 01:32:06 2025 +0500 Commit: Michael Stahl <michael.st...@collabora.com> CommitDate: Thu Aug 7 13:50:15 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> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189033 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Michael Stahl <michael.st...@collabora.com> diff --git a/include/xmloff/xmlexp.hxx b/include/xmloff/xmlexp.hxx index 7e4b74ef9a47..9ac58acbe00c 100644 --- a/include/xmloff/xmlexp.hxx +++ b/include/xmloff/xmlexp.hxx @@ -165,9 +165,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; @@ -318,8 +317,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 29b867251490..9a192bc01e81 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 1116d015ac8c..2c3ac3d823f1 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 df064b740cb7..c61469e6a637 100644 --- a/sw/qa/extras/uiwriter/uiwriter6.cxx +++ b/sw/qa/extras/uiwriter/uiwriter6.cxx @@ -2329,7 +2329,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); @@ -2339,7 +2339,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 @@ -2391,19 +2391,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 fa5e2a6f327b..cf45481cf933 100644 --- a/sw/source/filter/xml/wrtxml.hxx +++ b/sw/source/filter/xml/wrtxml.hxx @@ -57,7 +57,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() commit eba7d8df443289ea38552560301dedf3d7a14b01 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Fri May 23 12:14:27 2025 +0500 Commit: Michael Stahl <michael.st...@collabora.com> CommitDate: Thu Aug 7 13:50:05 2025 +0200 tdf#166627: embed fonts everywhere we emit font data Commit 69ed893087f89d176a5ec4b263ce8d75774be72b (tdf#160253: fix list identifier export decision code) made a large change to the autostyle collection procedure, which became more precise. It turns out, that before that change, exporting content.xml gathered autostyles from page definitions, too, meaning that the fonts used there were marked as used in that pass. After the change, that pass doesn't look into the page styles and their content, and the fonts that are only used in headers/footers aren't seen as used in that pass. The font embedding procedure was previously implemented to only do the embedding during content.xml export, to avoid duplicating font files from each pass. Since each stream was exported by a separate instance of SvXMLExport, it was considered difficult to maintain the already embedded fonts list across all passes. It assumed that the export of content.xml sees all used fonts. But after the described change, this assumption doesn't hold anymore. We need to make sure to embed all fonts found in all passes. This change introduces such state, implemented as set of font names maintained in the object that exports all the streams, creating an exporter for each. Using a new set of function to set and get the "already embedded" font list in SvXMLExport, the outer object passes that list to each created SvXMLExport instance, and after the call to `filter`, retrieves the updated list, to pass it to the next one. The change required to move some members from XMLFontAutoStylePool to SvXMLExport, to avoid additional complexity of passing the list from SvXMLExport to XMLFontAutoStylePool. The implementations of the moved methods are kept in XMLFontAutoStylePool.cxx, because the internal structs used in the methods are defined there. After the change, some of the embedded font file references, that previously appeared in content.xml, will now be in styles.xml. Change-Id: Iaa26f1d1d623dee5a5c43600ea5fd2af1d04b46f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185704 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189032 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Michael Stahl <michael.st...@collabora.com> diff --git a/include/xmloff/XMLFontAutoStylePool.hxx b/include/xmloff/XMLFontAutoStylePool.hxx index 569f1443ab14..427ad6dac79f 100644 --- a/include/xmloff/XMLFontAutoStylePool.hxx +++ b/include/xmloff/XMLFontAutoStylePool.hxx @@ -40,23 +40,12 @@ private: std::unique_ptr<XMLFontAutoStylePool_Impl> m_pFontAutoStylePool; std::set<OUString> m_aNames; - bool m_bTryToEmbedFonts; - std::unordered_map<OString, OUString> m_aEmbeddedFontFiles; - - OUString embedFontFile(OUString const & rFileUrl, OUString const & rFamilyName); - - std::unordered_set<OUString> getUsedFontList(); protected: - bool m_bEmbedUsedOnly; - bool m_bEmbedLatinScript; - bool m_bEmbedAsianScript; - bool m_bEmbedComplexScript; - SvXMLExport& GetExport() { return m_rExport; } public: - XMLFontAutoStylePool( SvXMLExport& rExport, bool tryToEmbedFonts = false ); + XMLFontAutoStylePool(SvXMLExport& rExport); virtual ~XMLFontAutoStylePool() override; OUString Add( @@ -74,17 +63,6 @@ public: rtl_TextEncoding eEnc )const; void exportXML(); - - void setEmbedOnlyUsedFonts(bool bEmbedUsedOnly) - { - m_bEmbedUsedOnly = bEmbedUsedOnly; - } - void setEmbedFontScripts(bool bEmbedLatinScript, bool bEmbedAsianScript, bool bEmbedComplexScript) - { - m_bEmbedLatinScript = bEmbedLatinScript; - m_bEmbedAsianScript = bEmbedAsianScript; - m_bEmbedComplexScript = bEmbedComplexScript; - } }; #endif // INCLUDED_XMLOFF_XMLFONTAUTOSTYLEPOOL_HXX diff --git a/include/xmloff/xmlexp.hxx b/include/xmloff/xmlexp.hxx index 4ff51e19bc50..7e4b74ef9a47 100644 --- a/include/xmloff/xmlexp.hxx +++ b/include/xmloff/xmlexp.hxx @@ -51,6 +51,8 @@ #include <vector> #include <memory> +#include <unordered_map> +#include <unordered_set> #include <o3tl/typed_flags_set.hxx> namespace com::sun::star::beans { class XPropertySet; } @@ -72,6 +74,7 @@ class SvtSecurityMapPersonalInfo; class SvXMLExport_Impl; class ProgressBarHelper; class XMLEventExport; +class XMLFontAutoStylePoolEntry_Impl; class XMLImageMapExport; class XMLErrors; class LanguageTag; @@ -162,6 +165,10 @@ class XMLOFF_DLLPUBLIC SvXMLExport : public cppu::WeakImplHelper< const OUString msWS; // " " + 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; SAL_DLLPRIVATE void DetermineModelType_(); @@ -177,6 +184,9 @@ class XMLOFF_DLLPUBLIC SvXMLExport : public cppu::WeakImplHelper< virtual void SetBodyAttributes(); void GetViewSettingsAndViews(css::uno::Sequence<css::beans::PropertyValue>& rProps); + OUString embedFontFile(OUString const& rFileUrl, OUString const& rFamilyName); + std::unordered_set<OUString> getUsedFontList(); + protected: void setExportFlags( SvXMLExportFlags nExportFlags ) { mnExportFlags = nExportFlags; } @@ -229,6 +239,12 @@ protected: virtual void GetViewSettings(css::uno::Sequence<css::beans::PropertyValue>& aProps); virtual void GetConfigurationSettings(css::uno::Sequence<css::beans::PropertyValue>& aProps); + virtual bool getEmbedFonts() { return false; } + virtual bool getEmbedOnlyUsedFonts() { return false; } + virtual bool getEmbedLatinScript() { return true; } + virtual bool getEmbedAsianScript() { return true; } + virtual bool getEmbedComplexScript() { return true; } + struct SettingsGroup { ::xmloff::token::XMLTokenEnum eGroupName; @@ -294,6 +310,16 @@ public: virtual ~SvXMLExport() override; virtual void collectAutoStyles(); + void exportFonts(const std::vector<XMLFontAutoStylePoolEntry_Impl*>& rFonts); + + // We write font info to both content.xml and styles.xml, but they are written by different + // SvXMLExport instances, and would therefore embed each font file twice, if done naively. On + // the other hand, we can't limit the embedding only to content.xml phase, because there it + // 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>&); // 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 bfae5363cfbd..29b867251490 100644 --- a/sc/inc/xmlwrap.hxx +++ b/sc/inc/xmlwrap.hxx @@ -63,6 +63,8 @@ class ScXMLImportWrapper SfxMedium* pMedium; css::uno::Reference< css::embed::XStorage > xStorage; + std::vector<OUString> maEmbeddedFontNames; + css::uno::Reference< css::task::XStatusIndicator> GetStatusIndicator() const; ErrCodeMsg ImportFromComponent(const css::uno::Reference<css::uno::XComponentContext>& xContext, diff --git a/sc/source/filter/xml/xmlexprt.hxx b/sc/source/filter/xml/xmlexprt.hxx index d7ad2c726187..0ff2e453f400 100644 --- a/sc/source/filter/xml/xmlexprt.hxx +++ b/sc/source/filter/xml/xmlexprt.hxx @@ -227,6 +227,12 @@ protected: virtual XMLPageExport* CreatePageExport() override; virtual XMLShapeExport* CreateShapeExport() override; virtual XMLFontAutoStylePool* CreateFontAutoStylePool() override; + virtual bool getEmbedFonts() override; + virtual bool getEmbedOnlyUsedFonts() override; + virtual bool getEmbedLatinScript() override; + virtual bool getEmbedAsianScript() override; + virtual bool getEmbedComplexScript() override; + public: ScXMLExport( const css::uno::Reference< css::uno::XComponentContext >& rContext, diff --git a/sc/source/filter/xml/xmlfonte.cxx b/sc/source/filter/xml/xmlfonte.cxx index 55d0eee18f4e..3b71077614fa 100644 --- a/sc/source/filter/xml/xmlfonte.cxx +++ b/sc/source/filter/xml/xmlfonte.cxx @@ -41,7 +41,7 @@ private: void AddFontItems(const sal_uInt16* pWhichIds, sal_uInt8 nIdCount, const SfxItemPool* pItemPool, const bool bExportDefaults); public: - ScXMLFontAutoStylePool_Impl(ScDocument* pDoc, ScXMLExport& rExport, bool bEmbedFonts); + ScXMLFontAutoStylePool_Impl(ScDocument* pDoc, ScXMLExport& rExport); }; } @@ -71,8 +71,8 @@ void ScXMLFontAutoStylePool_Impl::AddFontItems(const sal_uInt16* pWhichIds, sal_ } } -ScXMLFontAutoStylePool_Impl::ScXMLFontAutoStylePool_Impl(ScDocument* pDoc, ScXMLExport& rExportP, bool bEmbedFonts) - : XMLFontAutoStylePool(rExportP, bEmbedFonts) +ScXMLFontAutoStylePool_Impl::ScXMLFontAutoStylePool_Impl(ScDocument* pDoc, ScXMLExport& rExportP) + : XMLFontAutoStylePool(rExportP) { if (!pDoc) return; @@ -92,11 +92,6 @@ ScXMLFontAutoStylePool_Impl::ScXMLFontAutoStylePool_Impl(ScDocument* pDoc, ScXML std::unique_ptr<SfxStyleSheetIterator> pItr = pDoc->GetStyleSheetPool()->CreateIterator(SfxStyleFamily::Page); - m_bEmbedUsedOnly = pDoc->IsEmbedUsedFontsOnly(); - m_bEmbedLatinScript = pDoc->IsEmbedFontScriptLatin(); - m_bEmbedAsianScript = pDoc->IsEmbedFontScriptAsian(); - m_bEmbedComplexScript = pDoc->IsEmbedFontScriptComplex(); - if(!pItr) return; @@ -148,17 +143,13 @@ ScXMLFontAutoStylePool_Impl::ScXMLFontAutoStylePool_Impl(ScDocument* pDoc, ScXML XMLFontAutoStylePool* ScXMLExport::CreateFontAutoStylePool() { - bool blockFontEmbedding = false; - // We write font info to both content.xml and styles.xml, but they are both - // written by different ScXMLExport instance, and would therefore write each - // font file twice without complicated checking for duplicates, so handle - // the embedding only in one of them. - if(!( getExportFlags() & SvXMLExportFlags::CONTENT )) - blockFontEmbedding = true; - ScDocument* pDoc = GetDocument(); - if (pDoc && !pDoc->IsEmbedFonts()) - blockFontEmbedding = true; - return new ScXMLFontAutoStylePool_Impl(pDoc, *this, !blockFontEmbedding); + return new ScXMLFontAutoStylePool_Impl(GetDocument(), *this); } +bool ScXMLExport::getEmbedFonts() { return GetDocument()->IsEmbedFonts(); } +bool ScXMLExport::getEmbedOnlyUsedFonts() { return GetDocument()->IsEmbedUsedFontsOnly(); } +bool ScXMLExport::getEmbedLatinScript() { return GetDocument()->IsEmbedFontScriptLatin(); } +bool ScXMLExport::getEmbedAsianScript() { return GetDocument()->IsEmbedFontScriptAsian(); } +bool ScXMLExport::getEmbedComplexScript() { return GetDocument()->IsEmbedFontScriptComplex(); } + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/xml/xmlwrap.cxx b/sc/source/filter/xml/xmlwrap.cxx index bf4e055440db..1116d015ac8c 100644 --- a/sc/source/filter/xml/xmlwrap.cxx +++ b/sc/source/filter/xml/xmlwrap.cxx @@ -650,6 +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); // if there are sheets to copy, get the source stream if ( sName == "content.xml" && lcl_HasValidStream(rDoc) && ( pExport->getExportFlags() & SvXMLExportFlags::OASIS ) ) @@ -697,6 +698,7 @@ bool ScXMLImportWrapper::ExportToComponent(const uno::Reference<uno::XComponentC else bRet = xFilter->filter( aDescriptor ); + maEmbeddedFontNames = pExport->getEmbeddedFontNames(); pSharedData = pExport->ReleaseSharedData(); } diff --git a/sd/source/filter/xml/sdxmlwrp.cxx b/sd/source/filter/xml/sdxmlwrp.cxx index 8bf962a7ede0..d8cd04671945 100644 --- a/sd/source/filter/xml/sdxmlwrp.cxx +++ b/sd/source/filter/xml/sdxmlwrp.cxx @@ -38,6 +38,7 @@ #include <svx/dialmgr.hxx> #include <svx/strings.hrc> #include <svx/xmlgrhlp.hxx> +#include <xmloff/xmlexp.hxx> #include <DrawDocShell.hxx> @@ -895,6 +896,7 @@ bool SdXMLFilter::Export() aServices[i].mpStream = nullptr; XML_SERVICEMAP* pServices = aServices; + std::vector<OUString> aEmbeddedFontNames; // doc export do @@ -948,8 +950,18 @@ bool SdXMLFilter::Export() if( xExporter.is() ) { xExporter->setSourceDocument( mxModel ); + + auto pFilter = dynamic_cast<SvXMLExport*>(xFilter.get()); + if (pFilter) + { + pFilter->setEmbeddedFontNames(aEmbeddedFontNames); + } // outputstream will be closed by SAX parser bDocRet = xFilter->filter( aDescriptor ); + if (pFilter) + { + aEmbeddedFontNames = pFilter->getEmbeddedFontNames(); + } } } diff --git a/sw/qa/extras/odfexport/data/font_used_in_header_only.fodt b/sw/qa/extras/odfexport/data/font_used_in_header_only.fodt new file mode 100644 index 000000000000..17f7feed9e93 --- /dev/null +++ b/sw/qa/extras/odfexport/data/font_used_in_header_only.fodt @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:settings> + <config:config-item-set config:name="ooo:configuration-settings"> + <config:config-item config:name="EmbedFonts" config:type="boolean">true</config:config-item> + <config:config-item config:name="EmbedOnlyUsedFonts" config:type="boolean">true</config:config-item> + <config:config-item config:name="EmbedLatinScriptFonts" config:type="boolean">true</config:config-item> + <config:config-item config:name="EmbedAsianScriptFonts" config:type="boolean">false</config:config-item> + <config:config-item config:name="EmbedComplexScriptFonts" config:type="boolean">false</config:config-item> + </config:config-item-set> + </office:settings> + <office:font-face-decls> + <style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'" style:font-family-generic="swiss" style:font-pitch="variable"/> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <style:default-style style:family="paragraph"> + <style:text-properties style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="US"/> + </style:default-style> + <style:style style:name="Standard" style:family="paragraph" style:class="text"/> + </office:styles> + <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard"> + <style:text-properties style:font-name="Liberation Sans"/> + </style:style> + <style:page-layout style:name="pm1"> + <style:header-style> + <style:header-footer-properties fo:min-height="0" fo:margin-left="0" fo:margin-right="0" fo:margin-bottom="5mm"/> + </style:header-style> + </style:page-layout> + </office:automatic-styles> + <office:master-styles> + <style:master-page style:name="Standard" style:page-layout-name="pm1"> + <style:header> + <text:p text:style-name="P1">Header: Liberation Sans</text:p> + </style:header> + </style:master-page> + </office:master-styles> + <office:body> + <office:text> + <text:p>Body: Liberation Serif</text:p> + </office:text> + </office:body> +</office:document> \ No newline at end of file diff --git a/sw/qa/extras/odfexport/odfexport2.cxx b/sw/qa/extras/odfexport/odfexport2.cxx index b2c844e91f81..85991c7570f5 100644 --- a/sw/qa/extras/odfexport/odfexport2.cxx +++ b/sw/qa/extras/odfexport/odfexport2.cxx @@ -18,6 +18,7 @@ #include <com/sun/star/linguistic2/XHyphenator.hpp> #include <com/sun/star/style/VerticalAlignment.hpp> #include <com/sun/star/text/ColumnSeparatorStyle.hpp> +#include <com/sun/star/packages/zip/ZipFileAccess.hpp> #include <com/sun/star/text/XBookmarksSupplier.hpp> #include <com/sun/star/text/XChapterNumberingSupplier.hpp> #include <com/sun/star/text/XDocumentIndex.hpp> @@ -61,7 +62,7 @@ CPPUNIT_TEST_FIXTURE(Test, testEmbeddedFontProps) #if !defined(MACOSX) // Test that font style/weight of embedded fonts is exposed. // Test file is a normal ODT, except EmbedFonts is set to true in settings.xml. - xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr); + xmlDocUniquePtr pXmlDoc = parseExport(u"styles.xml"_ustr); // These failed, the attributes were missing. assertXPath(pXmlDoc, "//style:font-face[@style:name='Liberation Serif']/svg:font-face-src/svg:font-face-uri[1]", "font-style", u"normal"); assertXPath(pXmlDoc, "//style:font-face[@style:name='Liberation Serif']/svg:font-face-src/svg:font-face-uri[1]", "font-weight", u"normal"); @@ -74,6 +75,45 @@ CPPUNIT_TEST_FIXTURE(Test, testEmbeddedFontProps) #endif } +CPPUNIT_TEST_FIXTURE(Test, tdf166627) +{ + loadAndReload("font_used_in_header_only.fodt"); + // Liberation Sans wasn't embedded before fix, because it was only seen used in header + + xmlDocUniquePtr pXmlDoc = parseExport(u"styles.xml"_ustr); + + // There should be four files embedded for the font + assertXPath( + pXmlDoc, + "//style:font-face[@style:name='Liberation Sans']/svg:font-face-src/svg:font-face-uri", 4); + + uno::Reference<container::XNameAccess> xZipNames( + packages::zip::ZipFileAccess::createWithURL(comphelper::getProcessComponentContext(), + maTempFile.GetURL()), + uno::UNO_SET_THROW); + + OUString url = getXPath( + pXmlDoc, + "//style:font-face[@style:name='Liberation Sans']/svg:font-face-src/svg:font-face-uri[1]", + "href"); + CPPUNIT_ASSERT(xZipNames->hasByName(url)); + url = getXPath( + pXmlDoc, + "//style:font-face[@style:name='Liberation Sans']/svg:font-face-src/svg:font-face-uri[2]", + "href"); + CPPUNIT_ASSERT(xZipNames->hasByName(url)); + url = getXPath( + pXmlDoc, + "//style:font-face[@style:name='Liberation Sans']/svg:font-face-src/svg:font-face-uri[3]", + "href"); + CPPUNIT_ASSERT(xZipNames->hasByName(url)); + url = getXPath( + pXmlDoc, + "//style:font-face[@style:name='Liberation Sans']/svg:font-face-src/svg:font-face-uri[4]", + "href"); + CPPUNIT_ASSERT(xZipNames->hasByName(url)); +} + DECLARE_ODFEXPORT_TEST(testTdf100492, "tdf100492.odt") { CPPUNIT_ASSERT_EQUAL(2, getShapes()); diff --git a/sw/qa/extras/uiwriter/uiwriter6.cxx b/sw/qa/extras/uiwriter/uiwriter6.cxx index af5c132f880a..df064b740cb7 100644 --- a/sw/qa/extras/uiwriter/uiwriter6.cxx +++ b/sw/qa/extras/uiwriter/uiwriter6.cxx @@ -2230,6 +2230,7 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testFontEmbedding) createSwDoc("testFontEmbedding.odt"); OString aContentBaseXpath("/office:document-content/office:font-face-decls"_ostr); + OString aStylesBaseXpath("/office:document-styles/office:font-face-decls"_ostr); OString aSettingsBaseXpath( "/office:document-settings/office:settings/config:config-item-set"_ostr); @@ -2261,36 +2262,31 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testFontEmbedding) assertXPathContent( pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedFonts']", u"false"); + // Check styles - No font-face-src nodes should be present + pXmlDoc = parseExport(u"styles.xml"_ustr); + CPPUNIT_ASSERT(pXmlDoc); + + assertXPath(pXmlDoc, aStylesBaseXpath + "/style:font-face['CASE 1']", 6); + for (auto fontName : { "Caladea", "Carlito", "Liberation Sans", "Liberation Sans1", + "Liberation Serif", "Liberation Serif1" }) + { + OString prefix = aStylesBaseXpath + "/style:font-face[@style:name='" + fontName + "']"; + assertXPath(pXmlDoc, prefix + "['CASE 1']"); + assertXPath(pXmlDoc, prefix + "/svg:font-face-src['CASE 1']", 0); + } + // Check content - No font-face-src nodes should be present pXmlDoc = parseExport(u"content.xml"_ustr); CPPUNIT_ASSERT(pXmlDoc); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face", 6); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']"); - assertXPath( - pXmlDoc, - aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']/svg:font-face-src", 0); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans1']"); - assertXPath(pXmlDoc, - aContentBaseXpath - + "/style:font-face[@style:name='Liberation Sans1']/svg:font-face-src", - 0); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif']"); - assertXPath(pXmlDoc, - aContentBaseXpath - + "/style:font-face[@style:name='Liberation Serif']/svg:font-face-src", - 0); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif1']"); - assertXPath(pXmlDoc, - aContentBaseXpath - + "/style:font-face[@style:name='Liberation Serif1']/svg:font-face-src", - 0); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Carlito']"); - assertXPath(pXmlDoc, - aContentBaseXpath + "/style:font-face[@style:name='Carlito']/svg:font-face-src", 0); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Caladea']"); - assertXPath(pXmlDoc, - aContentBaseXpath + "/style:font-face[@style:name='Caladea']/svg:font-face-src", 0); + assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face['CASE 1']", 6); + for (auto fontName : { "Caladea", "Carlito", "Liberation Sans", "Liberation Sans1", + "Liberation Serif", "Liberation Serif1" }) + { + OString prefix = aContentBaseXpath + "/style:font-face[@style:name='" + fontName + "']"; + assertXPath(pXmlDoc, prefix + "['CASE 1']"); + assertXPath(pXmlDoc, prefix + "/svg:font-face-src['CASE 1']", 0); + } // CASE 2 - font embedding enabled, but embed used fonts disabled @@ -2302,7 +2298,7 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testFontEmbedding) save(u"writer8"_ustr); CPPUNIT_ASSERT(maTempFile.IsValid()); - // Check setting - font embedding should be enabled + embed only used fonts and scripts + // Check setting - font embedding should be enabled pXmlDoc = parseExport(u"settings.xml"_ustr); CPPUNIT_ASSERT(pXmlDoc); assertXPathContent( @@ -2320,37 +2316,31 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testFontEmbedding) pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedComplexScriptFonts']", u"true"); - // Check content - font-face-src should be present only for "Liberation Sans" fonts + // Check styles - font-face-src should be present for all fonts + pXmlDoc = parseExport(u"styles.xml"_ustr); + CPPUNIT_ASSERT(pXmlDoc); + + assertXPath(pXmlDoc, aStylesBaseXpath + "/style:font-face['CASE 2']", 6); + for (auto fontName : { "Caladea", "Carlito", "Liberation Sans", "Liberation Sans1", + "Liberation Serif", "Liberation Serif1" }) + { + OString prefix = aStylesBaseXpath + "/style:font-face[@style:name='" + fontName + "']"; + assertXPath(pXmlDoc, prefix + "['CASE 2']"); + assertXPath(pXmlDoc, prefix + "/svg:font-face-src['CASE 2']", 1); + } + // Check content - No font-face-src nodes should be present pXmlDoc = parseExport(u"content.xml"_ustr); CPPUNIT_ASSERT(pXmlDoc); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face", 6); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']"); - assertXPath( - pXmlDoc, - aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']/svg:font-face-src", 1); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans1']"); - assertXPath(pXmlDoc, - aContentBaseXpath - + "/style:font-face[@style:name='Liberation Sans1']/svg:font-face-src", - 1); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif']"); - assertXPath(pXmlDoc, - aContentBaseXpath - + "/style:font-face[@style:name='Liberation Serif']/svg:font-face-src", - 1); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif1']"); - assertXPath(pXmlDoc, - aContentBaseXpath - + "/style:font-face[@style:name='Liberation Serif1']/svg:font-face-src", - 1); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Carlito']"); - assertXPath(pXmlDoc, - aContentBaseXpath + "/style:font-face[@style:name='Carlito']/svg:font-face-src", 1); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Caladea']"); - assertXPath(pXmlDoc, - aContentBaseXpath + "/style:font-face[@style:name='Caladea']/svg:font-face-src", 1); + assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face['CASE 2']", 6); + for (auto fontName : { "Caladea", "Carlito", "Liberation Sans", "Liberation Sans1", + "Liberation Serif", "Liberation Serif1" }) + { + OString prefix = aContentBaseXpath + "/style:font-face[@style:name='" + fontName + "']"; + assertXPath(pXmlDoc, prefix + "['CASE 2']"); + assertXPath(pXmlDoc, prefix + "/svg:font-face-src['CASE 2']", 0); + } // CASE 3 - font embedding enabled, embed only used fonts enabled @@ -2383,37 +2373,42 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testFontEmbedding) pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedComplexScriptFonts']", u"true"); - // Check content - font-face-src should be present only for "Liberation Sans" fonts + // Check styles - font-face-src should be present only for "Liberation Serif" fonts + pXmlDoc = parseExport(u"styles.xml"_ustr); + CPPUNIT_ASSERT(pXmlDoc); + + assertXPath(pXmlDoc, aStylesBaseXpath + "/style:font-face['CASE 3']", 6); + for (auto fontName : { "Caladea", "Carlito", "Liberation Sans", "Liberation Sans1" }) + { + OString prefix = aStylesBaseXpath + "/style:font-face[@style:name='" + fontName + "']"; + assertXPath(pXmlDoc, prefix + "['CASE 3']"); + assertXPath(pXmlDoc, prefix + "/svg:font-face-src['CASE 3']", 0); + } + for (auto fontName : { "Liberation Serif", "Liberation Serif1" }) + { + OString prefix = aStylesBaseXpath + "/style:font-face[@style:name='" + fontName + "']"; + assertXPath(pXmlDoc, prefix + "['CASE 3']"); + assertXPath(pXmlDoc, prefix + "/svg:font-face-src['CASE 3']", 1); + } + // Check content - font-face-src should be present only for Carlito fonts pXmlDoc = parseExport(u"content.xml"_ustr); CPPUNIT_ASSERT(pXmlDoc); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face", 6); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']"); - assertXPath( - pXmlDoc, - aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']/svg:font-face-src", 0); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans1']"); - assertXPath(pXmlDoc, - aContentBaseXpath - + "/style:font-face[@style:name='Liberation Sans1']/svg:font-face-src", - 0); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif']"); - assertXPath(pXmlDoc, - aContentBaseXpath - + "/style:font-face[@style:name='Liberation Serif']/svg:font-face-src", - 1); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif1']"); - assertXPath(pXmlDoc, - aContentBaseXpath - + "/style:font-face[@style:name='Liberation Serif1']/svg:font-face-src", - 1); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Carlito']"); - assertXPath(pXmlDoc, - aContentBaseXpath + "/style:font-face[@style:name='Carlito']/svg:font-face-src", 1); - assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Caladea']"); - assertXPath(pXmlDoc, - aContentBaseXpath + "/style:font-face[@style:name='Caladea']/svg:font-face-src", 0); + assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face['CASE 3']", 6); + for (auto fontName : { "Caladea", "Liberation Sans", "Liberation Sans1", "Liberation Serif", + "Liberation Serif1" }) + { + 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" }) + { + OString prefix = aContentBaseXpath + "/style:font-face[@style:name='" + fontName + "']"; + assertXPath(pXmlDoc, prefix + "['CASE 3']"); + assertXPath(pXmlDoc, prefix + "/svg:font-face-src['CASE 3']", 1); + } #endif } diff --git a/sw/source/filter/xml/wrtxml.cxx b/sw/source/filter/xml/wrtxml.cxx index 01d0bd2b682e..66faa6342428 100644 --- a/sw/source/filter/xml/wrtxml.cxx +++ b/sw/source/filter/xml/wrtxml.cxx @@ -579,8 +579,14 @@ bool SwXMLWriter::WriteThroughComponent( if (pFilter) { pFilter->SetLibreOfficeKitNotifier(SfxViewShell::Current()); + pFilter->setEmbeddedFontNames(maEmbeddedFontNames); } - return xFilter->filter( rMediaDesc ); + bool result = xFilter->filter( rMediaDesc ); + if (pFilter) + { + maEmbeddedFontNames = pFilter->getEmbeddedFontNames(); + } + return result; } void GetXMLWriter( diff --git a/sw/source/filter/xml/wrtxml.hxx b/sw/source/filter/xml/wrtxml.hxx index abbdd7aa7bde..fa5e2a6f327b 100644 --- a/sw/source/filter/xml/wrtxml.hxx +++ b/sw/source/filter/xml/wrtxml.hxx @@ -25,6 +25,8 @@ #include <com/sun/star/beans/PropertyValue.hpp> #include <shellio.hxx> +#include <vector> + class SwPaM; class SfxMedium; @@ -55,6 +57,7 @@ public: virtual ErrCodeMsg Write( SwPaM&, SfxMedium&, const OUString* ) override; private: + std::vector<OUString> maEmbeddedFontNames; // helper methods to write XML streams @@ -73,7 +76,7 @@ private: // write a single output stream // (to be called either directly or by WriteThroughComponent(...)) - static bool WriteThroughComponent( + bool WriteThroughComponent( const css::uno::Reference<css::io::XOutputStream> & xOutputStream, const css::uno::Reference<css::lang::XComponent> & xComponent, const css::uno::Reference<css::uno::XComponentContext> & rFactory, diff --git a/sw/source/filter/xml/xmlexp.hxx b/sw/source/filter/xml/xmlexp.hxx index 6e095396db61..780ff0c8ddd7 100644 --- a/sw/source/filter/xml/xmlexp.hxx +++ b/sw/source/filter/xml/xmlexp.hxx @@ -112,6 +112,11 @@ protected: virtual XMLPageExport* CreatePageExport() override; virtual XMLShapeExport* CreateShapeExport() override; virtual XMLFontAutoStylePool* CreateFontAutoStylePool() override; + virtual bool getEmbedFonts() override; + virtual bool getEmbedOnlyUsedFonts() override; + virtual bool getEmbedLatinScript() override; + virtual bool getEmbedAsianScript() override; + virtual bool getEmbedComplexScript() override; public: SwXMLExport( diff --git a/sw/source/filter/xml/xmlfonte.cxx b/sw/source/filter/xml/xmlfonte.cxx index 8c521e5fe293..974542f1d4e0 100644 --- a/sw/source/filter/xml/xmlfonte.cxx +++ b/sw/source/filter/xml/xmlfonte.cxx @@ -33,7 +33,7 @@ namespace { class SwXMLFontAutoStylePool_Impl: public XMLFontAutoStylePool { public: - SwXMLFontAutoStylePool_Impl(SwXMLExport& rExport, bool bFontEmbedding); + SwXMLFontAutoStylePool_Impl(SwXMLExport& rExport); }; } @@ -56,8 +56,8 @@ sal_Int32 CompareTo(sal_Int32 nA, sal_Int32 nB) } } -SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl(SwXMLExport& _rExport, bool bFontEmbedding) - : XMLFontAutoStylePool(_rExport, bFontEmbedding) +SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl(SwXMLExport& _rExport) + : XMLFontAutoStylePool(_rExport) { TypedWhichId<SvxFontItem> const aWhichIds[3] = { RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT }; @@ -110,28 +110,32 @@ SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl(SwXMLExport& _rExport, Add(pFont->GetFamilyName(), pFont->GetStyleName(), pFont->GetFamily(), pFont->GetPitch(), pFont->GetCharSet()); } - - auto const pDocument = _rExport.getDoc(); - - m_bEmbedUsedOnly = pDocument->getIDocumentSettingAccess().get(DocumentSettingId::EMBED_USED_FONTS); - m_bEmbedLatinScript = pDocument->getIDocumentSettingAccess().get(DocumentSettingId::EMBED_LATIN_SCRIPT_FONTS); - m_bEmbedAsianScript = pDocument->getIDocumentSettingAccess().get(DocumentSettingId::EMBED_ASIAN_SCRIPT_FONTS); - m_bEmbedComplexScript = pDocument->getIDocumentSettingAccess().get(DocumentSettingId::EMBED_COMPLEX_SCRIPT_FONTS); - } XMLFontAutoStylePool* SwXMLExport::CreateFontAutoStylePool() { - bool blockFontEmbedding = false; - // We write font info to both content.xml and styles.xml, but they are both - // written by different SwXMLExport instance, and would therefore write each - // font file twice without complicated checking for duplicates, so handle - // the embedding only in one of them. - if( !( getExportFlags() & SvXMLExportFlags::CONTENT) ) - blockFontEmbedding = true; - if( !getDoc()->getIDocumentSettingAccess().get( DocumentSettingId::EMBED_FONTS )) - blockFontEmbedding = true; - return new SwXMLFontAutoStylePool_Impl( *this, !blockFontEmbedding ); + return new SwXMLFontAutoStylePool_Impl(*this); +} + +bool SwXMLExport::getEmbedFonts() +{ + return getDoc()->getIDocumentSettingAccess().get(DocumentSettingId::EMBED_FONTS); +} +bool SwXMLExport::getEmbedOnlyUsedFonts() +{ + return getDoc()->getIDocumentSettingAccess().get(DocumentSettingId::EMBED_USED_FONTS); +} +bool SwXMLExport::getEmbedLatinScript() +{ + return getDoc()->getIDocumentSettingAccess().get(DocumentSettingId::EMBED_LATIN_SCRIPT_FONTS); +} +bool SwXMLExport::getEmbedAsianScript() +{ + return getDoc()->getIDocumentSettingAccess().get(DocumentSettingId::EMBED_ASIAN_SCRIPT_FONTS); +} +bool SwXMLExport::getEmbedComplexScript() +{ + return getDoc()->getIDocumentSettingAccess().get(DocumentSettingId::EMBED_COMPLEX_SCRIPT_FONTS); } void SwXMLImport::NotifyContainsEmbeddedFont() diff --git a/xmloff/source/draw/sdxmlexp.cxx b/xmloff/source/draw/sdxmlexp.cxx index 74ee70aa6a33..93b88d8abb40 100644 --- a/xmloff/source/draw/sdxmlexp.cxx +++ b/xmloff/source/draw/sdxmlexp.cxx @@ -2774,47 +2774,36 @@ com_sun_star_comp_Impress_XMLClipboardExporter_get_implementation( XMLFontAutoStylePool* SdXMLExport::CreateFontAutoStylePool() { - bool bEmbedFonts = false; - bool bEmbedUsedOnly = false; - bool bEmbedLatinScript = true; - bool bEmbedAsianScript = true; - bool bEmbedComplexScript = true; - - if (getExportFlags() & SvXMLExportFlags::CONTENT) + try { - try - { - Reference<lang::XMultiServiceFactory> xFactory(GetModel(), UNO_QUERY); - Reference<beans::XPropertySet> xProps; - Reference<beans::XPropertySetInfo> xInfo; - - if (xFactory.is()) - xProps.set(xFactory->createInstance(u"com.sun.star.document.Settings"_ustr), UNO_QUERY); - if (xProps.is()) - xInfo = xProps->getPropertySetInfo(); - if (xInfo.is() && xProps.is()) - { - if (xInfo->hasPropertyByName(u"EmbedFonts"_ustr)) - xProps->getPropertyValue(u"EmbedFonts"_ustr) >>= bEmbedFonts; - if (xInfo->hasPropertyByName(u"EmbedOnlyUsedFonts"_ustr)) - xProps->getPropertyValue(u"EmbedOnlyUsedFonts"_ustr) >>= bEmbedUsedOnly; - if (xInfo->hasPropertyByName(u"EmbedLatinScriptFonts"_ustr)) - xProps->getPropertyValue(u"EmbedLatinScriptFonts"_ustr) >>= bEmbedLatinScript; - if (xInfo->hasPropertyByName(u"EmbedAsianScriptFonts"_ustr)) - xProps->getPropertyValue(u"EmbedAsianScriptFonts"_ustr) >>= bEmbedAsianScript; - if (xInfo->hasPropertyByName(u"EmbedComplexScriptFonts"_ustr)) - xProps->getPropertyValue(u"EmbedComplexScriptFonts"_ustr) >>= bEmbedComplexScript; - } - } catch(...) + Reference<lang::XMultiServiceFactory> xFactory(GetModel(), UNO_QUERY); + Reference<beans::XPropertySet> xProps; + Reference<beans::XPropertySetInfo> xInfo; + + if (xFactory.is()) + xProps.set(xFactory->createInstance(u"com.sun.star.document.Settings"_ustr), UNO_QUERY); + if (xProps.is()) + xInfo = xProps->getPropertySetInfo(); + if (xInfo.is() && xProps.is()) { - // clipboard document doesn't have shell so throws from getPropertyValue - // gallery elements may not support com.sun.star.document.Settings so throws from createInstance + if (xInfo->hasPropertyByName(u"EmbedFonts"_ustr)) + xProps->getPropertyValue(u"EmbedFonts"_ustr) >>= mbEmbedFonts; + if (xInfo->hasPropertyByName(u"EmbedOnlyUsedFonts"_ustr)) + xProps->getPropertyValue(u"EmbedOnlyUsedFonts"_ustr) >>= mbEmbedUsedOnly; + if (xInfo->hasPropertyByName(u"EmbedLatinScriptFonts"_ustr)) + xProps->getPropertyValue(u"EmbedLatinScriptFonts"_ustr) >>= mbEmbedLatinScript; + if (xInfo->hasPropertyByName(u"EmbedAsianScriptFonts"_ustr)) + xProps->getPropertyValue(u"EmbedAsianScriptFonts"_ustr) >>= mbEmbedAsianScript; + if (xInfo->hasPropertyByName(u"EmbedComplexScriptFonts"_ustr)) + xProps->getPropertyValue(u"EmbedComplexScriptFonts"_ustr) >>= mbEmbedComplexScript; } + } catch(...) + { + // clipboard document doesn't have shell so throws from getPropertyValue + // gallery elements may not support com.sun.star.document.Settings so throws from createInstance } - XMLFontAutoStylePool *pPool = new XMLFontAutoStylePool( *this, bEmbedFonts ); - pPool->setEmbedOnlyUsedFonts(bEmbedUsedOnly); - pPool->setEmbedFontScripts(bEmbedLatinScript, bEmbedAsianScript, bEmbedComplexScript); + XMLFontAutoStylePool* pPool = new XMLFontAutoStylePool(*this); Reference< beans::XPropertySet > xProps( GetModel(), UNO_QUERY ); if ( xProps.is() ) { diff --git a/xmloff/source/draw/sdxmlexp_impl.hxx b/xmloff/source/draw/sdxmlexp_impl.hxx index 8207d64e3b9e..ab79e5590f71 100644 --- a/xmloff/source/draw/sdxmlexp_impl.hxx +++ b/xmloff/source/draw/sdxmlexp_impl.hxx @@ -109,6 +109,12 @@ class SdXMLExport : public SvXMLExport bool mbIsDraw; + bool mbEmbedFonts = false; + bool mbEmbedUsedOnly = false; + bool mbEmbedLatinScript = true; + bool mbEmbedAsianScript = true; + bool mbEmbedComplexScript = true; + virtual void ExportStyles_(bool bUsed) override; virtual void ExportAutoStyles_() override; virtual void ExportFontDecls_() override; @@ -150,6 +156,11 @@ protected: virtual void GetViewSettings(css::uno::Sequence<css::beans::PropertyValue>& aProps) override; virtual void GetConfigurationSettings(css::uno::Sequence<css::beans::PropertyValue>& aProps) override; virtual XMLFontAutoStylePool* CreateFontAutoStylePool() override; + virtual bool getEmbedFonts() override { return mbEmbedFonts; } + virtual bool getEmbedOnlyUsedFonts() override { return mbEmbedUsedOnly; } + virtual bool getEmbedLatinScript() override { return mbEmbedLatinScript; } + virtual bool getEmbedAsianScript() override { return mbEmbedAsianScript; } + virtual bool getEmbedComplexScript() override { return mbEmbedComplexScript; } public: SdXMLExport( diff --git a/xmloff/source/style/XMLFontAutoStylePool.cxx b/xmloff/source/style/XMLFontAutoStylePool.cxx index 363b4a575e8e..e2050423b047 100644 --- a/xmloff/source/style/XMLFontAutoStylePool.cxx +++ b/xmloff/source/style/XMLFontAutoStylePool.cxx @@ -49,8 +49,6 @@ using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::xmloff::token; -namespace { - class XMLFontAutoStylePoolEntry_Impl { OUString sName; @@ -85,8 +83,6 @@ public: rtl_TextEncoding GetEncoding() const { return eEnc; } }; -} - inline XMLFontAutoStylePoolEntry_Impl::XMLFontAutoStylePoolEntry_Impl( OUString aName, OUString aFamilyName, @@ -150,14 +146,9 @@ class XMLFontAutoStylePool_Impl : public o3tl::sorted_vector<std::unique_ptr<XML { }; -XMLFontAutoStylePool::XMLFontAutoStylePool(SvXMLExport& rExp, bool bTryToEmbedFonts) : +XMLFontAutoStylePool::XMLFontAutoStylePool(SvXMLExport& rExp) : m_rExport( rExp ), - m_pFontAutoStylePool( new XMLFontAutoStylePool_Impl ), - m_bTryToEmbedFonts( bTryToEmbedFonts ), - m_bEmbedUsedOnly(false), - m_bEmbedLatinScript(true), - m_bEmbedAsianScript(true), - m_bEmbedComplexScript(true) + m_pFontAutoStylePool( new XMLFontAutoStylePool_Impl ) { } @@ -255,14 +246,6 @@ OUString lcl_checkFontFile( const OUString &fileUrl ) return OUString(); } -/// Contains information about a single variant of an embedded font. -struct EmbeddedFontInfo -{ - OUString aURL; - FontWeight eWeight = WEIGHT_NORMAL; - FontItalic eItalic = ITALIC_NONE; -}; - /// Converts FontWeight to CSS-compatible string representation. OUString FontWeightToString(FontWeight eWeight) { @@ -301,11 +284,11 @@ OUString FontItalicToString(FontItalic eWeight) } -std::unordered_set<OUString> XMLFontAutoStylePool::getUsedFontList() +std::unordered_set<OUString> SvXMLExport::getUsedFontList() { std::unordered_set<OUString> aReturnSet; - uno::Reference<style::XStyleFamiliesSupplier> xFamiliesSupp(GetExport().GetModel(), UNO_QUERY); + uno::Reference<style::XStyleFamiliesSupplier> xFamiliesSupp(GetModel(), UNO_QUERY); if (!xFamiliesSupp.is()) return aReturnSet; @@ -313,6 +296,9 @@ std::unordered_set<OUString> XMLFontAutoStylePool::getUsedFontList() uno::Reference<container::XNameAccess> xFamilies(xFamiliesSupp->getStyleFamilies()); if (xFamilies.is()) { + const bool bEmbedLatinScript = getEmbedLatinScript(); + const bool bEmbedAsianScript = getEmbedAsianScript(); + const bool bEmbedComplexScript = getEmbedComplexScript(); const uno::Sequence<OUString> aFamilyNames = xFamilies->getElementNames(); for (OUString const & sFamilyName : aFamilyNames) { @@ -332,7 +318,7 @@ std::unordered_set<OUString> XMLFontAutoStylePool::getUsedFontList() uno::Reference<beans::XPropertySetInfo> xInfo(xPropertySet ? xPropertySet->getPropertySetInfo() : nullptr); if (xInfo) { - if (m_bEmbedLatinScript && xInfo->hasPropertyByName(u"CharFontName"_ustr)) + if (bEmbedLatinScript && xInfo->hasPropertyByName(u"CharFontName"_ustr)) { OUString sCharFontName; Any aFontAny = xPropertySet->getPropertyValue(u"CharFontName"_ustr); @@ -340,7 +326,7 @@ std::unordered_set<OUString> XMLFontAutoStylePool::getUsedFontList() if (!sCharFontName.isEmpty()) aReturnSet.insert(sCharFontName); } - if (m_bEmbedAsianScript && xInfo->hasPropertyByName(u"CharFontNameAsian"_ustr)) + if (bEmbedAsianScript && xInfo->hasPropertyByName(u"CharFontNameAsian"_ustr)) { OUString sCharFontNameAsian; Any aFontAny = xPropertySet->getPropertyValue(u"CharFontNameAsian"_ustr); @@ -348,7 +334,7 @@ std::unordered_set<OUString> XMLFontAutoStylePool::getUsedFontList() if (!sCharFontNameAsian.isEmpty()) aReturnSet.insert(sCharFontNameAsian); } - if (m_bEmbedComplexScript && xInfo->hasPropertyByName(u"CharFontNameComplex"_ustr)) + if (bEmbedComplexScript && xInfo->hasPropertyByName(u"CharFontNameComplex"_ustr)) { OUString sCharFontNameComplex; Any aFontAny = xPropertySet->getPropertyValue(u"CharFontNameComplex"_ustr); @@ -364,10 +350,10 @@ std::unordered_set<OUString> XMLFontAutoStylePool::getUsedFontList() } // make sure auto-styles are collected - GetExport().collectAutoStyles(); + collectAutoStyles(); // Check auto-styles for fonts - std::vector<xmloff::AutoStyleEntry> aAutoStyleEntries = GetExport().GetAutoStylePool()->GetAutoStyleEntries(); + std::vector<xmloff::AutoStyleEntry> aAutoStyleEntries = GetAutoStylePool()->GetAutoStyleEntries(); for (auto const & rAutoStyleEntry : aAutoStyleEntries) { for (auto const & rPair : rAutoStyleEntry.m_aXmlProperties) @@ -389,103 +375,85 @@ std::unordered_set<OUString> XMLFontAutoStylePool::getUsedFontList() return aReturnSet; } -void XMLFontAutoStylePool::exportXML() +void SvXMLExport::exportFonts(const std::vector<XMLFontAutoStylePoolEntry_Impl*>& rFonts) { - SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_OFFICE, - XML_FONT_FACE_DECLS, - true, true); + SvXMLElementExport aElem(*this, XML_NAMESPACE_OFFICE, XML_FONT_FACE_DECLS, true, true); + Any aAny; OUString sTmp; XMLFontFamilyNamePropHdl aFamilyNameHdl; XMLFontFamilyPropHdl aFamilyHdl; XMLFontPitchPropHdl aPitchHdl; XMLFontEncodingPropHdl aEncHdl; - const SvXMLUnitConverter& rUnitConv = GetExport().GetMM100UnitConverter(); + const bool bEmbedFonts = getEmbedFonts(); + const bool bEmbedUsedOnly = bEmbedFonts && getEmbedOnlyUsedFonts(); std::map<OUString, OUString> fontFilesMap; // our url to document url std::unordered_set<OUString> aUsedFontNames; - if (m_bEmbedUsedOnly) + if (bEmbedUsedOnly) aUsedFontNames = getUsedFontList(); - // Sort <style:font-face> elements based on their style:name attribute. - std::vector<XMLFontAutoStylePoolEntry_Impl*> aFontAutoStyles; - for (const auto& pEntry : *m_pFontAutoStylePool) + for (const auto& pEntry : rFonts) { - aFontAutoStyles.push_back(pEntry.get()); - } - std::sort( - aFontAutoStyles.begin(), aFontAutoStyles.end(), - [](const XMLFontAutoStylePoolEntry_Impl* pA, XMLFontAutoStylePoolEntry_Impl* pB) -> bool { - return pA->GetName() < pB->GetName(); - }); - - for (const auto& pEntry : aFontAutoStyles) - { - GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, pEntry->GetName()); + AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, pEntry->GetName()); aAny <<= pEntry->GetFamilyName(); - if (aFamilyNameHdl.exportXML(sTmp, aAny, rUnitConv)) - GetExport().AddAttribute(XML_NAMESPACE_SVG, - XML_FONT_FAMILY, sTmp); + if (aFamilyNameHdl.exportXML(sTmp, aAny, GetMM100UnitConverter())) + AddAttribute(XML_NAMESPACE_SVG, XML_FONT_FAMILY, sTmp); const OUString& rStyleName = pEntry->GetStyleName(); if (!rStyleName.isEmpty()) - GetExport().AddAttribute(XML_NAMESPACE_STYLE, - XML_FONT_ADORNMENTS, - rStyleName); + AddAttribute(XML_NAMESPACE_STYLE, XML_FONT_ADORNMENTS, rStyleName); aAny <<= static_cast<sal_Int16>(pEntry->GetFamily()); - if (aFamilyHdl.exportXML(sTmp, aAny, rUnitConv)) + if (aFamilyHdl.exportXML(sTmp, aAny, GetMM100UnitConverter())) { - GetExport().AddAttribute(XML_NAMESPACE_STYLE, - XML_FONT_FAMILY_GENERIC, sTmp); + AddAttribute(XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC, sTmp); } aAny <<= static_cast<sal_Int16>(pEntry->GetPitch()); - if (aPitchHdl.exportXML(sTmp, aAny, rUnitConv)) + if (aPitchHdl.exportXML(sTmp, aAny, GetMM100UnitConverter())) { - GetExport().AddAttribute(XML_NAMESPACE_STYLE, - XML_FONT_PITCH, sTmp); + AddAttribute(XML_NAMESPACE_STYLE, XML_FONT_PITCH, sTmp); } aAny <<= static_cast<sal_Int16>(pEntry->GetEncoding()); - if (aEncHdl.exportXML( sTmp, aAny, rUnitConv)) + if (aEncHdl.exportXML(sTmp, aAny, GetMM100UnitConverter())) { - GetExport().AddAttribute(XML_NAMESPACE_STYLE, - XML_FONT_CHARSET, sTmp); + AddAttribute(XML_NAMESPACE_STYLE, XML_FONT_CHARSET, sTmp); } - SvXMLElementExport aElement(GetExport(), XML_NAMESPACE_STYLE, - XML_FONT_FACE, true, true); + SvXMLElementExport aElement(*this, XML_NAMESPACE_STYLE, XML_FONT_FACE, true, true); - if (m_bTryToEmbedFonts) + // 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())) { - const bool bExportFlat(GetExport().getExportFlags() & SvXMLExportFlags::EMBEDDED); - std::vector<EmbeddedFontInfo> aEmbeddedFonts; - static const std::vector<std::pair<FontWeight, FontItalic>> aCombinations = + const bool bExportFlat(getExportFlags() & SvXMLExportFlags::EMBEDDED); + + /// Contains information about a single variant of an embedded font. + struct EmbeddedFontInfo { - { WEIGHT_NORMAL, ITALIC_NONE }, - { WEIGHT_BOLD, ITALIC_NONE }, - { WEIGHT_NORMAL, ITALIC_NORMAL }, - { WEIGHT_BOLD, ITALIC_NORMAL }, + OUString aURL; + FontWeight eWeight; + FontItalic eItalic; }; + std::vector<EmbeddedFontInfo> aEmbeddedFonts; - for (auto const & aCombinationPair : aCombinations) + for (FontItalic fontItalic : { ITALIC_NONE, ITALIC_NORMAL }) { - // Embed font if at least viewing is allowed (in which case the opening app must check - // the font license rights too and open either read-only or not use the font for editing). - OUString sFileUrl = EmbeddedFontsHelper::fontFileUrl( - pEntry->GetFamilyName(), pEntry->GetFamily(), - aCombinationPair.second, aCombinationPair.first, pEntry->GetPitch(), - EmbeddedFontsHelper::FontRights::ViewingAllowed); - if (sFileUrl.isEmpty()) - continue; - - // When embedded only is not set or font is used - if (!m_bEmbedUsedOnly || - aUsedFontNames.find(pEntry->GetFamilyName()) != aUsedFontNames.end()) + for (FontWeight fontWeight : { WEIGHT_NORMAL, WEIGHT_BOLD }) { - if (!fontFilesMap.count(sFileUrl)) + // Embed font if at least viewing is allowed (in which case the opening app must check + // the font license rights too and open either read-only or not use the font for editing). + OUString sFileUrl = EmbeddedFontsHelper::fontFileUrl( + pEntry->GetFamilyName(), pEntry->GetFamily(), fontItalic, fontWeight, + pEntry->GetPitch(), EmbeddedFontsHelper::FontRights::ViewingAllowed); + if (sFileUrl.isEmpty()) + continue; + + if (!fontFilesMap.contains(sFileUrl)) { const OUString docUrl = bExportFlat ? lcl_checkFontFile(sFileUrl) : embedFontFile(sFileUrl, pEntry->GetFamilyName()); @@ -494,45 +462,42 @@ void XMLFontAutoStylePool::exportXML() else continue; // --> failed to embed } - EmbeddedFontInfo aEmbeddedFont; - aEmbeddedFont.aURL = sFileUrl; - aEmbeddedFont.eWeight = aCombinationPair.first; - aEmbeddedFont.eItalic = aCombinationPair.second; - aEmbeddedFonts.push_back(aEmbeddedFont); + aEmbeddedFonts.push_back({ sFileUrl, fontWeight, fontItalic }); } } if (!aEmbeddedFonts.empty()) { - SvXMLElementExport fontFaceSrc(GetExport(), XML_NAMESPACE_SVG, XML_FONT_FACE_SRC, true, true); + m_aEmbeddedFontNames.insert(pEntry->GetName()); + SvXMLElementExport fontFaceSrc(*this, XML_NAMESPACE_SVG, XML_FONT_FACE_SRC, true, true); for (EmbeddedFontInfo const & rEmbeddedFont : aEmbeddedFonts) { - if (fontFilesMap.count(rEmbeddedFont.aURL)) + if (fontFilesMap.contains(rEmbeddedFont.aURL)) { if (!bExportFlat) { - GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, - fontFilesMap[rEmbeddedFont.aURL]); - GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, u"simple"_ustr); + AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, + fontFilesMap[rEmbeddedFont.aURL]); + AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, u"simple"_ustr); } // Help consumers of our output by telling them which // font file is which one. - GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_FONT_STYLE, - FontItalicToString(rEmbeddedFont.eItalic)); - GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_FONT_WEIGHT, - FontWeightToString(rEmbeddedFont.eWeight)); + AddAttribute(XML_NAMESPACE_LO_EXT, XML_FONT_STYLE, + FontItalicToString(rEmbeddedFont.eItalic)); + AddAttribute(XML_NAMESPACE_LO_EXT, XML_FONT_WEIGHT, + FontWeightToString(rEmbeddedFont.eWeight)); - SvXMLElementExport fontFaceUri(GetExport(), XML_NAMESPACE_SVG, + SvXMLElementExport fontFaceUri(*this, XML_NAMESPACE_SVG, XML_FONT_FACE_URI, true, true); if (bExportFlat) { const uno::Reference<ucb::XSimpleFileAccess> xFileAccess( - ucb::SimpleFileAccess::create(GetExport().getComponentContext())); + ucb::SimpleFileAccess::create(getComponentContext())); try { const uno::Reference<io::XInputStream> xInput(xFileAccess->openFileRead(fontFilesMap[rEmbeddedFont.aURL])); - XMLBase64Export aBase64Exp(GetExport()); + XMLBase64Export aBase64Exp(*this); aBase64Exp.exportOfficeBinaryDataElement(xInput); } catch (const uno::Exception &) @@ -541,8 +506,8 @@ void XMLFontAutoStylePool::exportXML() } } - GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_STRING, u"truetype"_ustr); - SvXMLElementExport fontFaceFormat(GetExport(), XML_NAMESPACE_SVG, + AddAttribute(XML_NAMESPACE_SVG, XML_STRING, u"truetype"_ustr); + SvXMLElementExport fontFaceFormat(*this, XML_NAMESPACE_SVG, XML_FONT_FACE_FORMAT, true, true); } } @@ -551,6 +516,33 @@ void XMLFontAutoStylePool::exportXML() } } +std::vector<OUString> SvXMLExport::getEmbeddedFontNames() const +{ + return std::vector(m_aEmbeddedFontNames.begin(), m_aEmbeddedFontNames.end()); +} + +void SvXMLExport::setEmbeddedFontNames(const std::vector<OUString>& newNames) +{ + m_aEmbeddedFontNames.clear(); + m_aEmbeddedFontNames.insert(newNames.begin(), newNames.end()); +} + +void XMLFontAutoStylePool::exportXML() +{ + // Sort <style:font-face> elements based on their style:name attribute. + std::vector<XMLFontAutoStylePoolEntry_Impl*> aFontAutoStyles; + for (const auto& pEntry : *m_pFontAutoStylePool) + { + aFontAutoStyles.push_back(pEntry.get()); + } + std::sort( + aFontAutoStyles.begin(), aFontAutoStyles.end(), + [](const XMLFontAutoStylePoolEntry_Impl* pA, XMLFontAutoStylePoolEntry_Impl* pB) -> bool { + return pA->GetName() < pB->GetName(); + }); + GetExport().exportFonts(aFontAutoStyles); +} + static OUString getFreeFontName(uno::Reference<embed::XStorage> const & rxStorage, OUString const & rFamilyName) { OUString sName; @@ -609,7 +601,7 @@ static OString getFileHash(OUString const & rFileUrl) return convertToHashString(aHashEngine.finalize()); } -OUString XMLFontAutoStylePool::embedFontFile(OUString const & fileUrl, OUString const & rFamilyName) +OUString SvXMLExport::embedFontFile(OUString const& fileUrl, OUString const& rFamilyName) { try { @@ -621,11 +613,11 @@ OUString XMLFontAutoStylePool::embedFontFile(OUString const & fileUrl, OUString if( file.open( osl_File_OpenFlag_Read ) != osl::File::E_None ) return OUString(); - if ( !GetExport().GetTargetStorage().is() ) + if ( !GetTargetStorage().is() ) return OUString(); uno::Reference< embed::XStorage > storage; - storage.set( GetExport().GetTargetStorage()->openStorageElement( u"Fonts"_ustr, + storage.set( GetTargetStorage()->openStorageElement( u"Fonts"_ustr, ::embed::ElementModes::WRITE ), uno::UNO_SET_THROW ); OUString name = getFreeFontName(storage, rFamilyName);