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