include/sfx2/docfile.hxx                             |    8 +++
 include/vcl/embeddedfontshelper.hxx                  |   20 +++----
 oox/source/ppt/EmbeddedFontListContext.cxx           |    1 
 sfx2/source/doc/docfile.cxx                          |   16 ++++++
 sfx2/source/doc/objmisc.cxx                          |    2 
 sfx2/source/doc/sfxbasemodel.cxx                     |   10 +++
 sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx |    2 
 sw/source/writerfilter/dmapper/FontTable.cxx         |    7 +-
 sw/source/writerfilter/dmapper/FontTable.hxx         |    7 ++
 vcl/source/gdi/embeddedfontshelper.cxx               |   48 +++++++++++++++++--
 xmloff/source/core/xmlimp.cxx                        |    2 
 11 files changed, 103 insertions(+), 20 deletions(-)

New commits:
commit badc9c68dcbb12b358a81999618c57befcb411ed
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Sun Aug 10 15:29:46 2025 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Sun Aug 10 15:23:12 2025 +0200

    Delay embedded fonts activation until SfxObjectShell::FinishedLoading
    
    Embedded fonts may appear several times during document loading. Now,
    they activate immediately after current element was processed, and a
    portion of the embedded fonts was collected. The activation may also
    happen several times during the load process, each time refreshing
    fonts in all windows, which takes significant time.
    
    This change tries to not activate collected fonts in the destructor
    of EmbeddedFontsHelper, but to send the list to the model. The model
    accumulates the lists in its medium, and only activates late in the
    loading process, when all the embedded fonts are collected.
    
    Change-Id: Iff188e84e259206541bcc94880d8aead2b72715a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189310
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins

diff --git a/include/sfx2/docfile.hxx b/include/sfx2/docfile.hxx
index 6ab8d2ce5571..7e5b5aa4b8c6 100644
--- a/include/sfx2/docfile.hxx
+++ b/include/sfx2/docfile.hxx
@@ -30,6 +30,10 @@
 #include <svl/itemset.hxx>
 #include <tools/link.hxx>
 #include <tools/stream.hxx>
+
+#include <com/sun/star/beans/StringPair.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+
 #include <mutex>
 
 namespace com::sun::star::beans { struct PropertyValue; }
@@ -100,6 +104,7 @@ public:
     DECL_DLLPRIVATE_STATIC_LINK(SfxMedium, ShowReloadEditableDialog, void*, 
void);
     bool CheckCanGetLockfile() const;
     void SetOriginallyReadOnly(bool val);
+    void AddEmbeddedFonts(const css::uno::Sequence<css::beans::StringPair>& 
fonts);
     void AddToCheckEditableWorkerList();
     void SetWorkerReloadEvent(ImplSVEvent* pEvent);
     ImplSVEvent* GetWorkerReloadEvent() const;
@@ -202,6 +207,9 @@ public:
     // independent of later changes via SetOpenMode; used for SID_RELOAD:
     [[nodiscard]] bool IsOriginallyLoadedReadOnly() const;
 
+    // Activates the collected embedded fonts.
+    void activateEmbeddedFonts();
+
     [[nodiscard]] bool IsRepairPackage() const;
 
     css::uno::Reference< css::io::XInputStream > const &  GetInputStream();
diff --git a/include/vcl/embeddedfontshelper.hxx 
b/include/vcl/embeddedfontshelper.hxx
index 1b260fe1aa52..12059c7f07b8 100644
--- a/include/vcl/embeddedfontshelper.hxx
+++ b/include/vcl/embeddedfontshelper.hxx
@@ -19,6 +19,7 @@
 #include <string_view>
 #include <vector>
 
+namespace com::sun::star::frame { class XModel; }
 namespace com::sun::star::io { class XInputStream; }
 namespace com::sun::star::uno { template <typename > class Reference; }
 
@@ -26,14 +27,9 @@ namespace com::sun::star::uno { template <typename > class 
Reference; }
 class VCL_DLLPUBLIC EmbeddedFontsHelper
 {
 private:
+    css::uno::Reference<css::frame::XModel> m_xDocumentModel;
     std::vector<std::pair<OUString, OUString>> m_aAccumulatedFonts;
 
-    /**
-      Adds the accumulated fonts to the list of known fonts. The fonts are 
used only until application
-      exit.
-    */
-    void activateFonts();
-
 public:
     /// Specification of what kind of operation is allowed when embedding a 
font
     enum class FontRights
@@ -63,6 +59,12 @@ public:
         std::vector< unsigned char > const & key, bool eot = false,
         bool bSubsetted = false);
 
