bin/find-can-be-private-symbols.functions.results            |    8 
 bin/find-mergedlib-can-be-private-symbols.functions.results  |    8 
 compilerplugins/clang/constantparam.booleans.results         |    6 
 desktop/source/lib/lokinteractionhandler.cxx                 |    4 
 include/sfx2/docfile.hxx                                     |   13 
 include/vcl/embeddedfontsmanager.hxx                         |   25 -
 include/vcl/outdev.hxx                                       |    1 
 include/xmloff/xmlimp.hxx                                    |    8 
 ios/UnitTest/UnitTest.xcodeproj/project.pbxproj              |    4 
 offapi/UnoApi_offapi.mk                                      |    1 
 offapi/com/sun/star/document/FontsDisallowEditingRequest.idl |   26 +
 oox/source/export/drawingml.cxx                              |    6 
 oox/source/ppt/EmbeddedFontListContext.cxx                   |   18 
 oox/source/ppt/EmbeddedFontListContext.hxx                   |    4 
 sd/qa/unit/FontEmbeddingTest.cxx                             |   10 
 sd/source/filter/eppt/pptx-epptooxml.cxx                     |    8 
 sd/source/ui/func/fudraw.cxx                                 |    2 
 sd/source/ui/unoidl/unomodel.cxx                             |    2 
 sfx2/source/doc/docfile.cxx                                  |   46 +-
 sfx2/source/doc/objmisc.cxx                                  |    2 
 sfx2/source/doc/objserv.cxx                                  |    3 
 sfx2/source/doc/objstor.cxx                                  |    4 
 sfx2/source/view/viewfrm.cxx                                 |   12 
 solenv/clang-format/excludelist                              |    4 
 sw/qa/writerfilter/dmapper/FontTable.cxx                     |   10 
 sw/source/filter/ww8/docxattributeoutput.cxx                 |    8 
 sw/source/writerfilter/dmapper/FontTable.cxx                 |    6 
 sw/source/writerfilter/dmapper/FontTable.hxx                 |    4 
 uui/inc/strings.hrc                                          |    3 
 uui/source/iahndl.cxx                                        |   49 ++
 uui/source/iahndl.hxx                                        |    3 
 vcl/Library_vcl.mk                                           |    2 
 vcl/headless/svptext.cxx                                     |    5 
 vcl/inc/headless/svpgdi.hxx                                  |    1 
 vcl/inc/qt5/QtGraphics.hxx                                   |    1 
 vcl/inc/quartz/salgdi.h                                      |    1 
 vcl/inc/salgdi.hxx                                           |    4 
 vcl/inc/textrender.hxx                                       |    1 
 vcl/inc/unx/fontmanager.hxx                                  |    8 
 vcl/inc/unx/freetypetextrender.hxx                           |    1 
 vcl/inc/unx/genpspgraphics.h                                 |    2 
 vcl/inc/unx/glyphcache.hxx                                   |    1 
 vcl/inc/unx/salgdi.h                                         |    1 
 vcl/inc/win/salgdi.h                                         |    1 
 vcl/qt5/QtGraphics_Text.cxx                                  |    5 
 vcl/quartz/salgdi.cxx                                        |   24 +
 vcl/source/app/svmain.cxx                                    |    6 
 vcl/source/font/EOTConverter.cxx                             |    2 
 vcl/source/gdi/embeddedfontsmanager.cxx                      |  244 +++++++++--
 vcl/source/outdev/font.cxx                                   |    9 
 vcl/unx/generic/fontmanager/fontconfig.cxx                   |   34 +
 vcl/unx/generic/fontmanager/fontmanager.cxx                  |   34 +
 vcl/unx/generic/gdi/font.cxx                                 |    5 
 vcl/unx/generic/gdi/freetypetextrender.cxx                   |   16 
 vcl/unx/generic/glyphs/freetype_glyphcache.cxx               |    7 
 vcl/unx/generic/print/genpspgraphics.cxx                     |    5 
 vcl/win/gdi/salfont.cxx                                      |   20 
 xmloff/source/core/xmlimp.cxx                                |    8 
 xmloff/source/style/XMLFontAutoStylePool.cxx                 |    8 
 59 files changed, 643 insertions(+), 121 deletions(-)

New commits:
commit fdd24dabb6f8c520e8307bacab2bd8b09ebc763d
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Mon Aug 11 17:55:27 2025 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Tue Aug 12 14:14:52 2025 +0200

    tdf#145967: Initial support for docs with restricted embedded fonts
    
    Previously, we silently discarded fonts which rights disallowed editing
    of documents. This change introduces a choice, where user can opt to
    either discard the restricted fonts, or switch to read-only mode.
    
    1. When user opens a document with restricted embedded fonts, which are
       already installed on the system, those fonts are not considered as
       restricted.
    
    2. Trying to switch to edit mode will show the dialog again, allowing
       to discard those fonts to allow editing.
    
    3. Saving the document will discard restricted fonts not installed on
       the system in any case.
    
    4. Even though saving discards those fonts from file, it doesn't switch
       to edit mode, because it doesn't reload the document, that is needed
       to reload embedded font data (and release respective font files).
    
    5. Opening a document initially in read-only mode skips the dialog.
    
    TODO: avoid showing those fonts in the font lists.
    
    Change-Id: Ia7c9b6c3f727720e64e4df8d1c4a8e3641b067bd
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189366
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins

diff --git a/desktop/source/lib/lokinteractionhandler.cxx 
b/desktop/source/lib/lokinteractionhandler.cxx
index 723a87fb934b..858793b856b9 100644
--- a/desktop/source/lib/lokinteractionhandler.cxx
+++ b/desktop/source/lib/lokinteractionhandler.cxx
@@ -23,6 +23,7 @@
 #include <cppuhelper/supportsservice.hxx>
 
 #include <com/sun/star/document/BrokenPackageRequest.hpp>
+#include <com/sun/star/document/FontsDisallowEditingRequest.hpp>
 #include <com/sun/star/beans/NamedValue.hpp>
 #include <com/sun/star/task/XInteractionAbort.hpp>
 #include <com/sun/star/task/XInteractionApprove.hpp>
@@ -153,6 +154,9 @@ bool ShouldFallbackToStandard(const 
uno::Reference<task::XInteractionRequest>& x
     if (document::FilterOptionsRequest aStruct; request >>= aStruct)
         return true;
 
+    if (document::FontsDisallowEditingRequest aStruct; request >>= aStruct)
+        return true;
+
     if (beans::NamedValue aStruct; request >>= aStruct)
         if (aStruct.Name == "LoadReadOnlyRequest")
             if (OUString aFileName; aStruct.Value >>= aFileName)
diff --git a/include/sfx2/docfile.hxx b/include/sfx2/docfile.hxx
index e15983b65a6c..ec95a16bacf9 100644
--- a/include/sfx2/docfile.hxx
+++ b/include/sfx2/docfile.hxx
@@ -209,7 +209,13 @@ public:
     // independent of later changes via SetOpenMode; used for SID_RELOAD:
     [[nodiscard]] bool IsOriginallyLoadedReadOnly() const;
 
-    // Activates the collected embedded fonts.
+    // Whether the medium has embedded fonts that disallow editing of the 
document,
+    // meaning that it can't be switched to editing mode at all, without 
reloading
+    // and discarding these fonts:
+    [[nodiscard]] bool HasRestrictedFonts() const;
+
+    // Activates collected embedded fonts. Here it may ask user to approve use 
of restricted fonts,
+    // and switch tyo read-only mode.
     void activateEmbeddedFonts();
 
     [[nodiscard]] bool IsRepairPackage() const;
diff --git a/include/vcl/embeddedfontsmanager.hxx 
b/include/vcl/embeddedfontsmanager.hxx
index 798de1f310fb..a1cb9e3021aa 100644
--- a/include/vcl/embeddedfontsmanager.hxx
+++ b/include/vcl/embeddedfontsmanager.hxx
@@ -20,6 +20,7 @@
 
 namespace com::sun::star::frame { class XModel; }
 namespace com::sun::star::io { class XInputStream; }
+namespace com::sun::star::task { class XInteractionHandler; }
 namespace com::sun::star::uno { template <typename > class Reference; }
 
 /** Helper functions for handling embedded fonts in documents. */
@@ -61,8 +62,17 @@ public:
     /**
       Adds the passed fonts to the list of known fonts. The fonts are used 
only until application
       exit.
+
+      If some fonts are restricted (i.e., block document editing), and 
'silentlyAllowRestricted' is
+      false, it checks if interaction handle is set; if it is, then asks user 
to approve read-only
+      mode. If 'silentlyAllowRestricted' is true; or if user approved 
switching to read-only mode,
+      then it activates all the fonts (and sets 'activatedRestrictedFonts' to 
true). Otherwise, it
+      removes these fonts from 'fonts', releases them, and only activates 
unrestricted fonts.
     */
-    static void activateFonts(std::vector<std::pair<OUString, OUString>>& 
fonts);
+    static void activateFonts(std::vector<std::pair<OUString, OUString>>& 
fonts,
+                              bool silentlyAllowRestrictedFonts,
+                              const 
css::uno::Reference<css::task::XInteractionHandler>& xHandler,
+                              bool& activatedRestrictedFonts);
 
     /**
       Returns if the restrictions specified in the font (if present) allow 
embedding
diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk
index 476269912352..0188d2ab7ba1 100644
--- a/offapi/UnoApi_offapi.mk
+++ b/offapi/UnoApi_offapi.mk
@@ -2172,6 +2172,7 @@ $(eval $(call 
gb_UnoApi_add_idlfiles,offapi,com/sun/star/document,\
        EventObject \
        ExoticFileLoadException \
        FilterOptionsRequest \
+       FontsDisallowEditingRequest \
        LinkUpdateModes \
        LockFileCorruptRequest \
        LockFileIgnoreRequest \
diff --git a/offapi/com/sun/star/document/FontsDisallowEditingRequest.idl 
b/offapi/com/sun/star/document/FontsDisallowEditingRequest.idl
new file mode 100644
index 000000000000..5a47f440bff6
--- /dev/null
+++ b/offapi/com/sun/star/document/FontsDisallowEditingRequest.idl
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+module com { module sun { module star { module document {
+
+/** Some fonts embedded in the document have no editing permissions.
+    The document can only be opened read-only.
+
+    @since LibreOffice 26.2
+*/
+exception FontsDisallowEditingRequest : ::com::sun::star::uno::Exception
+{
+    /** The names of the fonts that lack editing permission (
-separated) */
+    string aFontNames;
+
+};
+
+}; }; }; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/sd/source/ui/func/fudraw.cxx b/sd/source/ui/func/fudraw.cxx
index bb1811ab037f..acbc2d412880 100644
--- a/sd/source/ui/func/fudraw.cxx
+++ b/sd/source/ui/func/fudraw.cxx
@@ -245,7 +245,7 @@ bool FuDraw::MouseMove(const MouseEvent& rMEvt)
             bOrtho = rMEvt.IsShift() != pFrameView->IsOrtho();
         }
 
-        bool bSnapModPressed = rMEvt.IsMod2();
+        bool bSnapModPressed = mpView->IsDragObj() ? rMEvt.IsMod2() : 
rMEvt.IsMod1();
         mpView->SetDragWithCopy(rMEvt.IsMod1() && 
pFrameView->IsDragWithCopy());
 
         if (mpView->IsOrtho() != bOrtho)
diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx
index 8ccf6990c85d..07d52cb6440f 100644
--- a/sd/source/ui/unoidl/unomodel.cxx
+++ b/sd/source/ui/unoidl/unomodel.cxx
@@ -2889,7 +2889,7 @@ uno::Any SAL_CALL SdXImpressDocument::getPropertyValue( 
const OUString& Property
 
     uno::Any aAny;
     if( nullptr == mpDoc )
-        throw lang::DisposedException();
+        throw lang::DisposedException({}, getXWeak());
 
     const SfxItemPropertyMapEntry* pEntry = 
mpPropSet->getPropertyMapEntry(PropertyName);
 
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index 85e1ce3dd9db..d483a341804b 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -415,6 +415,9 @@ public:
     /// if true, xStorage is an inner package and not directly from xStream
     bool m_bODFWholesomeEncryption = false;
 
+    /// If there are such fonts, the document can't be set into editing mode;
+    /// these can't be embedded on save.
+    bool hasRestrictedFonts = false;
     /// font family, file URL
     std::vector<std::pair<OUString, OUString>> m_aEmbeddedFonts;
     std::vector<std::pair<OUString, OUString>> m_aEmbeddedFontsToActivate;
@@ -3997,6 +4000,10 @@ bool SfxMedium::IsReadOnly() const
             bReadOnly = pItem->GetValue();
     }
 
+    // d) Embedded fonts may disallow editing
+    if (!bReadOnly)
+        bReadOnly = HasRestrictedFonts();
+
     return bReadOnly;
 }
 
@@ -4015,8 +4022,11 @@ bool SfxMedium::IsOriginallyLoadedReadOnly() const
     return pImpl->m_bOriginallyLoadedReadOnly;
 }
 