+    /**
+      Adds the passed fonts to the list of known fonts. The fonts are used 
only until application
+      exit.
+    */
+    static void activateFonts(std::vector<std::pair<OUString, OUString>>& 
fonts);
+
     /**
       Returns if the restrictions specified in the font (if present) allow 
embedding
       the font for a particular purpose.
@@ -92,10 +94,8 @@ public:
      */
     static bool isCommonFont(std::u16string_view aFontName);
 
-    ~EmbeddedFontsHelper() COVERITY_NOEXCEPT_FALSE
-    {
-        activateFonts();
-    }
+    EmbeddedFontsHelper(const css::uno::Reference<css::frame::XModel>& xModel);
+    ~EmbeddedFontsHelper() COVERITY_NOEXCEPT_FALSE;
 };
 
 #endif
diff --git a/oox/source/ppt/EmbeddedFontListContext.cxx 
b/oox/source/ppt/EmbeddedFontListContext.cxx
index de480363a3e3..731048236b10 100644
--- a/oox/source/ppt/EmbeddedFontListContext.cxx
+++ b/oox/source/ppt/EmbeddedFontListContext.cxx
@@ -24,6 +24,7 @@ EmbeddedFontListContext::EmbeddedFontListContext(
     FragmentHandler2 const& rParent, bool bEmbedTrueType,
     css::uno::Reference<css::beans::XPropertySet> const& rxDocSettings)
     : FragmentHandler2(rParent)
+    , maEmbeddedFontHelper(getFilter().getModel())
     , mbEmbedTrueType(bEmbedTrueType)
     , mxDocSettings(rxDocSettings)
 {
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index 87d23df72e40..a392e091cc19 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -126,6 +126,7 @@
 #include <openflag.hxx>
 #include <officecfg/Office/Common.hxx>
 #include <comphelper/propertysequence.hxx>
+#include <vcl/embeddedfontshelper.hxx>
 #include <vcl/weld.hxx>
 #include <vcl/svapp.hxx>
 #include <comphelper/diagnose_ex.hxx>
@@ -413,6 +414,9 @@ public:
     /// if true, xStorage is an inner package and not directly from xStream
     bool m_bODFWholesomeEncryption = false;
 
+    /// font family, file URL
+    std::vector<std::pair<OUString, OUString>> m_aEmbeddedFontsToActivate;
+
     OUString m_aName;
     OUString m_aLogicName;
     OUString m_aLongName;
@@ -3998,6 +4002,18 @@ bool SfxMedium::IsOriginallyLoadedReadOnly() const
     return pImpl->m_bOriginallyLoadedReadOnly;
 }
 
+void SfxMedium::AddEmbeddedFonts(
+    const css::uno::Sequence<css::beans::StringPair>& fonts)
+{
+    for (const auto& [ name, url ] : fonts)
+        pImpl->m_aEmbeddedFontsToActivate.emplace_back(name, url);
+}
+
+void SfxMedium::activateEmbeddedFonts()
+{
+    EmbeddedFontsHelper::activateFonts(pImpl->m_aEmbeddedFontsToActivate);
+}
+
 bool SfxMedium::SetWritableForUserOnly( const OUString& aURL )
 {
     // UCB does not allow to allow write access only for the user,
diff --git a/sfx2/source/doc/objmisc.cxx b/sfx2/source/doc/objmisc.cxx
index 9dbf71c0948b..dd52481d2687 100644
--- a/sfx2/source/doc/objmisc.cxx
+++ b/sfx2/source/doc/objmisc.cxx
@@ -1143,6 +1143,8 @@ void SfxObjectShell::FinishedLoading( SfxLoadedFlags 
nFlags )
         pImpl->nFlagsInProgress |= SfxLoadedFlags::MAINDOCUMENT;
         
static_cast<SfxHeaderAttributes_Impl*>(GetHeaderAttributes())->SetAttributes();
 
+        pMedium->activateEmbeddedFonts();
+
         if ( ( GetModifyPasswordHash() || 
GetModifyPasswordInfo().hasElements() ) && !IsModifyPasswordEntered() )
             SetReadOnly();
 
diff --git a/sfx2/source/doc/sfxbasemodel.cxx b/sfx2/source/doc/sfxbasemodel.cxx
index 603757f882e0..671ddf6c2180 100644
--- a/sfx2/source/doc/sfxbasemodel.cxx
+++ b/sfx2/source/doc/sfxbasemodel.cxx
@@ -44,6 +44,7 @@
 #include <com/sun/star/frame/DoubleInitializationException.hpp>
 #include <com/sun/star/embed/XStorage.hpp>
 #include <com/sun/star/document/XStorageChangeListener.hpp>
+#include <com/sun/star/beans/StringPair.hpp>
 #include <com/sun/star/beans/XPropertySet.hpp>
 #include <com/sun/star/beans/XPropertySetInfo.hpp>
 #include <com/sun/star/container/XIndexContainer.hpp>
@@ -1199,6 +1200,15 @@ void SAL_CALL SfxBaseModel::setArgs(const 
Sequence<beans::PropertyValue>& aArgs)
             pMedium->GetItemSet().Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA, 
rArg.Value));
             ok = true;
         }