+bool SfxMedium::HasRestrictedFonts() const { return pImpl->hasRestrictedFonts; 
}
+
 void SfxMedium::TransferEmbeddedFontsTo(SfxMedium& target)
 {
+    target.pImpl->hasRestrictedFonts = target.pImpl->hasRestrictedFonts || 
pImpl->hasRestrictedFonts;
     target.pImpl->m_aEmbeddedFonts.insert(target.pImpl->m_aEmbeddedFonts.end(),
                                           pImpl->m_aEmbeddedFonts.begin(),
                                           pImpl->m_aEmbeddedFonts.end());
@@ -4036,7 +4046,10 @@ void SfxMedium::AddEmbeddedFonts(
 
 void SfxMedium::activateEmbeddedFonts()
 {
-    EmbeddedFontsManager::activateFonts(pImpl->m_aEmbeddedFontsToActivate);
+    bool bActivatedRestrictedFonts;
+    EmbeddedFontsManager::activateFonts(pImpl->m_aEmbeddedFontsToActivate, 
IsReadOnly(),
+                                       GetInteractionHandler(), 
bActivatedRestrictedFonts);
+    pImpl->hasRestrictedFonts = pImpl->hasRestrictedFonts || 
bActivatedRestrictedFonts;
     pImpl->m_aEmbeddedFonts.insert(pImpl->m_aEmbeddedFonts.end(),
                                    pImpl->m_aEmbeddedFontsToActivate.begin(),
                                    pImpl->m_aEmbeddedFontsToActivate.end());
diff --git a/sfx2/source/doc/objmisc.cxx b/sfx2/source/doc/objmisc.cxx
index dd52481d2687..85aef306e161 100644
--- a/sfx2/source/doc/objmisc.cxx
+++ b/sfx2/source/doc/objmisc.cxx
@@ -434,7 +434,7 @@ void SfxObjectShell::SetReadOnly()
 
 bool SfxObjectShell::IsReadOnly() const
 {
-    return pImpl->bReadOnlyUI || pMedium == nullptr;
+    return pImpl->bReadOnlyUI || pMedium == nullptr || 
pMedium->HasRestrictedFonts();
 }
 
 
diff --git a/sfx2/source/doc/objserv.cxx b/sfx2/source/doc/objserv.cxx
index 9ce43e1b6f02..3d32d342ddb8 100644
--- a/sfx2/source/doc/objserv.cxx
+++ b/sfx2/source/doc/objserv.cxx
@@ -1312,7 +1312,8 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq)
             if ( ( nId == SID_SAVEASDOC || nId == SID_SAVEASREMOTE ) && 
nErrorCode == ERRCODE_NONE )
             {
                 const SfxBoolItem* saveTo = 
rReq.GetArg<SfxBoolItem>(SID_SAVETO);
-                if (saveTo == nullptr || !saveTo->GetValue())
+                // IsReadOnly may still return true, e.g. when embedded fonts 
disallow editing
+                if ((saveTo == nullptr || !saveTo->GetValue()) && 
!IsReadOnly())
                 {
                     if (SfxViewFrame* pFrame = GetFrame())
                         pFrame->RemoveInfoBar(u"readonly");
diff --git a/sfx2/source/view/viewfrm.cxx b/sfx2/source/view/viewfrm.cxx
index c8b088b378a5..831e5eb59ff7 100644
--- a/sfx2/source/view/viewfrm.cxx
+++ b/sfx2/source/view/viewfrm.cxx
@@ -279,6 +279,9 @@ bool physObjIsOlder(INetURLObject const & aMedObj, 
INetURLObject const & aPhysOb
 
 void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
 {
+    // Open as editable?
+    std::optional<bool> oForEdit;
+
     SfxObjectShell* pSh = GetObjectShell();
     switch ( rReq.GetSlot() )
     {
@@ -403,6 +406,8 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
 
                 nOpenMode = pSh->IsOriginallyReadOnlyMedium() ? 
SFX_STREAM_READONLY : SFX_STREAM_READWRITE;
                 aReadOnlyUIGuard.m_bSetRO = false;
+                if (pMed->HasRestrictedFonts())
+                    bNeedsReload = true; // Let it ask user, reload fonts, etc.
 
                 // if only the view was in the readonly mode then there is no 
need to do the reload
                 if ( !pSh->IsReadOnlyMedium() )
@@ -610,6 +615,8 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
                     || bNeedsReload) );
             rReq.AppendItem( SfxBoolItem( SID_SILENT, true ));
 
+            oForEdit = !aReadOnlyUIGuard.m_bSetRO;
+
             [[fallthrough]]; //TODO ???
         }
 
@@ -638,7 +645,8 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
             m_pImpl->bReloading = true;
             const SfxStringItem* pURLItem = 
rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
             // Open as editable?
-            bool bForEdit = !pSh->IsReadOnly();
+            if (!oForEdit.has_value())
+                oForEdit = !pSh->IsReadOnly();
 
             // If possible ask the User
             bool bDo = GetViewShell()->PrepareClose();
@@ -826,7 +834,7 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
                     }
                     else if ( rReq.GetSlot() == SID_EDITDOC || rReq.GetSlot() 
== SID_READONLYDOC )
                     {
-                        xNewObj->SetReadOnlyUI( !bForEdit );
+                        xNewObj->SetReadOnlyUI(!*oForEdit);
                     }
 
 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
diff --git a/uui/inc/strings.hrc b/uui/inc/strings.hrc
index 66cc704e97fb..28c0ccd83ad0 100644
--- a/uui/inc/strings.hrc
+++ b/uui/inc/strings.hrc
@@ -81,4 +81,7 @@
 #define STR_LOADREADONLY_MSG                    NC_("STR_LOADREADONLY_MSG", 
"The author would like you to open '$(ARG1)' as read-only unless you need to 
make changes. Open as read-only?")
 #define STR_VERIFY_CERT                         NC_("STR_VERIFY_CERT", "You 
need to view the certificate first.")
 
+#define STR_READONLY_FONT_TITLE                 NC_("STR_READONLY_FONT_TITLE", 
"Font Disallows Editing")
+#define STR_READONLY_FONT_MSG                   NC_("STR_READONLY_FONT_MSG", 
"One or more fonts embedded in the document have no editing permission.
Open document in read-only mode?
Pressing [ No ] will drop these fonts from the document:
$(ARG1)")
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/uui/source/iahndl.cxx b/uui/source/iahndl.cxx
index b884e87c931c..847b72e2aa07 100644
--- a/uui/source/iahndl.cxx
+++ b/uui/source/iahndl.cxx
@@ -26,6 +26,7 @@
 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
 #include <com/sun/star/document/BrokenPackageRequest.hpp>
 #include <com/sun/star/document/ExoticFileLoadException.hpp>
+#include <com/sun/star/document/FontsDisallowEditingRequest.hpp>
 #include <com/sun/star/task/DocumentMacroConfirmationRequest.hpp>
 #include <com/sun/star/java/WrongJavaVersionException.hpp>
 #include <com/sun/star/lang/XInitialization.hpp>
@@ -697,6 +698,9 @@ UUIInteractionHelper::handleRequest_impl(
             return true;
         }
 
+        if (handleFontsDisallowEditingRequest(rRequest))
+            return true;
+
         task::ErrorCodeRequest2 aErrorCodeRequest2;
         if (aAnyRequest >>= aErrorCodeRequest2)
         {
@@ -1151,6 +1155,51 @@ UUIInteractionHelper::handleBrokenPackageRequest(
     }
 }
 
+bool UUIInteractionHelper::handleFontsDisallowEditingRequest(
+    const uno::Reference<task::XInteractionRequest>& rRequest)
+{
+    document::FontsDisallowEditingRequest aRequest;
+    if (!(rRequest->getRequest() >>= aRequest))
+        return false;
+
+    uno::Reference<task::XInteractionApprove> xApprove;
+    uno::Reference<task::XInteractionDisapprove> xDisapprove;
+    getContinuations(rRequest->getContinuations(), &xApprove, &xDisapprove);
+
+    if (xApprove.is() && xDisapprove.is())
+    {
+        std::locale aResLocale = Translate::Create("uui");
+        OUString title(utl::ConfigManager::getProductName());
+
+        OUString title2 = Translate::get(STR_READONLY_FONT_TITLE, aResLocale);
+        if (!title.isEmpty() && !title2.isEmpty())
+            title += " - ";
+        title += title2;
+
+        OUString aMessage = replaceMessageWithArguments(
+            Translate::get(STR_READONLY_FONT_MSG, aResLocale), { 
aRequest.aFontNames });
+
+        switch 
(executeMessageBox(Application::GetFrameWeld(getParentXWindow()), title, 
aMessage,
+                                  VclMessageType::Question))
+        {
+            case DialogMask::ButtonsNo:
+                if (xDisapprove.is())
+                    xDisapprove->select();
+                break;
+
+            case DialogMask::ButtonsYes:
+                if (xApprove.is())
+                    xApprove->select();
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    return true;
+}
+
 // ErrorResource Implementation
 bool ErrorResource::getString(ErrCode nErrorCode, OUString &rString) const
 {
diff --git a/uui/source/iahndl.hxx b/uui/source/iahndl.hxx
index e193b1be04c8..51045f59282d 100644
--- a/uui/source/iahndl.hxx
+++ b/uui/source/iahndl.hxx
@@ -196,6 +196,9 @@ private:
         bool & bHasErrorString,
         OUString & rErrorString);
 
+    bool handleFontsDisallowEditingRequest(
+        const css::uno::Reference<css::task::XInteractionRequest>& rRequest);
+
     bool handleLockedDocumentRequest(
         css::uno::Reference< css::task::XInteractionRequest > const & 
rRequest);
 
diff --git a/vcl/source/font/EOTConverter.cxx b/vcl/source/font/EOTConverter.cxx
index 12d52038a506..803b02406f82 100644
--- a/vcl/source/font/EOTConverter.cxx
+++ b/vcl/source/font/EOTConverter.cxx
@@ -92,7 +92,7 @@ bool EOTConverter::convert(std::vector<sal_uInt8>& rEotOutput)
         pEot->nWeight = pOS2->nWeightClass;
         // FIXME: Should use OS2->fsType, but some TrueType fonts set it to an 
over-restrictive value.
         // Since ATS does not enforce this on Mac OS X, we do not enforce it 
either.
-        pEot->nFsType = 0x0000;
+        pEot->nFsType = pOS2->nFsType;
         pEot->nUnicodeRange1 = pOS2->nUnicodeRange1;
         pEot->nUnicodeRange2 = pOS2->nUnicodeRange2;
         pEot->nUnicodeRange3 = pOS2->nUnicodeRange3;
diff --git a/vcl/source/gdi/embeddedfontsmanager.cxx 
b/vcl/source/gdi/embeddedfontsmanager.cxx
index c9a10c2b2365..b08732ccce15 100644
--- a/vcl/source/gdi/embeddedfontsmanager.cxx
+++ b/vcl/source/gdi/embeddedfontsmanager.cxx
@@ -11,6 +11,7 @@
 
 #include <memory>
 #include <mutex>
+#include <set>
 #include <unordered_map>
 #include <frozen/bits/defines.h>
 #include <frozen/bits/elsa_std.h>
@@ -18,6 +19,7 @@
 #include <config_folders.h>
 #include <config_eot.h>
 
+#include <o3tl/temporary.hxx>
 #include <osl/file.hxx>
 #include <rtl/bootstrap.hxx>
 #include <rtl/uri.hxx>
@@ -26,6 +28,7 @@
 #include <vcl/embeddedfontsmanager.hxx>
 #include <com/sun/star/io/XInputStream.hpp>
 #include <comphelper/diagnose_ex.hxx>
+#include <comphelper/interaction.hxx>
 #include <comphelper/propertyvalue.hxx>
 #include <comphelper/storagehelper.hxx>
 
@@ -35,6 +38,8 @@
 #include <sft.hxx>
 
 #include <com/sun/star/beans/StringPair.hpp>
+#include <com/sun/star/document/FontsDisallowEditingRequest.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
 #include <com/sun/star/frame/XModel2.hpp>
 
 #if ENABLE_EOT
@@ -68,6 +73,7 @@ struct EmbeddedFontData
 {
     OUString familyName;
     int refcount = 0;
+    bool isRestricted = true; // Has restricted permissions, *and* isn't 
installed locally
     bool isActivated = false;
 };
 
@@ -75,6 +81,24 @@ std::mutex s_EmbeddedFontsMutex;
 // file URL -> EmbeddedFontData
 std::unordered_map<OUString, EmbeddedFontData> s_EmbeddedFonts;
 
+bool isFontAvailableUnrestricted(std::u16string_view family, const OUString& 
fileURL)
+{
+    // Check if the font is already installed on system. It is either 
available and not among
+    // existing embedded files; or it could be listed among embedded, but 
without restrictions
+    // (because it was checked here before, and restrictions were removed). 
The idea is, that
+    // you can always edit your files with the restricted fonts taken from 
your own system.
+
+    if (Application::GetDefaultDevice()->IsFontAvailable(family))
+    {
+        std::unique_lock lock(s_EmbeddedFontsMutex);
+        auto it = s_EmbeddedFonts.find(fileURL);
+        if (it == s_EmbeddedFonts.end() || !it->second.isRestricted)
+            return true;
+    }
+
+    return false;
+}
+
 void clearDir( const OUString& path )
 {
     osl::Directory dir( path );
@@ -196,8 +220,9 @@ EmbeddedFontsManager::~EmbeddedFontsManager() 
COVERITY_NOEXCEPT_FALSE
         }
     }
 
-    // Failed to transfer the fonts to the document. Activate them here.
-    activateFonts(m_aAccumulatedFonts);
+    // Failed to transfer the fonts to the document. Activate them here, 
discarding restricted.
+    // They won't be released, so will stay until the application shutdown.
+    activateFonts(m_aAccumulatedFonts, false, {}, o3tl::temporary(bool()));
 }
 
 void EmbeddedFontsManager::clearTemporaryFontFiles()
@@ -255,14 +280,6 @@ bool EmbeddedFontsManager::addEmbeddedFont( const 
uno::Reference< io::XInputStre
     {
         sufficientFontRights = sufficientTTFRights(fontData.data(), 
fontData.size(), FontRights::EditingAllowed);
     }
-    if( !sufficientFontRights )
-    {
-        // It would be actually better to open the document in read-only mode 
in this case,
-        // warn the user about this, and provide a button to drop the font(s) 
in order
-        // to switch to editing.
-        SAL_INFO( "vcl.fonts", "Ignoring embedded font that is not usable for 
editing" );
-        return false;
-    }
 
     if (bSubsetted)
     {
@@ -297,12 +314,20 @@ bool EmbeddedFontsManager::addEmbeddedFont( const 
uno::Reference< io::XInputStre
     if (fileUrl.isEmpty())
         return false;
 
-    // Register it, and increase its refcount in s_EmbeddedFonts
+    // Must not call isFontAvailableUnrestricted under unique_lock: it will 
deadlock
+    if (!sufficientFontRights && isFontAvailableUnrestricted(fontName, 
fileUrl))
+        sufficientFontRights = true;
+
+    // Register  it / increase its refcount in s_EmbeddedFonts
     {
         std::unique_lock lock(s_EmbeddedFontsMutex);
         auto& rData = s_EmbeddedFonts[fileUrl];
-        assert(rData.familyName.isEmpty() || rData.familyName == fontName);
-        rData.familyName = fontName;
+        if (rData.refcount == 0)
+        {
+            rData.familyName = fontName;
+            rData.isRestricted = !sufficientFontRights;
+        }
+        assert(rData.familyName == fontName);
         ++rData.refcount;
     }
 
@@ -327,18 +352,83 @@ namespace
     };
 }
 
-void EmbeddedFontsManager::activateFonts(std::vector<std::pair<OUString, 
OUString>>& fonts)
+void EmbeddedFontsManager::activateFonts(std::vector<std::pair<OUString, 
OUString>>& fonts,
+                                        bool silentlyAllowRestrictedFonts,
+                                        const 
uno::Reference<task::XInteractionHandler>& xHandler,
+                                        bool& activatedRestrictedFonts)
 {
+    activatedRestrictedFonts = false;
     if (fonts.empty())
         return;
     std::vector<std::pair<OUString, OUString>> temp;
 
     {
         std::unique_lock lock(s_EmbeddedFontsMutex);
-        // Only activate fonts that need activation.
+        // Handle restricted fonts
+        for (auto it1 = fonts.begin(); it1 != fonts.end();)
+        {
+            auto it2 = s_EmbeddedFonts.find(it1->second);
+            if (it2 == s_EmbeddedFonts.end())
+            {
+                SAL_WARN("vcl.fonts", "Trying to activate a font not in 
s_EmbeddedFonts");
+                it1 = fonts.erase(it1);
+                continue;
+            }
+            assert(it2->second.familyName == it1->first);
+
+            if (!silentlyAllowRestrictedFonts && it2->second.isRestricted)
+            {
+                temp.push_back(*it1);
+                it1 = fonts.erase(it1);
+                continue;
+            }
+
+            ++it1;
+        }
+    }
+
+    if (!temp.empty())
+    {
+        bool allowRestrictedFonts = false;
+        if (xHandler)
+        {
+            std::set<OUString> filteredFamilies; // families can repeat, e.g. 
for bold/italic
+            for (const auto& pair : temp)
+                filteredFamilies.insert(pair.first);
+            OUString fontlist;
+            for (const auto& family : filteredFamilies)
+                fontlist += "
" + family;
+            rtl::Reference pRequest(new comphelper::OInteractionRequest(
+                uno::Any(document::FontsDisallowEditingRequest({}, {}, 
fontlist))));
+            rtl::Reference pApprove(new comphelper::OInteractionApprove);
+            pRequest->addContinuation(pApprove);
+            pRequest->addContinuation(new comphelper::OInteractionDisapprove);
+            xHandler->handle(pRequest);
+            allowRestrictedFonts = pApprove->wasSelected();
+        }
+        if (allowRestrictedFonts)
+        {
+            activatedRestrictedFonts = true;
+            fonts.insert(fonts.end(), temp.begin(), temp.end());
+        }
+        else
+        {
+            releaseFonts(temp);
+        }
+        temp.clear();
+    }
+
+    {
+        std::unique_lock lock(s_EmbeddedFontsMutex);
+        // Only activate fonts that need activation. It goes after restricted 
fonts handling,
+        // because we must ask user about a second document embedding the same 
restricted font.
+        // We do not remove from fonts: the unlocking must happen only when 
the document is closed,
+        // so that necessary fonts are not unregistered.
         for (const auto& pair : fonts)
         {
             auto it = s_EmbeddedFonts.find(pair.second);
+            // At this point, we must find a match: neither releaseFonts 
above, nor other possible
+            // intermediate changes of s_EmbeddedFonts must not remove our 
locked entries
             assert(it != s_EmbeddedFonts.end());
             if (!it->second.isActivated)
             {
@@ -426,6 +516,14 @@ bool EmbeddedFontsManager::sufficientTTFRights( const 
void* data, tools::Long si
 OUString EmbeddedFontsManager::fontFileUrl( std::u16string_view familyName, 
FontFamily family, FontItalic italic,
     FontWeight weight, FontPitch pitch, FontRights rights )
 {
+    // Do not embed restricted fonts coming from another document. If a font 
is among embedded, and
+    // is restricted, it means that it isn't installed locally. See 
isFontAvailableUnrestricted.
+    for (const auto& pair : s_EmbeddedFonts)
+    {
+        if (pair.second.familyName == familyName && pair.second.isRestricted)
+            return {};
+    }
+
     OUString path = GetEmbeddedFontsRoot() + "fromsystem/";
     osl::Directory::createPath( path );
     OUString filename = OUString::Concat(familyName) + "_" + OUString::number( 
family ) + "_" + OUString::number( italic )
commit e8d0ab587b33d3a664583bb46c6eb0b4b59b11fe
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Mon Aug 11 13:57:24 2025 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Tue Aug 12 14:14:45 2025 +0200

    EmbeddedFontsHelper -> EmbeddedFontsManager
    
    It is not just a helper anymore, the rename reflects its function better.
    
    Change-Id: I11bf130eb34ba90841b550ab2a1fd1b3d9831b72
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189350
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins

diff --git a/bin/find-can-be-private-symbols.functions.results 
b/bin/find-can-be-private-symbols.functions.results
index 9de455631eca..5544a507a936 100644
--- a/bin/find-can-be-private-symbols.functions.results
+++ b/bin/find-can-be-private-symbols.functions.results
@@ -479,10 +479,10 @@ EditUndo::GetId() const
 EditUndo::GetViewShellId() const
 EditUndo::~EditUndo()
 EditUndoManager::SetEditEngine(EditEngine*)
-EmbeddedFontsHelper::activateFont(rtl::OUString const&, rtl::OUString const&)
-EmbeddedFontsHelper::clearTemporaryFontFiles()
-EmbeddedFontsHelper::fileUrlForTemporaryFont(rtl::OUString const&, 
std::basic_string_view<char16_t, std::char_traits<char16_t> >)
-EmbeddedFontsHelper::sufficientTTFRights(void const*, long, 
EmbeddedFontsHelper::FontRights)
+EmbeddedFontsManager::activateFont(rtl::OUString const&, rtl::OUString const&)
+EmbeddedFontsManager::clearTemporaryFontFiles()
+EmbeddedFontsManager::fileUrlForTemporaryFont(rtl::OUString const&, 
std::basic_string_view<char16_t, std::char_traits<char16_t> >)
+EmbeddedFontsManager::sufficientTTFRights(void const*, long, 
EmbeddedFontsManager::FontRights)
 EnhancedCustomShapeTypeNames::GetAccName(rtl::OUString const&)
 ErrorContext::GetParent()
 ErrorRegistry::ErrorRegistry()
diff --git a/bin/find-mergedlib-can-be-private-symbols.functions.results 
b/bin/find-mergedlib-can-be-private-symbols.functions.results
index 3b27c9c3e2d7..06d19bb4f6d2 100644
--- a/bin/find-mergedlib-can-be-private-symbols.functions.results
+++ b/bin/find-mergedlib-can-be-private-symbols.functions.results
@@ -653,10 +653,10 @@ EditView::InsertParaBreak()
 EditView::IsReadOnly() const
 EditView::SetReadOnly(bool)
 EditView::SetSelectionMode(EESelectionMode)
-EmbeddedFontsHelper::activateFont(rtl::OUString const&, rtl::OUString const&)
-EmbeddedFontsHelper::clearTemporaryFontFiles()
-EmbeddedFontsHelper::fileUrlForTemporaryFont(rtl::OUString const&, 
std::basic_string_view<char16_t, std::char_traits<char16_t> >)
-EmbeddedFontsHelper::sufficientTTFRights(void const*, long, 
EmbeddedFontsHelper::FontRights)
+EmbeddedFontsManager::activateFont(rtl::OUString const&, rtl::OUString const&)
+EmbeddedFontsManager::clearTemporaryFontFiles()
+EmbeddedFontsManager::fileUrlForTemporaryFont(rtl::OUString const&, 
std::basic_string_view<char16_t, std::char_traits<char16_t> >)
+EmbeddedFontsManager::sufficientTTFRights(void const*, long, 
EmbeddedFontsManager::FontRights)
 EnhancedCustomShape2d::ApplyGluePoints(SdrObject*)
 EnhancedCustomShape2d::CreateObject(bool)
 EnhancedCustomShape2d::GetEquation(unsigned short, int, int, int)
diff --git a/compilerplugins/clang/constantparam.booleans.results 
b/compilerplugins/clang/constantparam.booleans.results
index bf397b1c990f..be4ee4d9e51d 100644
--- a/compilerplugins/clang/constantparam.booleans.results
+++ b/compilerplugins/clang/constantparam.booleans.results
@@ -1750,9 +1750,9 @@ include/vcl/dibtools.hxx:40
     _Bool ReadDIB(class Bitmap &,class SvStream &,_Bool,_Bool)
     _Bool bMSOFormat
     0
-include/vcl/embeddedfontshelper.hxx:54
-    class rtl::OUString EmbeddedFontsHelper::fontFileUrl(class 
std::basic_string_view<char16_t>,enum FontFamily,enum FontItalic,enum 
FontWeight,enum FontPitch,enum EmbeddedFontsHelper::FontRights)
-    enum EmbeddedFontsHelper::FontRights rights
+include/vcl/embeddedfontsmanager.hxx:54
+    class rtl::OUString EmbeddedFontsManager::fontFileUrl(class 
std::basic_string_view<char16_t>,enum FontFamily,enum FontItalic,enum 
FontWeight,enum FontPitch,enum EmbeddedFontsManager::FontRights)
+    enum EmbeddedFontsManager::FontRights rights
     0
 include/vcl/fieldvalues.hxx:38
     _Bool TextToValue(const class rtl::OUString &,double &,long,unsigned 
short,const class LocaleDataWrapper &,enum FieldUnit)
diff --git a/include/vcl/embeddedfontshelper.hxx 
b/include/vcl/embeddedfontsmanager.hxx
similarity index 93%
rename from include/vcl/embeddedfontshelper.hxx
rename to include/vcl/embeddedfontsmanager.hxx
index fa4129976040..798de1f310fb 100644
--- a/include/vcl/embeddedfontshelper.hxx
+++ b/include/vcl/embeddedfontsmanager.hxx
@@ -7,8 +7,7 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-#ifndef INCLUDED_VCL_EMBEDDEDFONTSHELPER_HXX
-#define INCLUDED_VCL_EMBEDDEDFONTSHELPER_HXX
+#pragma once
 
 #include <vcl/dllapi.h>
 
@@ -24,7 +23,7 @@ namespace com::sun::star::io { class XInputStream; }
 namespace com::sun::star::uno { template <typename > class Reference; }
 
 /** Helper functions for handling embedded fonts in documents. */
-class VCL_DLLPUBLIC EmbeddedFontsHelper
+class VCL_DLLPUBLIC EmbeddedFontsManager
 {
 private:
     css::uno::Reference<css::frame::XModel> m_xDocumentModel;
@@ -96,10 +95,8 @@ public:
 
     static void releaseFonts(const std::vector<std::pair<OUString, OUString>>& 
fonts);
 
-    EmbeddedFontsHelper(const css::uno::Reference<css::frame::XModel>& xModel);
-    ~EmbeddedFontsHelper() COVERITY_NOEXCEPT_FALSE;
+    EmbeddedFontsManager(const css::uno::Reference<css::frame::XModel>& 
xModel);
+    ~EmbeddedFontsManager() COVERITY_NOEXCEPT_FALSE;
 };
 
-#endif
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/xmloff/xmlimp.hxx b/include/xmloff/xmlimp.hxx
index 11cd7c570737..352c61224f74 100644
--- a/include/xmloff/xmlimp.hxx
+++ b/include/xmloff/xmlimp.hxx
@@ -76,7 +76,7 @@ namespace xmloff {
 namespace xmloff::token {
     class FastTokenHandler;
 }
-class EmbeddedFontsHelper;
+class EmbeddedFontsManager;
 class ProgressBarHelper;
 class SvXMLImport_Impl;
 class SvXMLUnitConverter;
@@ -246,8 +246,8 @@ private:
     css::uno::Reference< css::task::XStatusIndicator > mxStatusIndicator;
 
     // tdf#69060 & tdf#137643 import embedded fonts and activate them in a
-    // batch in EmbeddedFontsHelper's dtor
-    std::unique_ptr<EmbeddedFontsHelper, 
o3tl::default_delete<EmbeddedFontsHelper>> mxEmbeddedFontHelper;
+    // batch in EmbeddedFontsManager's dtor
+    std::unique_ptr<EmbeddedFontsManager, 
o3tl::default_delete<EmbeddedFontsManager>> mxEmbeddedFontManager;
 
 protected:
     bool                        mbIsFormsSupported;
@@ -582,7 +582,7 @@ public:
     */
     bool embeddedFontAlreadyProcessed( const OUString& url );
 
-    // see EmbeddedFontsHelper::addEmbeddedFont
+    // see EmbeddedFontsManager::addEmbeddedFont
     bool addEmbeddedFont( const css::uno::Reference< css::io::XInputStream >& 
stream,
         const OUString& fontName, std::u16string_view extra,
         std::vector< unsigned char > const & key, bool eot);
diff --git a/ios/UnitTest/UnitTest.xcodeproj/project.pbxproj 
b/ios/UnitTest/UnitTest.xcodeproj/project.pbxproj
index 940d62120390..ce48076bd696 100644
--- a/ios/UnitTest/UnitTest.xcodeproj/project.pbxproj
+++ b/ios/UnitTest/UnitTest.xcodeproj/project.pbxproj
@@ -137,7 +137,7 @@
                BEA20DDF216797C10032F67B /* pdffontcache.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = 
pdffontcache.cxx; path = ../../vcl/source/gdi/pdffontcache.cxx; sourceTree = 
"<group>"; };
                BEA20DE0216797C10032F67B /* textlayout.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = 
textlayout.cxx; path = ../../vcl/source/gdi/textlayout.cxx; sourceTree = 
"<group>"; };
                BEA20DE1216797C10032F67B /* virdev.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = virdev.cxx; 
path = ../../vcl/source/gdi/virdev.cxx; sourceTree = "<group>"; };
-               BEA20DE2216797C10032F67B /* embeddedfontshelper.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = 
embeddedfontshelper.cxx; path = ../../vcl/source/gdi/embeddedfontshelper.cxx; 
sourceTree = "<group>"; };
+               BEA20DE2216797C10032F67B /* embeddedfontsmanager.cxx */ = {isa 
= PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = 
embeddedfontsmanager.cxx; path = ../../vcl/source/gdi/embeddedfontsmanager.cxx; 
sourceTree = "<group>"; };
                BEA20DE3216797C10032F67B /* salgdiimpl.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = 
salgdiimpl.cxx; path = ../../vcl/source/gdi/salgdiimpl.cxx; sourceTree = 
"<group>"; };
                BEA20DE4216797C10032F67B /* gfxlink.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = gfxlink.cxx; 
path = ../../vcl/source/gdi/gfxlink.cxx; sourceTree = "<group>"; };
                BEA20DE5216797C10032F67B /* alpha.cxx */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = alpha.cxx; 
path = ../../vcl/source/gdi/alpha.cxx; sourceTree = "<group>"; };
@@ -399,7 +399,7 @@
                                BEA20DD7216797C10032F67B /* configsettings.cxx 
*/,
                                BEA20DD1216797C10032F67B /* cvtgrf.cxx */,
                                BEA20DF8216797C20032F67B /* dibtools.cxx */,
-                               BEA20DE2216797C10032F67B /* 
embeddedfontshelper.cxx */,
+                               BEA20DE2216797C10032F67B /* 
embeddedfontsmanager.cxx */,
                                BEA20DD0216797C00032F67B /* extoutdevdata.cxx 
*/,
                                BEA20DD3216797C10032F67B /* 
gdimetafiletools.cxx */,
                                BEA20DDD216797C10032F67B /* gdimtf.cxx */,
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index 75d23c2ae6d4..484e2bcafea3 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -118,7 +118,7 @@
 #include <unotools/fontdefs.hxx>
 #include <vcl/cvtgrf.hxx>
 #include <vcl/svapp.hxx>
-#include <vcl/embeddedfontshelper.hxx>
+#include <vcl/embeddedfontsmanager.hxx>
 #include <rtl/strbuf.hxx>
 #include <filter/msfilter/escherex.hxx>
 #include <filter/msfilter/util.hxx>
@@ -2837,7 +2837,7 @@ void DrawingML::WriteRunProperties( const Reference< 
XPropertySet >& rRun, bool
 
         mAny >>= usTypeface;
 
-        if (!mbEmbedFonts || EmbeddedFontsHelper::isCommonFont(usTypeface))
+        if (!mbEmbedFonts || EmbeddedFontsManager::isCommonFont(usTypeface))
         {
             OUString aSubstName( GetSubsFontName( usTypeface, 
SubsFontFlags::ONLYONE | SubsFontFlags::MS ) );
             if (!aSubstName.isEmpty())
@@ -2862,7 +2862,7 @@ void DrawingML::WriteRunProperties( const Reference< 
XPropertySet >& rRun, bool
         OUString usTypeface;
 
         mAny >>= usTypeface;
-        if (!mbEmbedFonts || EmbeddedFontsHelper::isCommonFont(usTypeface))
+        if (!mbEmbedFonts || EmbeddedFontsManager::isCommonFont(usTypeface))
         {
             OUString aSubstName( GetSubsFontName( usTypeface, 
SubsFontFlags::ONLYONE | SubsFontFlags::MS ) );
             if (!aSubstName.isEmpty())
diff --git a/oox/source/ppt/EmbeddedFontListContext.cxx 
b/oox/source/ppt/EmbeddedFontListContext.cxx
index 731048236b10..09d4a3735e6b 100644
--- a/oox/source/ppt/EmbeddedFontListContext.cxx
+++ b/oox/source/ppt/EmbeddedFontListContext.cxx
@@ -24,7 +24,7 @@ EmbeddedFontListContext::EmbeddedFontListContext(
     FragmentHandler2 const& rParent, bool bEmbedTrueType,
     css::uno::Reference<css::beans::XPropertySet> const& rxDocSettings)
     : FragmentHandler2(rParent)
-    , maEmbeddedFontHelper(getFilter().getModel())
+    , maEmbeddedFontManager(getFilter().getModel())
     , mbEmbedTrueType(bEmbedTrueType)
     , mxDocSettings(rxDocSettings)
 {
@@ -95,32 +95,32 @@ void EmbeddedFontListContext::onEndElement()
     {
         OUString aFragmentPath = 
getFragmentPathFromRelId(moCurrentFont->aRegularID);
         uno::Reference<io::XInputStream> xInputStream = 
getFilter().openInputStream(aFragmentPath);
-        maEmbeddedFontHelper.addEmbeddedFont(xInputStream, 
moCurrentFont->aTypeface, u"",
-                                             std::vector<unsigned char>(), 
true, false);
+        maEmbeddedFontManager.addEmbeddedFont(xInputStream, 
moCurrentFont->aTypeface, u"",
+                                              std::vector<unsigned char>(), 
true, false);
     }
 
     if (!moCurrentFont->aBoldID.isEmpty())
     {
         OUString aFragmentPath = 
getFragmentPathFromRelId(moCurrentFont->aBoldID);
         uno::Reference<io::XInputStream> xInputStream = 
getFilter().openInputStream(aFragmentPath);
-        maEmbeddedFontHelper.addEmbeddedFont(xInputStream, 
moCurrentFont->aTypeface, u"b",
-                                             std::vector<unsigned char>(), 
true, false);
+        maEmbeddedFontManager.addEmbeddedFont(xInputStream, 
moCurrentFont->aTypeface, u"b",
+                                              std::vector<unsigned char>(), 
true, false);
     }
 
     if (!moCurrentFont->aItalicID.isEmpty())
     {
         OUString aFragmentPath = 
getFragmentPathFromRelId(moCurrentFont->aItalicID);
         uno::Reference<io::XInputStream> xInputStream = 
getFilter().openInputStream(aFragmentPath);
-        maEmbeddedFontHelper.addEmbeddedFont(xInputStream, 
moCurrentFont->aTypeface, u"i",
-                                             std::vector<unsigned char>(), 
true, false);
+        maEmbeddedFontManager.addEmbeddedFont(xInputStream, 
moCurrentFont->aTypeface, u"i",
+                                              std::vector<unsigned char>(), 
true, false);
     }
 
     if (!moCurrentFont->aBoldItalicID.isEmpty())
     {
         OUString aFragmentPath = 
getFragmentPathFromRelId(moCurrentFont->aBoldItalicID);
         uno::Reference<io::XInputStream> xInputStream = 
getFilter().openInputStream(aFragmentPath);
-        maEmbeddedFontHelper.addEmbeddedFont(xInputStream, 
moCurrentFont->aTypeface, u"bi",
-                                             std::vector<unsigned char>(), 
true, false);
+        maEmbeddedFontManager.addEmbeddedFont(xInputStream, 
moCurrentFont->aTypeface, u"bi",
+                                              std::vector<unsigned char>(), 
true, false);
     }
 
     moCurrentFont = std::nullopt;
diff --git a/oox/source/ppt/EmbeddedFontListContext.hxx 
b/oox/source/ppt/EmbeddedFontListContext.hxx
index 4c9dd4075fe6..0601337e716a 100644
--- a/oox/source/ppt/EmbeddedFontListContext.hxx
+++ b/oox/source/ppt/EmbeddedFontListContext.hxx
@@ -14,7 +14,7 @@
 #include <com/sun/star/beans/XPropertySet.hpp>
 #include <oox/core/contexthandler.hxx>
 #include <oox/core/fragmenthandler2.hxx>
-#include <vcl/embeddedfontshelper.hxx>
+#include <vcl/embeddedfontsmanager.hxx>
 #include <rtl/ustring.hxx>
 #include <sal/types.h>
 #include <optional>
@@ -44,7 +44,7 @@ struct EmbeddedFont
 class EmbeddedFontListContext final : public ::oox::core::FragmentHandler2
 {
     std::optional<EmbeddedFont> moCurrentFont;
-    EmbeddedFontsHelper maEmbeddedFontHelper;
+    EmbeddedFontsManager maEmbeddedFontManager;
     bool mbEmbedTrueType = false;
     css::uno::Reference<css::beans::XPropertySet> mxDocSettings;
 
diff --git a/sd/qa/unit/FontEmbeddingTest.cxx b/sd/qa/unit/FontEmbeddingTest.cxx
index 75a12179fa8b..1b3169a6e5d9 100644
--- a/sd/qa/unit/FontEmbeddingTest.cxx
+++ b/sd/qa/unit/FontEmbeddingTest.cxx
@@ -11,7 +11,7 @@
 #include <test/unoapi_test.hxx>
 #include <config_eot.h>
 #include <config_fonts.h>
-#include <vcl/embeddedfontshelper.hxx>
+#include <vcl/embeddedfontsmanager.hxx>
 
 using namespace css;
 
@@ -38,9 +38,9 @@ CPPUNIT_TEST_FIXTURE(FontEmbeddingTest, 
testRoundtripEmbeddedFontsPPTX)
 
     // Expect the font to not be available
     {
-        OUString aUrl = EmbeddedFontsHelper::fontFileUrl(
+        OUString aUrl = EmbeddedFontsManager::fontFileUrl(
             u"Boldonse", FAMILY_ROMAN, ITALIC_NONE, WEIGHT_NORMAL, 
PITCH_VARIABLE,
-            EmbeddedFontsHelper::FontRights::ViewingAllowed);
+            EmbeddedFontsManager::FontRights::ViewingAllowed);
         CPPUNIT_ASSERT(aUrl.isEmpty());
     }
 
@@ -51,9 +51,9 @@ CPPUNIT_TEST_FIXTURE(FontEmbeddingTest, 
testRoundtripEmbeddedFontsPPTX)
 #if !defined(MACOSX)
     // Expect the font to be available now, if we imported the embedded fonts 
correctly
     {
-        OUString aUrl = EmbeddedFontsHelper::fontFileUrl(
+        OUString aUrl = EmbeddedFontsManager::fontFileUrl(
             u"Boldonse", FAMILY_ROMAN, ITALIC_NONE, WEIGHT_NORMAL, 
PITCH_VARIABLE,
-            EmbeddedFontsHelper::FontRights::ViewingAllowed);
+            EmbeddedFontsManager::FontRights::ViewingAllowed);
 
         CPPUNIT_ASSERT(!aUrl.isEmpty());
     }
diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx 
b/sd/source/filter/eppt/pptx-epptooxml.cxx
index 5bb2cc80ae44..30c08cf10c0c 100644
--- a/sd/source/filter/eppt/pptx-epptooxml.cxx
+++ b/sd/source/filter/eppt/pptx-epptooxml.cxx
@@ -69,7 +69,7 @@
 #include <com/sun/star/presentation/XPresentationSupplier.hpp>
 #include <comphelper/diagnose_ex.hxx>
 #include <comphelper/hash.hxx>
-#include <vcl/embeddedfontshelper.hxx>
+#include <vcl/embeddedfontsmanager.hxx>
 
 #include <oox/export/utils.hxx>
 #include <oox/export/ThemeExport.hxx>
@@ -725,7 +725,7 @@ void PowerPointExport::WriteEmbeddedFontList()
         aAnySeq[nSeqIndex++] >>= ePitch;
         aAnySeq[nSeqIndex++] >>= eCharSet;
 
-        if (EmbeddedFontsHelper::isCommonFont(sFamilyName))
+        if (EmbeddedFontsManager::isCommonFont(sFamilyName))
             continue;
 
         if (mbEmbedUsedOnly && !aUsedFonts.contains(sFamilyName))
@@ -748,9 +748,9 @@ void PowerPointExport::WriteEmbeddedFontList()
 
         for (auto [eItalic, eWeight] : aFontVariantCombinations)
         {
-            OUString sFontUrl = EmbeddedFontsHelper::fontFileUrl(
+            OUString sFontUrl = EmbeddedFontsManager::fontFileUrl(
                                     sFamilyName, FontFamily(eFamily), eItalic, 
eWeight, FontPitch(ePitch),
-                                    
EmbeddedFontsHelper::FontRights::ViewingAllowed);
+                                    
EmbeddedFontsManager::FontRights::ViewingAllowed);
 
             if (sFontUrl.isEmpty())
                 continue;
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index 164c064cdaf8..85e1ce3dd9db 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -127,7 +127,7 @@
 #include <openflag.hxx>
 #include <officecfg/Office/Common.hxx>
 #include <comphelper/propertysequence.hxx>
-#include <vcl/embeddedfontshelper.hxx>
+#include <vcl/embeddedfontsmanager.hxx>
 #include <vcl/weld.hxx>
 #include <vcl/svapp.hxx>
 #include <comphelper/diagnose_ex.hxx>
@@ -3762,7 +3762,7 @@ void SfxMedium::ReleaseEmbeddedFonts()
     toRelease.insert(toRelease.end(), 
pImpl->m_aEmbeddedFontsToActivate.begin(),
                      pImpl->m_aEmbeddedFontsToActivate.end());
     pImpl->m_aEmbeddedFontsToActivate.clear();
-    EmbeddedFontsHelper::releaseFonts(toRelease);
+    EmbeddedFontsManager::releaseFonts(toRelease);
 }
 
 const OUString& SfxMedium::GetName() const
@@ -4036,7 +4036,7 @@ void SfxMedium::AddEmbeddedFonts(
 
 void SfxMedium::activateEmbeddedFonts()
 {
-    EmbeddedFontsHelper::activateFonts(pImpl->m_aEmbeddedFontsToActivate);
+    EmbeddedFontsManager::activateFonts(pImpl->m_aEmbeddedFontsToActivate);
     pImpl->m_aEmbeddedFonts.insert(pImpl->m_aEmbeddedFonts.end(),
                                    pImpl->m_aEmbeddedFontsToActivate.begin(),
                                    pImpl->m_aEmbeddedFontsToActivate.end());
diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist
index 668e0af6f535..69c10ce88785 100644
--- a/solenv/clang-format/excludelist
+++ b/solenv/clang-format/excludelist
@@ -6144,7 +6144,7 @@ include/vcl/dndhelp.hxx
 include/vcl/dndlistenercontainer.hxx
 include/vcl/dockingarea.hxx
 include/vcl/dockwin.hxx
-include/vcl/embeddedfontshelper.hxx
+include/vcl/embeddedfontsmanager.hxx
 include/vcl/errinf.hxx
 include/vcl/event.hxx
 include/vcl/evntpost.hxx
@@ -14669,7 +14669,7 @@ vcl/source/fontsubset/ttcr.cxx
 vcl/source/fontsubset/ttcr.hxx
 vcl/source/gdi/CommonSalLayout.cxx
 vcl/source/gdi/cvtgrf.cxx
-vcl/source/gdi/embeddedfontshelper.cxx
+vcl/source/gdi/embeddedfontsmanager.cxx
 vcl/source/gdi/formpdfexport.cxx
 vcl/source/gdi/gdimetafiletools.cxx
 vcl/source/gdi/gdimtf.cxx
diff --git a/sw/qa/writerfilter/dmapper/FontTable.cxx 
b/sw/qa/writerfilter/dmapper/FontTable.cxx
index 2d5a80ca0476..a72d12c5e703 100644
--- a/sw/qa/writerfilter/dmapper/FontTable.cxx
+++ b/sw/qa/writerfilter/dmapper/FontTable.cxx
@@ -13,7 +13,7 @@
 #include <com/sun/star/beans/XPropertySet.hpp>
 #include <com/sun/star/text/XTextDocument.hpp>
 
-#include <vcl/embeddedfontshelper.hxx>
+#include <vcl/embeddedfontsmanager.hxx>
 
 using namespace com::sun::star;
 
@@ -35,9 +35,9 @@ CPPUNIT_TEST_FIXTURE(Test, testSubsettedEmbeddedFont)
     loadFromFile(u"subsetted-embedded-font.docx");
 
     // When checking if the font is available:
-    OUString aUrl = EmbeddedFontsHelper::fontFileUrl(
+    OUString aUrl = EmbeddedFontsManager::fontFileUrl(
         u"IBM Plex Serif Light", FAMILY_ROMAN, ITALIC_NONE, WEIGHT_NORMAL, 
PITCH_VARIABLE,
-        EmbeddedFontsHelper::FontRights::ViewingAllowed);
+        EmbeddedFontsManager::FontRights::ViewingAllowed);
 
     // Then make sure the subsetted font is not available, given that the 
newly inserted characters
     // during editing may be missing from the subsetted font:
@@ -52,9 +52,9 @@ CPPUNIT_TEST_FIXTURE(Test, testSubsettedFullEmbeddedFont)
     loadFromFile(u"subsetted-full-embedded-font.docx");
 
     // When checking if the font is available:
-    OUString aUrl = EmbeddedFontsHelper::fontFileUrl(
+    OUString aUrl = EmbeddedFontsManager::fontFileUrl(
         u"IBM Plex Serif Light", FAMILY_ROMAN, ITALIC_NONE, WEIGHT_NORMAL, 
PITCH_VARIABLE,
-        EmbeddedFontsHelper::FontRights::ViewingAllowed);
+        EmbeddedFontsManager::FontRights::ViewingAllowed);
 
     // Then make sure the subsetted font is available, given that it has the 
reasonable amount of
     // glyphs:
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 5ffe90b54bdf..c4e1c4a7db81 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -142,7 +142,7 @@
 #include <o3tl/unit_conversion.hxx>
 #include <osl/file.hxx>
 #include <utility>
-#include <vcl/embeddedfontshelper.hxx>
+#include <vcl/embeddedfontsmanager.hxx>
 
 #include <com/sun/star/i18n/ScriptType.hpp>
 #include <com/sun/star/i18n/XBreakIterator.hpp>
@@ -7550,7 +7550,7 @@ void DocxAttributeOutput::EmbedFont( std::u16string_view 
name, FontFamily family
 {
     if( !m_rExport.m_rDoc.getIDocumentSettingAccess().get( 
DocumentSettingId::EMBED_FONTS ))
         return; // no font embedding with this document
-    if (EmbeddedFontsHelper::isCommonFont(name))
+    if (EmbeddedFontsManager::isCommonFont(name))
         return;
 
     bool foundFont
@@ -7575,8 +7575,8 @@ bool 
DocxAttributeOutput::EmbedFontStyle(std::u16string_view name, int tag, Font
 {
     // 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 fontUrl = EmbeddedFontsHelper::fontFileUrl( name, family, italic, 
weight, pitch,
-        EmbeddedFontsHelper::FontRights::ViewingAllowed );
+    OUString fontUrl = EmbeddedFontsManager::fontFileUrl( name, family, 
italic, weight, pitch,
+        EmbeddedFontsManager::FontRights::ViewingAllowed );
     if( fontUrl.isEmpty())
         return false;
     // TODO IDocumentSettingAccess::EMBED_SYSTEM_FONTS
diff --git a/sw/source/writerfilter/dmapper/FontTable.cxx 
b/sw/source/writerfilter/dmapper/FontTable.cxx
index 767031b9c13e..602a31bcb93b 100644
--- a/sw/source/writerfilter/dmapper/FontTable.cxx
+++ b/sw/source/writerfilter/dmapper/FontTable.cxx
@@ -255,9 +255,9 @@ void FontTable::addEmbeddedFont(const 
css::uno::Reference<css::io::XInputStream>
                                 std::vector<unsigned char> const & key,
                                 bool bSubsetted)
 {
-    if (!m_xEmbeddedFontHelper)
-        m_xEmbeddedFontHelper.reset(new EmbeddedFontsHelper(m_xModel));
-    m_xEmbeddedFontHelper->addEmbeddedFont(stream, fontName, extra, key,
+    if (!m_xEmbeddedFontManager)
+        m_xEmbeddedFontManager.reset(new EmbeddedFontsManager(m_xModel));
+    m_xEmbeddedFontManager->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 56b949fd04c1..084116f40440 100644
--- a/sw/source/writerfilter/dmapper/FontTable.hxx
+++ b/sw/source/writerfilter/dmapper/FontTable.hxx
@@ -25,7 +25,7 @@
 #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 <vcl/embeddedfontsmanager.hxx>
 #include <o3tl/deleter.hxx>
 
 namespace rtl { template<class reference_type> class Reference; }
@@ -51,7 +51,7 @@ 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::unique_ptr<EmbeddedFontsManager, 
o3tl::default_delete<EmbeddedFontsManager>> m_xEmbeddedFontManager;
     std::vector< FontEntry::Pointer_t > m_aFontEntries;
     FontEntry::Pointer_t m_pCurrentEntry;
     bool m_bReadOnly;
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index b665e1c65728..4c33f3a36ca9 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -322,7 +322,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
     vcl/source/treelist/uiobject \
     vcl/source/gdi/formpdfexport \
     vcl/source/gdi/cvtgrf \
-    vcl/source/gdi/embeddedfontshelper \
+    vcl/source/gdi/embeddedfontsmanager \
     vcl/source/gdi/FileDefinitionWidgetDraw \
     vcl/source/gdi/WidgetDefinitionReader \
     vcl/source/gdi/WidgetDefinition \
diff --git a/vcl/source/app/svmain.cxx b/vcl/source/app/svmain.cxx
index 79d03ccc2e75..56c30312f3e3 100644
--- a/vcl/source/app/svmain.cxx
+++ b/vcl/source/app/svmain.cxx
@@ -46,7 +46,7 @@
 #include <vcl/settings.hxx>
 #include <vcl/toolkit/unowrap.hxx>
 #include <tools/lazydelete.hxx>
-#include <vcl/embeddedfontshelper.hxx>
+#include <vcl/embeddedfontsmanager.hxx>
 #include <vcl/toolkit/dialog.hxx>
 #include <vcl/menu.hxx>
 #include <vcl/virdev.hxx>
@@ -285,7 +285,7 @@ bool InitVCL()
     if( pExceptionHandler != nullptr )
         return false;
 
-    EmbeddedFontsHelper::clearTemporaryFontFiles();
+    EmbeddedFontsManager::clearTemporaryFontFiles();
 
     if( !ImplGetSVData()->mpApp )
     {
@@ -610,7 +610,7 @@ void DeInitVCL()
         pOwnSvApp = nullptr;
     }
 
-    EmbeddedFontsHelper::clearTemporaryFontFiles();
+    EmbeddedFontsManager::clearTemporaryFontFiles();
 }
 
 namespace {
diff --git a/vcl/source/gdi/embeddedfontshelper.cxx 
b/vcl/source/gdi/embeddedfontsmanager.cxx
similarity index 95%
rename from vcl/source/gdi/embeddedfontshelper.cxx
rename to vcl/source/gdi/embeddedfontsmanager.cxx
index d21fa500e4e6..c9a10c2b2365 100644
--- a/vcl/source/gdi/embeddedfontshelper.cxx
+++ b/vcl/source/gdi/embeddedfontsmanager.cxx
@@ -23,7 +23,7 @@
 #include <rtl/uri.hxx>
 #include <sal/log.hxx>
 #include <vcl/svapp.hxx>
-#include <vcl/embeddedfontshelper.hxx>
+#include <vcl/embeddedfontsmanager.hxx>
 #include <com/sun/star/io/XInputStream.hpp>
 #include <comphelper/diagnose_ex.hxx>
 #include <comphelper/propertyvalue.hxx>
@@ -167,12 +167,12 @@ OUString writeFontBytesToFile(const std::vector<char>& 
bytes, std::u16string_vie
 }
 }
 
-EmbeddedFontsHelper::EmbeddedFontsHelper(const uno::Reference<frame::XModel>& 
xModel)
+EmbeddedFontsManager::EmbeddedFontsManager(const 
uno::Reference<frame::XModel>& xModel)
     : m_xDocumentModel(xModel)
 {
 }
 
-EmbeddedFontsHelper::~EmbeddedFontsHelper() COVERITY_NOEXCEPT_FALSE
+EmbeddedFontsManager::~EmbeddedFontsManager() COVERITY_NOEXCEPT_FALSE
 {
     if (m_aAccumulatedFonts.empty())
         return;
@@ -200,14 +200,14 @@ EmbeddedFontsHelper::~EmbeddedFontsHelper() 
COVERITY_NOEXCEPT_FALSE
     activateFonts(m_aAccumulatedFonts);
 }
 
-void EmbeddedFontsHelper::clearTemporaryFontFiles()
+void EmbeddedFontsManager::clearTemporaryFontFiles()
 {
     const OUString& path = GetEmbeddedFontsRoot();
     clearDir( path + "fromdocs/" );
     clearDir( path + "fromsystem/" );
 }
 
-bool EmbeddedFontsHelper::addEmbeddedFont( const uno::Reference< 
io::XInputStream >& stream, const OUString& fontName,
+bool EmbeddedFontsManager::addEmbeddedFont( const uno::Reference< 
io::XInputStream >& stream, const OUString& fontName,
     std::u16string_view extra, std::vector< unsigned char > const & key, bool 
eot,
     bool bSubsetted )
 {
@@ -327,7 +327,7 @@ namespace
     };
 }
 
-void EmbeddedFontsHelper::activateFonts(std::vector<std::pair<OUString, 
OUString>>& fonts)
+void EmbeddedFontsManager::activateFonts(std::vector<std::pair<OUString, 
OUString>>& fonts)
 {
     if (fonts.empty())
         return;
@@ -357,7 +357,7 @@ void 
EmbeddedFontsHelper::activateFonts(std::vector<std::pair<OUString, OUString
         pDevice->AddTempDevFont(fileUrl, fontName);
 }
 
-void EmbeddedFontsHelper::releaseFonts(const std::vector<std::pair<OUString, 
OUString>>& fonts)
+void EmbeddedFontsManager::releaseFonts(const std::vector<std::pair<OUString, 
OUString>>& fonts)
 {
     std::vector<std::pair<OUString, OUString>> unregister;
     {
@@ -400,7 +400,7 @@ void EmbeddedFontsHelper::releaseFonts(const 
std::vector<std::pair<OUString, OUS
 // to have a different meaning (guessing from code, IsSubsettable() might
 // possibly mean it's ttf, while IsEmbeddable() might mean it's type1).
 // So just try to open the data as ttf and see.
-bool EmbeddedFontsHelper::sufficientTTFRights( const void* data, tools::Long 
size, FontRights rights )
+bool EmbeddedFontsManager::sufficientTTFRights( const void* data, tools::Long 
size, FontRights rights )
 {
     TrueTypeFont* font;
     if( OpenTTFontBuffer( data, size, 0 /*TODO*/, &font ) == SFErrCodes::Ok )
@@ -423,7 +423,7 @@ bool EmbeddedFontsHelper::sufficientTTFRights( const void* 
data, tools::Long siz
     return true; // no known restriction
 }
 
-OUString EmbeddedFontsHelper::fontFileUrl( std::u16string_view familyName, 
FontFamily family, FontItalic italic,
+OUString EmbeddedFontsManager::fontFileUrl( std::u16string_view familyName, 
FontFamily family, FontItalic italic,
     FontWeight weight, FontPitch pitch, FontRights rights )
 {
     OUString path = GetEmbeddedFontsRoot() + "fromsystem/";
@@ -542,7 +542,7 @@ OUString EmbeddedFontsHelper::fontFileUrl( 
std::u16string_view familyName, FontF
     return ok ? url : u""_ustr;
 }
 
-bool EmbeddedFontsHelper::isCommonFont(std::u16string_view aFontName)
+bool EmbeddedFontsManager::isCommonFont(std::u16string_view aFontName)
 {
     static constexpr auto aCommonFontsList = 
frozen::make_unordered_set<std::u16string_view>({
         // LO Common
diff --git a/xmloff/source/core/xmlimp.cxx b/xmloff/source/core/xmlimp.cxx
index a4704f9cdcd2..3e1c26fced76 100644
--- a/xmloff/source/core/xmlimp.cxx
+++ b/xmloff/source/core/xmlimp.cxx
@@ -27,7 +27,7 @@
 #include <com/sun/star/beans/XPropertySetInfo.hpp>
 #include <tools/urlobj.hxx>
 #include <utility>
-#include <vcl/embeddedfontshelper.hxx>
+#include <vcl/embeddedfontsmanager.hxx>
 #include <vcl/graph.hxx>
 #include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
 #include <xmloff/namespacemap.hxx>
@@ -503,9 +503,9 @@ bool SvXMLImport::addEmbeddedFont(const 
css::uno::Reference< css::io::XInputStre
                                   const OUString& fontName, 
std::u16string_view extra,
                                   std::vector<unsigned char> const & key, bool 
eot)
 {
-    if (!mxEmbeddedFontHelper)
-        mxEmbeddedFontHelper.reset(new EmbeddedFontsHelper(mxModel));
-    return mxEmbeddedFontHelper->addEmbeddedFont(stream, fontName, extra, key, 
eot);
+    if (!mxEmbeddedFontManager)
+        mxEmbeddedFontManager.reset(new EmbeddedFontsManager(mxModel));
+    return mxEmbeddedFontManager->addEmbeddedFont(stream, fontName, extra, 
key, eot);
 }
 
 namespace
diff --git a/xmloff/source/style/XMLFontAutoStylePool.cxx 
b/xmloff/source/style/XMLFontAutoStylePool.cxx
index 60036d1342ea..138ac56465ff 100644
--- a/xmloff/source/style/XMLFontAutoStylePool.cxx
+++ b/xmloff/source/style/XMLFontAutoStylePool.cxx
@@ -26,7 +26,7 @@
 #include "fonthdl.hxx"
 #include <xmloff/xmlexp.hxx>
 #include <xmloff/XMLFontAutoStylePool.hxx>
-#include <vcl/embeddedfontshelper.hxx>
+#include <vcl/embeddedfontsmanager.hxx>
 #include <osl/file.hxx>
 #include <sal/log.hxx>
 #include <comphelper/diagnose_ex.hxx>
@@ -428,7 +428,7 @@ void SvXMLExport::exportFonts(const 
std::vector<XMLFontAutoStylePoolEntry_Impl*>
         // When embedding is requested, and embedded only is not set or font 
is used
         if (bEmbedFonts && (!bEmbedUsedOnly || 
aUsedFontNames.contains(pEntry->GetFamilyName())))
         {
-            if (EmbeddedFontsHelper::isCommonFont(pEntry->GetFamilyName()))
+            if (EmbeddedFontsManager::isCommonFont(pEntry->GetFamilyName()))
                 continue;
 
             const bool bExportFlat(getExportFlags() & 
SvXMLExportFlags::EMBEDDED);
@@ -448,9 +448,9 @@ void SvXMLExport::exportFonts(const 
std::vector<XMLFontAutoStylePoolEntry_Impl*>
                 {
                     // 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(
+                    OUString sFileUrl = EmbeddedFontsManager::fontFileUrl(
                         pEntry->GetFamilyName(), pEntry->GetFamily(), 
fontItalic, fontWeight,
-                        pEntry->GetPitch(), 
EmbeddedFontsHelper::FontRights::ViewingAllowed);
+                        pEntry->GetPitch(), 
EmbeddedFontsManager::FontRights::ViewingAllowed);
                     if (sFileUrl.isEmpty())
                         continue;
 
commit c77a53433d9cfb0f03a3ebd04707ddccb11a3cca
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Sun Aug 10 23:21:41 2025 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Tue Aug 12 14:14:38 2025 +0200

    Keep track of documents' embedded fonts, and unregister them on unload
    
    First, not releasing the documents could degrade performance in some
    long-running instances.
    
    Also, this will help when we implement support for restricted embedded
    fonts, which must not show in font lists, when the document was closed.
    
    EmbeddedFontsHelper now keeps track of all the embedded fonts, using a
    static map s_EmbeddedFonts; each font has a refcount, and unregistered
    only when its refcount is zero. SfxMedium keeps track of its own fonts;
    and in its dtor, it calls EmbeddedFontsHelper::releaseFonts.
    
    Change-Id: I0afe971a785c4709cc54a3fab98953db96dbd05f
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189320
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins

diff --git a/include/sfx2/docfile.hxx b/include/sfx2/docfile.hxx
index 7e5b5aa4b8c6..e15983b65a6c 100644
--- a/include/sfx2/docfile.hxx
+++ b/include/sfx2/docfile.hxx
@@ -31,12 +31,12 @@
 #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; }
+namespace com::sun::star::beans { struct StringPair; }
 namespace com::sun::star::embed { class XStorage; }
 namespace com::sun::star::graphic { class XGraphic; }
 namespace com::sun::star::io { class XInputStream; }
@@ -105,6 +105,8 @@ public:
     bool CheckCanGetLockfile() const;
     void SetOriginallyReadOnly(bool val);
     void AddEmbeddedFonts(const css::uno::Sequence<css::beans::StringPair>& 
fonts);
+    // Transfers the embedded font list to another medium (passing ownership)
+    void TransferEmbeddedFontsTo(SfxMedium& target);
     void AddToCheckEditableWorkerList();
     void SetWorkerReloadEvent(ImplSVEvent* pEvent);
     ImplSVEvent* GetWorkerReloadEvent() const;
@@ -322,6 +324,7 @@ private:
                                             bool bIsLoading, bool bOwnLock, 
bool bHandleSysLocked);
     enum class MessageDlg { LockFileIgnore, LockFileCorrupt };
     bool                ShowLockFileProblemDialog(MessageDlg nWhichDlg);
+    void ReleaseEmbeddedFonts();
 };
 
 #endif
diff --git a/include/vcl/embeddedfontshelper.hxx 
b/include/vcl/embeddedfontshelper.hxx
index 12059c7f07b8..fa4129976040 100644
--- a/include/vcl/embeddedfontshelper.hxx
+++ b/include/vcl/embeddedfontshelper.hxx
@@ -94,6 +94,8 @@ public:
      */
     static bool isCommonFont(std::u16string_view aFontName);
 
+    static void releaseFonts(const std::vector<std::pair<OUString, OUString>>& 
fonts);
+
     EmbeddedFontsHelper(const css::uno::Reference<css::frame::XModel>& xModel);
     ~EmbeddedFontsHelper() COVERITY_NOEXCEPT_FALSE;
 };
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index d136e259cddd..4e75a66e3c9d 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -1131,6 +1131,7 @@ public:
     bool                        IsFontAvailable( std::u16string_view rFontName 
) const;
 
     bool                        AddTempDevFont( const OUString& rFileURL, 
const OUString& rFontName );
+    bool                        RemoveTempDevFont( const OUString& rFileURL, 
const OUString& rFontName );
     void                        RefreshFontData( const bool bNewFontLists );
 
     FontMetric                  GetFontMetric() const;
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index a392e091cc19..164c064cdaf8 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -30,6 +30,7 @@
 #include <com/sun/star/task/XStatusIndicator.hpp>
 #include <com/sun/star/uno/Reference.h>
 #include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/beans/StringPair.hpp>
 #include <com/sun/star/beans/XPropertySet.hpp>
 #include <com/sun/star/container/XChild.hpp>
 #include <com/sun/star/document/XDocumentRevisionListPersistence.hpp>
@@ -415,6 +416,7 @@ public:
     bool m_bODFWholesomeEncryption = false;
 
     /// font family, file URL
+    std::vector<std::pair<OUString, OUString>> m_aEmbeddedFonts;
     std::vector<std::pair<OUString, OUString>> m_aEmbeddedFontsToActivate;
 
     OUString m_aName;
@@ -3736,6 +3738,8 @@ SfxMedium::~SfxMedium()
 
     Close(/*bInDestruction*/true);
 
+    ReleaseEmbeddedFonts();
+
     if( !pImpl->bIsTemp || pImpl->m_aName.isEmpty() )
         return;
 
@@ -3752,6 +3756,15 @@ SfxMedium::~SfxMedium()
     }
 }
 
+void SfxMedium::ReleaseEmbeddedFonts()
+{
+    std::vector<std::pair<OUString, OUString>> 
toRelease(std::move(pImpl->m_aEmbeddedFonts));
+    toRelease.insert(toRelease.end(), 
pImpl->m_aEmbeddedFontsToActivate.begin(),
+                     pImpl->m_aEmbeddedFontsToActivate.end());
+    pImpl->m_aEmbeddedFontsToActivate.clear();
+    EmbeddedFontsHelper::releaseFonts(toRelease);
+}
+
 const OUString& SfxMedium::GetName() const
 {
     return pImpl->m_aLogicName;
@@ -4002,6 +4015,18 @@ bool SfxMedium::IsOriginallyLoadedReadOnly() const
     return pImpl->m_bOriginallyLoadedReadOnly;
 }
 
+void SfxMedium::TransferEmbeddedFontsTo(SfxMedium& target)
+{
+    target.pImpl->m_aEmbeddedFonts.insert(target.pImpl->m_aEmbeddedFonts.end(),
+                                          pImpl->m_aEmbeddedFonts.begin(),
+                                          pImpl->m_aEmbeddedFonts.end());
+    pImpl->m_aEmbeddedFonts.clear();
+    
target.pImpl->m_aEmbeddedFontsToActivate.insert(target.pImpl->m_aEmbeddedFontsToActivate.end(),
+                                                    
pImpl->m_aEmbeddedFontsToActivate.begin(),
+                                                    
pImpl->m_aEmbeddedFontsToActivate.end());
+    pImpl->m_aEmbeddedFontsToActivate.clear();
+}
+
 void SfxMedium::AddEmbeddedFonts(
     const css::uno::Sequence<css::beans::StringPair>& fonts)
 {
@@ -4012,6 +4037,10 @@ void SfxMedium::AddEmbeddedFonts(
 void SfxMedium::activateEmbeddedFonts()
 {
     EmbeddedFontsHelper::activateFonts(pImpl->m_aEmbeddedFontsToActivate);
+    pImpl->m_aEmbeddedFonts.insert(pImpl->m_aEmbeddedFonts.end(),
+                                   pImpl->m_aEmbeddedFontsToActivate.begin(),
+                                   pImpl->m_aEmbeddedFontsToActivate.end());
+    pImpl->m_aEmbeddedFontsToActivate.clear();
 }
 
 bool SfxMedium::SetWritableForUserOnly( const OUString& aURL )
diff --git a/sfx2/source/doc/objstor.cxx b/sfx2/source/doc/objstor.cxx
index b23396599240..db01b2e4b263 100644
--- a/sfx2/source/doc/objstor.cxx
+++ b/sfx2/source/doc/objstor.cxx
@@ -2375,6 +2375,10 @@ bool SfxObjectShell::DoSaveCompleted( SfxMedium* 
pNewMed, bool bRegisterRecent )
     SfxMedium* pOld = pMedium;
     if ( bMedChanged )
     {
+        if (pMedium)
+        {
+            pMedium->TransferEmbeddedFontsTo(*pNewMed);
+        }
         pMedium = pNewMed;
         pMedium->CanDisposeStorage_Impl( true );
     }
diff --git a/vcl/headless/svptext.cxx b/vcl/headless/svptext.cxx
index 22b7b37c5507..d01a967420c7 100644
--- a/vcl/headless/svptext.cxx
+++ b/vcl/headless/svptext.cxx
@@ -59,6 +59,11 @@ bool SvpSalGraphics::AddTempDevFont( 
vcl::font::PhysicalFontCollection* pFontCol
     return m_aTextRenderImpl.AddTempDevFont(pFontCollection, rFileURL, 
rFontName);
 }
 
+bool SvpSalGraphics::RemoveTempDevFont(const OUString& rFileURL, const 
OUString& rFontName)
+{
+    return m_aTextRenderImpl.RemoveTempDevFont(rFileURL, rFontName);
+}
+
 std::unique_ptr<GenericSalLayout> SvpSalGraphics::GetTextLayout(int 
nFallbackLevel)
 {
     return m_aTextRenderImpl.GetTextLayout(nFallbackLevel);
diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx
index c83b92839bff..837168b2ca7b 100644
--- a/vcl/inc/headless/svpgdi.hxx
+++ b/vcl/inc/headless/svpgdi.hxx
@@ -72,6 +72,7 @@ public:
     virtual void            GetDevFontList( vcl::font::PhysicalFontCollection* 
) override;
     virtual void ClearDevFontCache() override;
     virtual bool            AddTempDevFont( 
vcl::font::PhysicalFontCollection*, const OUString& rFileURL, const OUString& 
rFontName ) override;
+    virtual bool            RemoveTempDevFont( const OUString& rFileURL, const 
OUString& rFontName ) override;
     virtual std::unique_ptr<GenericSalLayout>
                             GetTextLayout(int nFallbackLevel) override;
     virtual void            DrawTextLayout( const GenericSalLayout& ) override;
diff --git a/vcl/inc/qt5/QtGraphics.hxx b/vcl/inc/qt5/QtGraphics.hxx
index 2fe97adcc9d9..80ad883f4306 100644
--- a/vcl/inc/qt5/QtGraphics.hxx
+++ b/vcl/inc/qt5/QtGraphics.hxx
@@ -218,6 +218,7 @@ public:
     virtual void ClearDevFontCache() override;
     virtual bool AddTempDevFont(vcl::font::PhysicalFontCollection*, const 
OUString& rFileURL,
                                 const OUString& rFontName) override;
+    virtual bool RemoveTempDevFont(const OUString& rFileURL, const OUString& 
rFontName) override;
 
     virtual std::unique_ptr<GenericSalLayout> GetTextLayout(int 
nFallbackLevel) override;
     virtual void DrawTextLayout(const GenericSalLayout&) override;
diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h
index ee40c46102ae..0fdb516d7f93 100644
--- a/vcl/inc/quartz/salgdi.h
+++ b/vcl/inc/quartz/salgdi.h
@@ -458,6 +458,7 @@ public:
     // graphics must drop any cached font info
     virtual void            ClearDevFontCache() override;
     virtual bool            AddTempDevFont( 
vcl::font::PhysicalFontCollection*, const OUString& rFileURL, const OUString& 
rFontName ) override;
+    virtual bool            RemoveTempDevFont( const OUString& rFileURL, const 
OUString& rFontName ) override;
 
     virtual std::unique_ptr<GenericSalLayout>
                             GetTextLayout(int nFallbackLevel) override;
diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx
index 36c8957a4dc3..0e45d881f770 100644
--- a/vcl/inc/salgdi.hxx
+++ b/vcl/inc/salgdi.hxx
@@ -152,6 +152,10 @@ public:
                                     const OUString& rFileURL,
                                     const OUString& rFontName ) = 0;
 
+    // Returns true, when the font was unregistered, and its file can be 
safely deleted
+    virtual bool                RemoveTempDevFont(const OUString& rFileURL,
+                                                  const OUString& rFontName) = 
0;
+
     virtual std::unique_ptr<GenericSalLayout>
                                 GetTextLayout(int nFallbackLevel) = 0;
     virtual void                DrawTextLayout( const GenericSalLayout& ) = 0;
diff --git a/vcl/inc/textrender.hxx b/vcl/inc/textrender.hxx
index 96e09fd8917d..6c2731648b48 100644
--- a/vcl/inc/textrender.hxx
+++ b/vcl/inc/textrender.hxx
@@ -38,6 +38,7 @@ public:
     virtual void                    GetDevFontList( 
vcl::font::PhysicalFontCollection* ) = 0;
     virtual void                    ClearDevFontCache() = 0;
     virtual bool                    AddTempDevFont( 
vcl::font::PhysicalFontCollection*, const OUString& rFileURL, const OUString& 
rFontName ) = 0;
+    virtual bool                    RemoveTempDevFont( const OUString& 
rFileURL, const OUString& rFontName ) = 0;
 
     virtual std::unique_ptr<GenericSalLayout>
                                     GetTextLayout(int nFallbackLevel) = 0;
diff --git a/vcl/inc/unx/fontmanager.hxx b/vcl/inc/unx/fontmanager.hxx
index e7d76bd6b659..ad54604fc019 100644
--- a/vcl/inc/unx/fontmanager.hxx
+++ b/vcl/inc/unx/fontmanager.hxx
@@ -117,6 +117,9 @@ class VCL_PLUGIN_PUBLIC PrintFontManager
     /* register an application specific font file for libfontconfig */
     static void addFontconfigFile(const OString& rFile);
 
+    /* deregister an application specific font file from libfontconfig */
+    static void removeFontconfigFile(std::string_view aFile);
+
     std::set<OString> m_aPreviousLangSupportRequests;
     std::vector<OUString> m_aCurrentRequests;
     Timer m_aFontInstallerTimer;
@@ -128,9 +131,14 @@ public:
     friend class ::GenericUnixSalData;
     static PrintFontManager& get(); // one instance only
 
+    // There may be multiple font ids for font collections
+    std::vector<fontID> findFontFileIDs( std::u16string_view rFileUrl ) const;
+
     // There may be multiple font ids for font collections
     std::vector<fontID> addFontFile( std::u16string_view rFileUrl );
 
+    void removeFontFile( std::u16string_view rFileUrl );
+
     void initialize();
 
     const PrintFont* getFont( fontID nID ) const
diff --git a/vcl/inc/unx/freetypetextrender.hxx 
b/vcl/inc/unx/freetypetextrender.hxx
index 63568db4985d..055b5ddf7a14 100644
--- a/vcl/inc/unx/freetypetextrender.hxx
+++ b/vcl/inc/unx/freetypetextrender.hxx
@@ -47,6 +47,7 @@ public:
     virtual void                GetDevFontList( 
vcl::font::PhysicalFontCollection* ) override;
     virtual void                ClearDevFontCache() override;
     virtual bool                AddTempDevFont( 
vcl::font::PhysicalFontCollection*, const OUString& rFileURL, const OUString& 
rFontName ) override;
+    virtual bool                RemoveTempDevFont( const OUString& rFileURL, 
const OUString& rFontName ) override;
 
     virtual std::unique_ptr<GenericSalLayout>
                                 GetTextLayout(int nFallbackLevel) override;
diff --git a/vcl/inc/unx/genpspgraphics.h b/vcl/inc/unx/genpspgraphics.h
index fe904a0b6f3c..aade5d4adb3b 100644
--- a/vcl/inc/unx/genpspgraphics.h
+++ b/vcl/inc/unx/genpspgraphics.h
@@ -67,6 +67,8 @@ public:
     SAL_DLLPRIVATE virtual bool AddTempDevFont( 
vcl::font::PhysicalFontCollection*,
                                             const OUString& rFileURL,
                                             const OUString& rFontName ) 
override;
+    SAL_DLLPRIVATE virtual bool RemoveTempDevFont(const OUString& rFileURL,
+                                                  const OUString& rFontName) 
override;
 
     SAL_DLLPRIVATE virtual std::unique_ptr<GenericSalLayout>
                             GetTextLayout(int nFallbackLevel) override;
diff --git a/vcl/inc/unx/glyphcache.hxx b/vcl/inc/unx/glyphcache.hxx
index 1a891e3d9b80..e85bad91d0c3 100644
--- a/vcl/inc/unx/glyphcache.hxx
+++ b/vcl/inc/unx/glyphcache.hxx
@@ -80,6 +80,7 @@ public:
                                 int nFaceNum, int nVariantNum,
                                 sal_IntPtr nFontId,
                                 const FontAttributes&);
+    void                    RemoveFontFile(sal_IntPtr nFontId);
 
     SAL_DLLPRIVATE void     AnnounceFonts( vcl::font::PhysicalFontCollection* 
) const;
 
diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h
index fb7619801d08..81e6fa317911 100644
--- a/vcl/inc/unx/salgdi.h
+++ b/vcl/inc/unx/salgdi.h
@@ -92,6 +92,7 @@ public:
     virtual void                    GetDevFontList( 
vcl::font::PhysicalFontCollection* ) override;
     virtual void                    ClearDevFontCache() override;
     virtual bool                    AddTempDevFont( 
vcl::font::PhysicalFontCollection*, const OUString& rFileURL, const OUString& 
rFontName ) override;
+    virtual bool                    RemoveTempDevFont( const OUString& 
rFileURL, const OUString& rFontName ) override;
 
     virtual std::unique_ptr<GenericSalLayout>
                                     GetTextLayout(int nFallbackLevel) override;
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index ed6ef27d45a1..dbeb9fc3d4d8 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -176,6 +176,7 @@ public:
     // graphics must drop any cached font info
     virtual void            ClearDevFontCache() override;
     virtual bool            AddTempDevFont( 
vcl::font::PhysicalFontCollection*, const OUString& rFileURL, const OUString& 
rFontName ) override;
+    virtual bool            RemoveTempDevFont(const OUString& rFileURL, const 
OUString& rFontName) override;
 
     virtual std::unique_ptr<GenericSalLayout>
                             GetTextLayout(int nFallbackLevel) override;
diff --git a/vcl/qt5/QtGraphics_Text.cxx b/vcl/qt5/QtGraphics_Text.cxx
index 3bd998cdbdd5..23006a4b2563 100644
--- a/vcl/qt5/QtGraphics_Text.cxx
+++ b/vcl/qt5/QtGraphics_Text.cxx
@@ -135,6 +135,11 @@ bool 
QtGraphics::AddTempDevFont(vcl::font::PhysicalFontCollection*, const OUStri
     return false;
 }
 
+bool QtGraphics::RemoveTempDevFont(const OUString& /*rFileURL*/, const 
OUString& /*rFontName*/)
+{
+    return true; // No fonts registered - no problem to remove
+}
+
 namespace
 {
 class QtCommonSalLayout : public GenericSalLayout
diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx
index 5c1fc31faedb..a08d17ab5942 100644
--- a/vcl/quartz/salgdi.cxx
+++ b/vcl/quartz/salgdi.cxx
@@ -243,6 +243,25 @@ static bool AddTempDevFont(const OUString& rFontFileURL)
     return success;
 }
 
+static bool RemoveTempDevFont(const OUString& rFontFileURL)
+{
+    OUString aUSystemPath;
+    OSL_VERIFY(!osl::FileBase::getSystemPathFromFileURL(rFontFileURL, 
aUSystemPath));
+    OString aCFileName = OUStringToOString(aUSystemPath, 
RTL_TEXTENCODING_UTF8);
+
+    CFStringRef rFontPath
+        = CFStringCreateWithCString(nullptr, aCFileName.getStr(), 
kCFStringEncodingUTF8);
+    CFURLRef rFontURL
+        = CFURLCreateWithFileSystemPath(nullptr, rFontPath, 
kCFURLPOSIXPathStyle, true);
+
+    CTFontManagerUnregisterFontsForURL(rFontURL, kCTFontManagerScopeProcess, 
nullptr);
+
+    CFRelease(rFontPath);
+    CFRelease(rFontURL);
+
+    return true; // Assume that even errors meant that there was nothing to 
remove
+}
+
 static void AddTempFontDir( const OUString &rFontDirUrl )
 {
     osl::Directory aFontDir( rFontDirUrl );
@@ -322,6 +341,11 @@ bool 
AquaSalGraphics::AddTempDevFont(vcl::font::PhysicalFontCollection*,
     return ::AddTempDevFont(rFontFileURL);
 }
 
+bool AquaSalGraphics::RemoveTempDevFont(const OUString& rFontFileURL, const 
OUString& /*rFontName*/)
+{
+    return ::RemoveTempDevFont(rFontFileURL);
+}
+
 void AquaSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout)
 {
     mpBackend->drawTextLayout(rLayout);
diff --git a/vcl/source/gdi/embeddedfontshelper.cxx 
b/vcl/source/gdi/embeddedfontshelper.cxx
index 3597207b1b35..d21fa500e4e6 100644
--- a/vcl/source/gdi/embeddedfontshelper.cxx
+++ b/vcl/source/gdi/embeddedfontshelper.cxx
@@ -10,6 +10,8 @@
 #include <sal/config.h>
 
 #include <memory>
+#include <mutex>
+#include <unordered_map>
 #include <frozen/bits/defines.h>
 #include <frozen/bits/elsa_std.h>
 #include <frozen/unordered_set.h>
@@ -62,6 +64,17 @@ const OUString& GetEmbeddedFontsRoot()
     return path;
 }
 
+struct EmbeddedFontData
+{
+    OUString familyName;
+    int refcount = 0;
+    bool isActivated = false;
+};
+
+std::mutex s_EmbeddedFontsMutex;
+// file URL -> EmbeddedFontData
+std::unordered_map<OUString, EmbeddedFontData> s_EmbeddedFonts;
+
 void clearDir( const OUString& path )
 {
     osl::Directory dir( path );
@@ -97,13 +110,12 @@ OUString fileUrlForTemporaryFont(std::u16string_view name)
                               RTL_TEXTENCODING_UTF8);
 }
 
-// Returns true when the file was written, or exactly same data was existing.
+// Returns actual URL (maybe of an already existing file), or empty string on 
failure.
 //
 // @param name name of the font file
-// @param url returns URL of a new file, or empty string (when the same file 
already existed).
-bool writeFontBytesToFile(const std::vector<char>& bytes, std::u16string_view 
name, OUString& url)
+OUString writeFontBytesToFile(const std::vector<char>& bytes, 
std::u16string_view name)
 {
-    url = fileUrlForTemporaryFont(name);
+    OUString url = fileUrlForTemporaryFont(name);
     std::optional<osl::File> file(url);
     auto rc = file->open(osl_File_OpenFlag_Create | osl_File_OpenFlag_Write);
 
@@ -126,8 +138,7 @@ bool writeFontBytesToFile(const std::vector<char>& bytes, 
std::u16string_view na
                 }
                 if (rc == osl::File::E_None && bytes2 == bytes)
                 {
-                    url.clear();
-                    return true; // OK, it's the same bytes
+                    return url; // OK, it's the same bytes
                 }
             }
         }
@@ -137,7 +148,7 @@ bool writeFontBytesToFile(const std::vector<char>& bytes, 
std::u16string_view na
     }
 
     if (rc != osl::File::E_None)
-        return false;
+        return {};
 
     sal_uInt64 writtenTotal = 0;
     while (writtenTotal < bytes.size())
@@ -148,11 +159,11 @@ bool writeFontBytesToFile(const std::vector<char>& bytes, 
std::u16string_view na
         {
             file->close();
             osl::File::remove(file->getURL());
-            return false;
+            return {};
         }
         writtenTotal += written;
     }
-    return true;
+    return url;
 }
 }
 
@@ -185,7 +196,7 @@ EmbeddedFontsHelper::~EmbeddedFontsHelper() 
COVERITY_NOEXCEPT_FALSE
         }
     }
 
-    // Failed to transfer the read-only fonts to the document. Activate them 
here.
+    // Failed to transfer the fonts to the document. Activate them here.
     activateFonts(m_aAccumulatedFonts);
 }
 
@@ -282,11 +293,21 @@ bool EmbeddedFontsHelper::addEmbeddedFont( const 
uno::Reference< io::XInputStrea
         }
     }
 
-    OUString fileUrl;
-    if (!writeFontBytesToFile(fontData, Concat2View(fontName + extra), 
fileUrl))
+    OUString fileUrl = writeFontBytesToFile(fontData, Concat2View(fontName + 
extra));
+    if (fileUrl.isEmpty())
         return false;
-    if (!fileUrl.isEmpty())
-        m_aAccumulatedFonts.emplace_back(std::make_pair(fontName, fileUrl));
+
+    // Register it, and increase its refcount in s_EmbeddedFonts
+    {
+        std::unique_lock lock(s_EmbeddedFontsMutex);
+        auto& rData = s_EmbeddedFonts[fileUrl];
+        assert(rData.familyName.isEmpty() || rData.familyName == fontName);
+        rData.familyName = fontName;
+        ++rData.refcount;
+    }
+
+    m_aAccumulatedFonts.emplace_back(fontName, fileUrl);
+
     return true;
 }
 
@@ -310,11 +331,68 @@ void 
EmbeddedFontsHelper::activateFonts(std::vector<std::pair<OUString, OUString
 {
     if (fonts.empty())
         return;
+    std::vector<std::pair<OUString, OUString>> temp;
+
+    {
+        std::unique_lock lock(s_EmbeddedFontsMutex);
+        // Only activate fonts that need activation.
+        for (const auto& pair : fonts)
+        {
+            auto it = s_EmbeddedFonts.find(pair.second);
+            assert(it != s_EmbeddedFonts.end());
+            if (!it->second.isActivated)
+            {
+                it->second.isActivated = true;
+                temp.push_back(pair);
+            }
+        }
+    }
+
+    if (temp.empty())
+        return;
+
     UpdateFontsGuard aUpdateFontsGuard;
     OutputDevice *pDevice = Application::GetDefaultDevice();
-    for (const auto& [ fontName, fileUrl ] : fonts)
+    for (const auto& [ fontName, fileUrl ] : temp)
         pDevice->AddTempDevFont(fileUrl, fontName);
-    fonts.clear();
+}
+
+void EmbeddedFontsHelper::releaseFonts(const std::vector<std::pair<OUString, 
OUString>>& fonts)
+{
+    std::vector<std::pair<OUString, OUString>> unregister;
+    {
+        std::unique_lock g(s_EmbeddedFontsMutex);
+        for (const auto& pair : fonts)
+        {
+            auto it = s_EmbeddedFonts.find(pair.second);
+            if (it == s_EmbeddedFonts.end())
+            {
+                SAL_WARN("vcl.fonts", "Trying to release a font that wasn't 
locked?");
+                continue;
+            }
+            assert(it->second.familyName == pair.first);
+
+            --it->second.refcount;
+            if (it->second.refcount == 0)
+            {
+                unregister.emplace_back(pair);
+
+                s_EmbeddedFonts.erase(it);
+            }
+        }
+    }
+
+    if (unregister.empty())
+        return;
+
+    OutputDevice* pDevice = Application::GetDefaultDevice();
+    for (const auto& [ family, url ] : unregister)
+    {
+        if (pDevice->RemoveTempDevFont(url, family))
+            osl::File::remove(url);
+    }
+
+    OutputDevice::ImplUpdateAllFontData(true);
 }
 
 // Check if it's (legally) allowed to embed the font file into a document
diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx
index 7b45f7782893..12a097fb38d8 100644
--- a/vcl/source/outdev/font.cxx
+++ b/vcl/source/outdev/font.cxx
@@ -136,6 +136,15 @@ bool OutputDevice::AddTempDevFont( const OUString& 
rFileURL, const OUString& rFo
     return true;
 }
 
+bool OutputDevice::RemoveTempDevFont(const OUString& rFileURL, const OUString& 
rFontName)
+{
+    if( !mpGraphics && !AcquireGraphics() )
+        return true; // No graphics -> no fonts used
+    assert(mpGraphics);
+
+    return mpGraphics->RemoveTempDevFont(rFileURL, rFontName);
+}
+
 bool OutputDevice::GetFontFeatures(std::vector<vcl::font::Feature>& 
rFontFeatures) const
 {
     if (!ImplNewFont())
diff --git a/vcl/unx/generic/fontmanager/fontconfig.cxx 
b/vcl/unx/generic/fontmanager/fontconfig.cxx
index 95ed5a19b5fc..642a1a7ef733 100644
--- a/vcl/unx/generic/fontmanager/fontconfig.cxx
+++ b/vcl/unx/generic/fontmanager/fontconfig.cxx
@@ -52,6 +52,7 @@
 #include <osl/process.h>
 
 #include <o3tl/hash_combine.hxx>
+#include <set>
 #include <utility>
 #include <algorithm>
 
@@ -791,6 +792,39 @@ void PrintFontManager::addFontconfigFile( const OString& 
rFileName )
     rWrapper.addFontSet( FcSetApplication );
 }
 
+void PrintFontManager::removeFontconfigFile(std::string_view aFileName)
+{
+    FcFontSet* pOrig = FcConfigGetFonts(FcConfigGetCurrent(), 
FcSetApplication);
+    if (!pOrig)
+        return;
+
+    std::set<OString> restoreList;
+
+    // filter the font sets to remove the file
+    for (int i = 0; i < pOrig->nfont; ++i)
+    {
+        FcChar8* file = nullptr;
+        FcResult eFileRes = FcPatternGetString(pOrig->fonts[i], FC_FILE, 0, 
&file);
+        if (eFileRes == FcResultMatch)
+        {
+            if (std::string_view curFile(reinterpret_cast<char*>(file)); 
aFileName != curFile)
+                restoreList.emplace(curFile);
+        }
+    }
+
+    FcConfigAppFontClear(FcConfigGetCurrent());
+
+    // Re-add the rest of files
+    for (const OString& thisFilename : restoreList)
+    {
+        FcConfigAppFontAddFile(FcConfigGetCurrent(),
+                               reinterpret_cast<FcChar8 
const*>(thisFilename.getStr()));
+    }
+
+    FontCfgWrapper& rWrapper = FontCfgWrapper::get();
+    rWrapper.addFontSet( FcSetApplication );
+}
+
 static void addtopattern(FcPattern *pPattern,
     FontItalic eItalic, FontWeight eWeight, FontWidth eWidth, FontPitch ePitch)
 {
diff --git a/vcl/unx/generic/fontmanager/fontmanager.cxx 
b/vcl/unx/generic/fontmanager/fontmanager.cxx
index 2e454aa13d08..d755f317362a 100644
--- a/vcl/unx/generic/fontmanager/fontmanager.cxx
+++ b/vcl/unx/generic/fontmanager/fontmanager.cxx
@@ -135,6 +135,21 @@ int PrintFontManager::getDirectoryAtom( const OString& 
rDirectory )
     return nAtom;
 }
 
+std::vector<fontID> PrintFontManager::findFontFileIDs( std::u16string_view 
rFileUrl ) const
+{
+    rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+    INetURLObject aPath( rFileUrl );
+    OString 
aName(OUStringToOString(aPath.GetLastName(INetURLObject::DecodeMechanism::WithCharset,
 aEncoding), aEncoding));
+    OString aDir( OUStringToOString(
+        INetURLObject::decode( aPath.GetPath(), 
INetURLObject::DecodeMechanism::WithCharset, aEncoding ), aEncoding ) );
+
+    auto dirIt = m_aDirToAtom.find(aDir);
+    if (dirIt == m_aDirToAtom.end())
+        return {};
+
+    return findFontFileIDs(dirIt->second, aName);
+}
+
 std::vector<fontID> PrintFontManager::addFontFile( std::u16string_view 
rFileUrl )
 {
     rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
@@ -161,6 +176,25 @@ std::vector<fontID> PrintFontManager::addFontFile( 
std::u16string_view rFileUrl
     return aFontIds;
 }
 
+void PrintFontManager::removeFontFile(std::u16string_view rFileUrl)
+{
+    INetURLObject aPath(rFileUrl);
+    rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+    if (auto ids = findFontFileIDs(rFileUrl); !ids.empty())
+    {
+        OString aName(OUStringToOString(
+            aPath.GetLastName(INetURLObject::DecodeMechanism::WithCharset, 
aEncoding), aEncoding));
+
+        for (auto nFontID : ids)
+        {
+            m_aFonts.erase(nFontID);
+            m_aFontFileToFontID[aName].erase(nFontID);
+        }
+    }
+
+    removeFontconfigFile(OUStringToOString(aPath.GetFull(), aEncoding));
+}
+
 std::vector<PrintFontManager::PrintFont> PrintFontManager::analyzeFontFile( 
int nDirID, const OString& rFontFile) const
 {
     std::vector<PrintFontManager::PrintFont> aNewFonts;
diff --git a/vcl/unx/generic/gdi/font.cxx b/vcl/unx/generic/gdi/font.cxx
index 19887a9af230..a17c72d90a7f 100644
--- a/vcl/unx/generic/gdi/font.cxx
+++ b/vcl/unx/generic/gdi/font.cxx
@@ -60,6 +60,11 @@ bool X11SalGraphics::AddTempDevFont( 
vcl::font::PhysicalFontCollection* pFontCol
     return mxTextRenderImpl->AddTempDevFont(pFontCollection, rFileURL, 
rFontName);
 }
 
+bool X11SalGraphics::RemoveTempDevFont(const OUString& rFileURL, const 
OUString& rFontName)
+{
+    return mxTextRenderImpl->RemoveTempDevFont(rFileURL, rFontName);
+}
+
 void X11SalGraphics::ClearDevFontCache()
 {
     mxTextRenderImpl->ClearDevFontCache();
diff --git a/vcl/unx/generic/gdi/freetypetextrender.cxx 
b/vcl/unx/generic/gdi/freetypetextrender.cxx
index e5d3f3067dce..4fae167f234c 100644
--- a/vcl/unx/generic/gdi/freetypetextrender.cxx
+++ b/vcl/unx/generic/gdi/freetypetextrender.cxx
@@ -128,6 +128,22 @@ bool 
FreeTypeTextRenderImpl::AddTempDevFont(vcl::font::PhysicalFontCollection* p
     return true;
 }
 
+bool FreeTypeTextRenderImpl::RemoveTempDevFont(const OUString& rFileURL, const 
OUString& /*rFontName*/)
+{
+    // inform PSP font manager
+    psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
+    std::vector<psp::fontID> aFontIds = rMgr.findFontFileIDs(rFileURL);
+    if (aFontIds.empty())
+        return true; // Nothing to remove -> safe to delete the file
+
+    FreetypeManager& rFreetypeManager = FreetypeManager::get();
+    for (auto const& nFontId : aFontIds)
+        rFreetypeManager.RemoveFontFile(nFontId);
+
+    rMgr.removeFontFile(rFileURL);
+    return true;
+}
+
 void FreeTypeTextRenderImpl::ClearDevFontCache()
 {
     FreetypeManager::get().ClearFontCache();
diff --git a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx 
b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
index 5745f94a223e..39c2c784b3b1 100644
--- a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
+++ b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
@@ -277,6 +277,13 @@ void FreetypeManager::AddFontFile(const OString& 
rNormalizedName,
     m_aFontInfoList[ nFontId ].reset(pFontInfo);
 }
 
+void FreetypeManager::RemoveFontFile(sal_IntPtr nFontId)
+{
+    auto it = m_aFontInfoList.find(nFontId);
+    if (it != m_aFontInfoList.end())
+        m_aFontInfoList.erase(it);
+}
+
 void FreetypeManager::AnnounceFonts( vcl::font::PhysicalFontCollection* pToAdd 
) const
 {
     for (auto const& font : m_aFontInfoList)
diff --git a/vcl/unx/generic/print/genpspgraphics.cxx 
b/vcl/unx/generic/print/genpspgraphics.cxx
index 66bf4524748f..ecff3110f51e 100644
--- a/vcl/unx/generic/print/genpspgraphics.cxx
+++ b/vcl/unx/generic/print/genpspgraphics.cxx
@@ -118,6 +118,11 @@ bool GenPspGraphics::AddTempDevFont( 
vcl::font::PhysicalFontCollection* pFontCol
     return m_aTextRenderImpl.AddTempDevFont(pFontCollection, rFileURL, 
rFontName);
 }
 
+bool GenPspGraphics::RemoveTempDevFont(const OUString& rFileURL, const 
OUString& rFontName)
+{
+    return m_aTextRenderImpl.RemoveTempDevFont(rFileURL, rFontName);
+}
+
 void GenPspGraphics::GetDevFontList( vcl::font::PhysicalFontCollection 
*pFontCollection )
 {
     m_aTextRenderImpl.GetDevFontList(pFontCollection);
diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx
index 2ca870aad98d..c2ade38a8953 100644
--- a/vcl/win/gdi/salfont.cxx
+++ b/vcl/win/gdi/salfont.cxx
@@ -972,6 +972,26 @@ bool 
WinSalGraphics::AddTempDevFont(vcl::font::PhysicalFontCollection* pFontColl
     return true;
 }
 
+bool WinSalGraphics::RemoveTempDevFont(const OUString& rFileURL, const 
OUString& /*rFontName*/)
+{
+    OUString path;
+    osl::FileBase::getSystemPathFromFileURL(rFileURL, path);
+    auto pSalData = GetSalData();
+    for (TempFontItem** pp = &pSalData->mpTempFontItem; *pp; pp = 
&(*pp)->mpNextItem)
+    {
+        if ((*pp)->maFontResourcePath == path)
+        {
+            RemoveFontResourceExW(o3tl::toW(path.getStr()), FR_PRIVATE, 
nullptr);
+            auto p = *pp;
+            *pp = p->mpNextItem;
+            delete p;
+            return true;
+        }
+    }
+    SAL_WARN("vcl.fonts", "Trying to unregister an embedded font that wasn't 
registered?");
+    return true; // It's still safe to delete the font file: we don't use it
+}
+
 void WinSalGraphics::GetDevFontList( vcl::font::PhysicalFontCollection* 
pFontCollection )
 {
     // make sure all LO shared fonts are registered temporarily

Reply via email to