+        else if (rArg.Name == "EmbeddedFonts")
+        {
+            if (uno::Sequence<beans::StringPair> fonts; rArg.Value >>= fonts)
+            {
+                pMedium->AddEmbeddedFonts(fonts);
+                ok = true;
+            }
+        }
+
         if (!ok)
         {
             throw lang::IllegalArgumentException("Setting property not 
supported: " + rArg.Name,
diff --git a/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx 
b/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx
index f578e3f0a229..fd3c170b1cb1 100644
--- a/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx
+++ b/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx
@@ -868,7 +868,7 @@ public:
     FontTablePtr const & GetFontTable()
     {
         if(!m_pFontTable)
-            m_pFontTable = new FontTable(m_bReadOnly);
+            m_pFontTable = new FontTable(m_xTextDocument, m_bReadOnly);
         return m_pFontTable;
     }
     StyleSheetTablePtr const & GetStyleSheetTable()
diff --git a/sw/source/writerfilter/dmapper/FontTable.cxx 
b/sw/source/writerfilter/dmapper/FontTable.cxx
index 2c839d3ab1e1..767031b9c13e 100644
--- a/sw/source/writerfilter/dmapper/FontTable.cxx
+++ b/sw/source/writerfilter/dmapper/FontTable.cxx
@@ -25,15 +25,18 @@
 #include <rtl/tencinfo.h>
 #include <unotools/fontdefs.hxx>
 
+#include <unotxdoc.hxx>
+
 using namespace com::sun::star;
 
 namespace writerfilter::dmapper
 {
 
-FontTable::FontTable(bool bReadOnly)
+FontTable::FontTable(const rtl::Reference<SwXTextDocument>& xModel, bool 
bReadOnly)
 : LoggedProperties("FontTable")
 , LoggedTable("FontTable")
 , LoggedStream("FontTable")
+, m_xModel(xModel)
 , m_bReadOnly(bReadOnly)
 {
 }
@@ -253,7 +256,7 @@ void FontTable::addEmbeddedFont(const 
css::uno::Reference<css::io::XInputStream>
                                 bool bSubsetted)
 {
     if (!m_xEmbeddedFontHelper)
-        m_xEmbeddedFontHelper.reset(new EmbeddedFontsHelper);
+        m_xEmbeddedFontHelper.reset(new EmbeddedFontsHelper(m_xModel));
     m_xEmbeddedFontHelper->addEmbeddedFont(stream, fontName, extra, key,
             /*eot=*/false, bSubsetted);
 }
diff --git a/sw/source/writerfilter/dmapper/FontTable.hxx 
b/sw/source/writerfilter/dmapper/FontTable.hxx
index 7f9c545c9f73..56b949fd04c1 100644
--- a/sw/source/writerfilter/dmapper/FontTable.hxx
+++ b/sw/source/writerfilter/dmapper/FontTable.hxx
@@ -23,10 +23,14 @@
 #include <vector>
 #include "LoggedResources.hxx"
 #include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/frame/XModel2.hpp>
 #include <com/sun/star/awt/FontFamily.hpp>
 #include <vcl/embeddedfontshelper.hxx>
 #include <o3tl/deleter.hxx>
 
+namespace rtl { template<class reference_type> class Reference; }
+class SwXTextDocument;
+
 namespace writerfilter::dmapper
 {
 
@@ -46,13 +50,14 @@ struct FontEntry : public virtual SvRefBase
 class FontTable : public LoggedProperties, public LoggedTable
     /*,public BinaryObj*/, public LoggedStream
 {
+    css::uno::Reference<css::frame::XModel2> m_xModel;
     std::unique_ptr<EmbeddedFontsHelper, 
o3tl::default_delete<EmbeddedFontsHelper>> m_xEmbeddedFontHelper;
     std::vector< FontEntry::Pointer_t > m_aFontEntries;
     FontEntry::Pointer_t m_pCurrentEntry;
     bool m_bReadOnly;
 
  public:
-    FontTable(bool bReadOnly);
+    FontTable(const rtl::Reference<SwXTextDocument>& xModel, bool bReadOnly);
     virtual ~FontTable() override;
 
     sal_uInt32          size();
diff --git a/vcl/source/gdi/embeddedfontshelper.cxx 
b/vcl/source/gdi/embeddedfontshelper.cxx
index a4d4f88c757e..3597207b1b35 100644
--- a/vcl/source/gdi/embeddedfontshelper.cxx
+++ b/vcl/source/gdi/embeddedfontshelper.cxx
@@ -23,6 +23,8 @@
 #include <vcl/svapp.hxx>
 #include <vcl/embeddedfontshelper.hxx>
 #include <com/sun/star/io/XInputStream.hpp>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/propertyvalue.hxx>
 #include <comphelper/storagehelper.hxx>
 
 #include <font/PhysicalFontFaceCollection.hxx>
@@ -30,6 +32,9 @@
 #include <salgdi.hxx>
 #include <sft.hxx>
 
+#include <com/sun/star/beans/StringPair.hpp>
+#include <com/sun/star/frame/XModel2.hpp>
+
 #if ENABLE_EOT
 extern "C"
 {
@@ -151,6 +156,39 @@ bool writeFontBytesToFile(const std::vector<char>& bytes, 
std::u16string_view na
 }
 }
 
+EmbeddedFontsHelper::EmbeddedFontsHelper(const uno::Reference<frame::XModel>& 
xModel)
+    : m_xDocumentModel(xModel)
+{
+}
+
+EmbeddedFontsHelper::~EmbeddedFontsHelper() COVERITY_NOEXCEPT_FALSE
+{
+    if (m_aAccumulatedFonts.empty())
+        return;
+
+    if (auto xModel2 = m_xDocumentModel.query<frame::XModel2>())
+    {
+        // Send embedded fonts list into the document's media descriptor.
+        // This helps to decide if the document is allowed to switch to edit 
mode.
+        try
+        {
+            uno::Sequence<beans::StringPair> fonts(m_aAccumulatedFonts.size());
+            std::transform(m_aAccumulatedFonts.begin(), 
m_aAccumulatedFonts.end(), fonts.getArray(),
+                           [](const auto& el) { return 
beans::StringPair(el.first, el.second); });
+            xModel2->setArgs({ 
comphelper::makePropertyValue(u"EmbeddedFonts"_ustr, fonts) });
+            // The following will not get executed, it setArgs throws
+            return;
+        }
+        catch (const uno::Exception&)
+        {
+            DBG_UNHANDLED_EXCEPTION("xmloff.core");
+        }
+    }
+
+    // Failed to transfer the read-only fonts to the document. Activate them 
here.
+    activateFonts(m_aAccumulatedFonts);
+}
+
 void EmbeddedFontsHelper::clearTemporaryFontFiles()
 {
     const OUString& path = GetEmbeddedFontsRoot();
@@ -268,15 +306,15 @@ namespace
     };
 }
 
-void EmbeddedFontsHelper::activateFonts()
+void EmbeddedFontsHelper::activateFonts(std::vector<std::pair<OUString, 
OUString>>& fonts)
 {
-    if (m_aAccumulatedFonts.empty())
+    if (fonts.empty())
         return;
     UpdateFontsGuard aUpdateFontsGuard;
     OutputDevice *pDevice = Application::GetDefaultDevice();
-    for (const auto& rEntry : m_aAccumulatedFonts)
-        pDevice->AddTempDevFont(rEntry.second, rEntry.first);
-    m_aAccumulatedFonts.clear();
+    for (const auto& [ fontName, fileUrl ] : fonts)
+        pDevice->AddTempDevFont(fileUrl, fontName);
+    fonts.clear();
 }
 
 // Check if it's (legally) allowed to embed the font file into a document
diff --git a/xmloff/source/core/xmlimp.cxx b/xmloff/source/core/xmlimp.cxx
index 368b54ae792f..a4704f9cdcd2 100644
--- a/xmloff/source/core/xmlimp.cxx
+++ b/xmloff/source/core/xmlimp.cxx
@@ -504,7 +504,7 @@ bool SvXMLImport::addEmbeddedFont(const 
css::uno::Reference< css::io::XInputStre
                                   std::vector<unsigned char> const & key, bool 
eot)
 {
     if (!mxEmbeddedFontHelper)
-        mxEmbeddedFontHelper.reset(new EmbeddedFontsHelper);
+        mxEmbeddedFontHelper.reset(new EmbeddedFontsHelper(mxModel));
     return mxEmbeddedFontHelper->addEmbeddedFont(stream, fontName, extra, key, 
eot);
 }
 

Reply via email to