include/svx/fontworkgallery.hxx | 2 - include/vcl/weld.hxx | 7 +++--- sd/source/ui/sidebar/MasterPagesSelector.cxx | 16 ++++++++++++- sd/source/ui/sidebar/MasterPagesSelector.hxx | 1 starmath/source/ElementsDockingWindow.cxx | 3 +- svx/source/inc/StylesPreviewWindow.hxx | 2 - svx/source/tbxctrls/StylesPreviewWindow.cxx | 31 +++++++++++++-------------- svx/source/tbxctrls/fontworkgallery.cxx | 6 ++--- vcl/inc/jsdialog/jsdialogbuilder.hxx | 4 +-- vcl/inc/qt5/QtInstanceIconView.hxx | 4 +-- vcl/inc/salvtables.hxx | 4 +-- vcl/jsdialog/jsdialogbuilder.cxx | 4 +-- vcl/qt5/QtInstanceIconView.cxx | 4 +-- vcl/source/app/salvtables.cxx | 6 +---- vcl/unx/gtk3/gtkinst.cxx | 12 ++++++++-- 15 files changed, 64 insertions(+), 42 deletions(-)
New commits: commit 25f007984f91393dbc34adbd2bf59d8b4bae490a Author: Noel Grandin <noelgran...@gmail.com> AuthorDate: Tue Jun 10 18:20:18 2025 +0200 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Wed Jun 11 17:11:29 2025 +0200 tdf#166932 use BitmapEx in preview style cache instead of VirtualDevice which reduces the number of open GDI handles we need Change-Id: I9620d120b9ec88d972908eb713560e414384dec7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186333 Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> Tested-by: Jenkins (cherry picked from commit 8899ae01feb9b9088372d76a6d0562397174c89c) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186352 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/include/svx/fontworkgallery.hxx b/include/svx/fontworkgallery.hxx index 21c418584570..a91aa0a95f90 100644 --- a/include/svx/fontworkgallery.hxx +++ b/include/svx/fontworkgallery.hxx @@ -53,7 +53,7 @@ class SAL_WARN_UNUSED SVXCORE_DLLPUBLIC FontWorkGalleryDialog final : public wel rtl::Reference<SdrObject> mxSdrObject; SdrModel* mpDestModel; - std::vector<VclPtr< VirtualDevice >> maFavoritesHorizontal; + std::vector<BitmapEx> maFavoritesHorizontal; // mapping between item ID and item title std::map<OUString, OUString> maIdToTitleMap; diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx index b78bb73092ee..ce231ca7977a 100644 --- a/include/vcl/weld.hxx +++ b/include/vcl/weld.hxx @@ -60,6 +60,7 @@ class TransferDataContainer; class OutputDevice; class VirtualDevice; struct SystemEnvData; +class BitmapEx; namespace vcl { @@ -1461,8 +1462,8 @@ public: const OUString* pIconName, TreeIter* pRet) = 0; - virtual void insert(int pos, const OUString* pStr, const OUString* pId, - const VirtualDevice* pIcon, TreeIter* pRet) + virtual void insert(int pos, const OUString* pStr, const OUString* pId, const BitmapEx* pIcon, + TreeIter* pRet) = 0; virtual void insert_separator(int pos, const OUString* pId) = 0; @@ -1472,7 +1473,7 @@ public: insert(-1, &rStr, &rId, &rImage, nullptr); } - void append(const OUString& rId, const OUString& rStr, const VirtualDevice* pImage) + void append(const OUString& rId, const OUString& rStr, const BitmapEx* pImage) { insert(-1, &rStr, &rId, pImage, nullptr); } diff --git a/sd/source/ui/sidebar/MasterPagesSelector.cxx b/sd/source/ui/sidebar/MasterPagesSelector.cxx index b40704c307de..13ba8a88180f 100644 --- a/sd/source/ui/sidebar/MasterPagesSelector.cxx +++ b/sd/source/ui/sidebar/MasterPagesSelector.cxx @@ -391,16 +391,18 @@ void MasterPagesSelector::SetItem ( if (aPreview.GetSizePixel().Width() > 0) { - VclPtr<VirtualDevice> pVDev = GetVirtualDevice(aPreview); if (!mxPreviewIconView->get_id(nIndex).isEmpty()) { + VclPtr<VirtualDevice> pVDev = GetVirtualDevice(aPreview); mxPreviewIconView->set_image(nIndex, *pVDev); mxPreviewIconView->set_id(nIndex, OUString::number(aToken)); + pVDev.disposeAndClear(); } else { + BitmapEx aPreviewBitmap = GetPreviewAsBitmap(aPreview); OUString sId = OUString::number(aToken); - mxPreviewIconView->insert(nIndex, nullptr, &sId, pVDev, nullptr); + mxPreviewIconView->insert(nIndex, nullptr, &sId, &aPreviewBitmap, nullptr); mxPreviewIconView->set_item_accessible_name( nIndex, mpContainer->GetPageNameForToken(aToken)); } @@ -481,6 +483,16 @@ VclPtr<VirtualDevice> MasterPagesSelector::GetVirtualDevice(const Image& rImage) return pVDev; } +BitmapEx MasterPagesSelector::GetPreviewAsBitmap(const Image& rImage) +{ + BitmapEx aPreviewBitmap = rImage.GetBitmapEx(); + ScopedVclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create(); + if (pVDev->GetDPIScaleFactor() > 1) + aPreviewBitmap.Scale(pVDev->GetDPIScaleFactor(), pVDev->GetDPIScaleFactor()); + + return aPreviewBitmap; +} + void MasterPagesSelector::UpdateAllPreviews() { const ::osl::MutexGuard aGuard (maMutex); diff --git a/sd/source/ui/sidebar/MasterPagesSelector.hxx b/sd/source/ui/sidebar/MasterPagesSelector.hxx index 3731a491da74..0c8a36fd5e43 100644 --- a/sd/source/ui/sidebar/MasterPagesSelector.hxx +++ b/sd/source/ui/sidebar/MasterPagesSelector.hxx @@ -171,6 +171,7 @@ private: MasterPageContainer::Token aToken); static VclPtr<VirtualDevice> GetVirtualDevice(const Image& rPreview); + static BitmapEx GetPreviewAsBitmap(const Image& rPreview); }; } // end of namespace sd::sidebar diff --git a/starmath/source/ElementsDockingWindow.cxx b/starmath/source/ElementsDockingWindow.cxx index f96d4647c0b9..cfba577cb155 100644 --- a/starmath/source/ElementsDockingWindow.cxx +++ b/starmath/source/ElementsDockingWindow.cxx @@ -594,7 +594,8 @@ void SmElementsControl::addElement(const OUString& aElementVisual, const OUStrin maItemDatas.push_back(std::make_unique<ElementData>(aElementSource, aHelpText, maItemDatas.size())); const OUString aId(weld::toId(maItemDatas.back().get())); - mpIconView->insert(-1, nullptr, &aId, pDevice, nullptr); + BitmapEx aBitmap = pDevice->GetBitmapEx(Point(0,0), pDevice->GetOutputSizePixel()); + mpIconView->insert(-1, nullptr, &aId, &aBitmap, nullptr); mpIconView->set_item_accessible_name(mpIconView->n_children() - 1, GetElementHelpText(aId)); if (mpIconView->get_item_width() < aSize.Width()) mpIconView->set_item_width(aSize.Width()); diff --git a/svx/source/inc/StylesPreviewWindow.hxx b/svx/source/inc/StylesPreviewWindow.hxx index 455462659079..0cbee0c31747 100644 --- a/svx/source/inc/StylesPreviewWindow.hxx +++ b/svx/source/inc/StylesPreviewWindow.hxx @@ -123,7 +123,7 @@ public: void Select(const OUString& rStyleName); void RequestStylesListUpdate(); - static VclPtr<VirtualDevice> GetCachedPreview(const std::pair<OUString, OUString>& rStyle); + static BitmapEx GetCachedPreview(const std::pair<OUString, OUString>& rStyle); static OString GetCachedPreviewJson(const std::pair<OUString, OUString>& rStyle); private: diff --git a/svx/source/tbxctrls/StylesPreviewWindow.cxx b/svx/source/tbxctrls/StylesPreviewWindow.cxx index 7b2c63931e96..f3684c13c743 100644 --- a/svx/source/tbxctrls/StylesPreviewWindow.cxx +++ b/svx/source/tbxctrls/StylesPreviewWindow.cxx @@ -80,20 +80,17 @@ private: virtual void Invoke() override { StylePreviewCache::gJsonStylePreviewCache.clear(); } }; - static std::map<OUString, VclPtr<VirtualDevice>> gStylePreviewCache; + static std::map<OUString, BitmapEx> gStylePreviewCache; static std::map<OUString, OString> gJsonStylePreviewCache; static int gStylePreviewCacheClients; static JsonStylePreviewCacheClear gJsonIdleClear; public: - static std::map<OUString, VclPtr<VirtualDevice>>& Get() { return gStylePreviewCache; } + static std::map<OUString, BitmapEx>& Get() { return gStylePreviewCache; } static std::map<OUString, OString>& GetJson() { return gJsonStylePreviewCache; } static void ClearCache(bool bHard) { - for (auto& aPreview : gStylePreviewCache) - aPreview.second.disposeAndClear(); - gStylePreviewCache.clear(); if (bHard) { @@ -122,7 +119,7 @@ public: } }; -std::map<OUString, VclPtr<VirtualDevice>> StylePreviewCache::gStylePreviewCache; +std::map<OUString, BitmapEx> StylePreviewCache::gStylePreviewCache; std::map<OUString, OString> StylePreviewCache::gJsonStylePreviewCache; int StylePreviewCache::gStylePreviewCacheClients; StylePreviewCache::JsonStylePreviewCacheClear StylePreviewCache::gJsonIdleClear; @@ -580,23 +577,23 @@ IMPL_LINK(StylesPreviewWindow_Base, GetPreviewImage, const weld::encoded_image_q return true; } -VclPtr<VirtualDevice> -StylesPreviewWindow_Base::GetCachedPreview(const std::pair<OUString, OUString>& rStyle) +BitmapEx StylesPreviewWindow_Base::GetCachedPreview(const std::pair<OUString, OUString>& rStyle) { auto aFound = StylePreviewCache::Get().find(rStyle.second); if (aFound != StylePreviewCache::Get().end()) return StylePreviewCache::Get()[rStyle.second]; else { - VclPtr<VirtualDevice> pImg = VclPtr<VirtualDevice>::Create(); + ScopedVclPtrInstance<VirtualDevice> pImg; const Size aSize(100, 30); pImg->SetOutputSizePixel(aSize); StyleItemController aStyleController(rStyle); aStyleController.Paint(*pImg); - StylePreviewCache::Get()[rStyle.second] = pImg; + BitmapEx aBitmap = pImg->GetBitmapEx(Point(0, 0), aSize); + StylePreviewCache::Get()[rStyle.second] = aBitmap; - return pImg; + return aBitmap; } } @@ -606,8 +603,7 @@ OString StylesPreviewWindow_Base::GetCachedPreviewJson(const std::pair<OUString, if (aJsonFound != StylePreviewCache::GetJson().end()) return StylePreviewCache::GetJson()[rStyle.second]; - VclPtr<VirtualDevice> xDev = GetCachedPreview(rStyle); - BitmapEx aBitmap(xDev->GetBitmapEx(Point(0, 0), xDev->GetOutputSize())); + BitmapEx aBitmap = GetCachedPreview(rStyle); OString sResult = extractPngString(aBitmap); StylePreviewCache::GetJson()[rStyle.second] = sResult; return sResult; @@ -645,8 +641,13 @@ void StylesPreviewWindow_Base::UpdateStylesList() const bool bNeedInsertPreview = !comphelper::LibreOfficeKit::isActive(); for (const auto& rStyle : m_aAllStyles) { - VclPtr<VirtualDevice> pImg = bNeedInsertPreview ? GetCachedPreview(rStyle) : nullptr; - m_xStylesView->append(rStyle.first, rStyle.second, pImg); + if (bNeedInsertPreview) + { + BitmapEx aPreview = GetCachedPreview(rStyle); + m_xStylesView->append(rStyle.first, rStyle.second, &aPreview); + } + else + m_xStylesView->append(rStyle.first, rStyle.second, nullptr); } m_xStylesView->thaw(); } diff --git a/svx/source/tbxctrls/fontworkgallery.cxx b/svx/source/tbxctrls/fontworkgallery.cxx index 7c8f2b789525..e1b1e1baad7f 100644 --- a/svx/source/tbxctrls/fontworkgallery.cxx +++ b/svx/source/tbxctrls/fontworkgallery.cxx @@ -100,7 +100,7 @@ void FontWorkGalleryDialog::initFavorites(sal_uInt16 nThemeId) if (GalleryExplorer::GetSdrObj(nThemeId, nModelPos, pModel, &aThumb) && !aThumb.IsEmpty()) { - VclPtr< VirtualDevice > pVDev = VclPtr<VirtualDevice>::Create(); + ScopedVclPtrInstance< VirtualDevice > pVDev; const Point aNull(0, 0); if (pVDev->GetDPIScaleFactor() > 1) @@ -117,7 +117,7 @@ void FontWorkGalleryDialog::initFavorites(sal_uInt16 nThemeId) pVDev->DrawCheckered(aNull, aSize, nLen, aW, aG); pVDev->DrawBitmapEx(aNull, aThumb); - maFavoritesHorizontal.emplace_back(pVDev); + maFavoritesHorizontal.emplace_back(pVDev->GetBitmapEx(Point(0,0), aSize)); } } @@ -142,7 +142,7 @@ void FontWorkGalleryDialog::fillFavorites(sal_uInt16 nThemeId) { OUString sId = OUString::number(static_cast<sal_uInt16>(nFavorite)); maIdToTitleMap.emplace(sId, aTitles.at(nFavorite - 1)); - maCtlFavorites->insert(-1, nullptr, &sId, maFavoritesHorizontal[nFavorite - 1], nullptr); + maCtlFavorites->insert(-1, nullptr, &sId, &maFavoritesHorizontal[nFavorite - 1], nullptr); maCtlFavorites->set_item_accessible_name(maCtlFavorites->n_children() - 1, aTitles.at(nFavorite -1)); } diff --git a/vcl/inc/jsdialog/jsdialogbuilder.hxx b/vcl/inc/jsdialog/jsdialogbuilder.hxx index 23c2cc1b8abd..18df577e78b5 100644 --- a/vcl/inc/jsdialog/jsdialogbuilder.hxx +++ b/vcl/inc/jsdialog/jsdialogbuilder.hxx @@ -741,8 +741,8 @@ public: virtual void insert(int pos, const OUString* pStr, const OUString* pId, const OUString* pIconName, weld::TreeIter* pRet) override; - virtual void insert(int pos, const OUString* pStr, const OUString* pId, - const VirtualDevice* pIcon, weld::TreeIter* pRet) override; + virtual void insert(int pos, const OUString* pStr, const OUString* pId, const BitmapEx* pIcon, + weld::TreeIter* pRet) override; virtual void insert_separator(int pos, const OUString* pId) override; diff --git a/vcl/inc/qt5/QtInstanceIconView.hxx b/vcl/inc/qt5/QtInstanceIconView.hxx index 274d92ab8886..8cff84249a33 100644 --- a/vcl/inc/qt5/QtInstanceIconView.hxx +++ b/vcl/inc/qt5/QtInstanceIconView.hxx @@ -31,8 +31,8 @@ public: virtual void insert(int nPos, const OUString* pStr, const OUString* pId, const OUString* pIconName, weld::TreeIter* pRet) override; - virtual void insert(int nPos, const OUString* pStr, const OUString* pId, - const VirtualDevice* pIcon, weld::TreeIter* pRet) override; + virtual void insert(int nPos, const OUString* pStr, const OUString* pId, const BitmapEx* pIcon, + weld::TreeIter* pRet) override; virtual void insert_separator(int pos, const OUString* pId) override; diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx index a057e67f96fa..3f9d3238c7c1 100644 --- a/vcl/inc/salvtables.hxx +++ b/vcl/inc/salvtables.hxx @@ -1942,8 +1942,8 @@ public: virtual void insert(int pos, const OUString* pStr, const OUString* pId, const OUString* pIconName, weld::TreeIter* pRet) override; - virtual void insert(int pos, const OUString* pStr, const OUString* pId, - const VirtualDevice* pIcon, weld::TreeIter* pRet) override; + virtual void insert(int pos, const OUString* pStr, const OUString* pId, const BitmapEx* pIcon, + weld::TreeIter* pRet) override; virtual void insert_separator(int pos, const OUString* pId) override; diff --git a/vcl/jsdialog/jsdialogbuilder.cxx b/vcl/jsdialog/jsdialogbuilder.cxx index 219e72c2b98b..b54ecf9855be 100644 --- a/vcl/jsdialog/jsdialogbuilder.cxx +++ b/vcl/jsdialog/jsdialogbuilder.cxx @@ -1887,8 +1887,8 @@ void JSIconView::insert(int pos, const OUString* pStr, const OUString* pId, sendUpdate(); } -void JSIconView::insert(int pos, const OUString* pStr, const OUString* pId, - const VirtualDevice* pIcon, weld::TreeIter* pRet) +void JSIconView::insert(int pos, const OUString* pStr, const OUString* pId, const BitmapEx* pIcon, + weld::TreeIter* pRet) { SalInstanceIconView::insert(pos, pStr, pId, pIcon, pRet); sendUpdate(); diff --git a/vcl/qt5/QtInstanceIconView.cxx b/vcl/qt5/QtInstanceIconView.cxx index d943b508652d..041041584f43 100644 --- a/vcl/qt5/QtInstanceIconView.cxx +++ b/vcl/qt5/QtInstanceIconView.cxx @@ -55,7 +55,7 @@ void QtInstanceIconView::insert(int, const OUString*, const OUString*, const OUS } void QtInstanceIconView::insert(int nPos, const OUString* pStr, const OUString* pId, - const VirtualDevice* pIcon, weld::TreeIter* pRet) + const BitmapEx* pIcon, weld::TreeIter* pRet) { assert(!pRet && "Support for pRet param not implemented yet"); (void)pRet; @@ -76,7 +76,7 @@ void QtInstanceIconView::insert(int nPos, const OUString* pStr, const OUString* pItem->setIcon(QIcon(toQPixmap(*pIcon))); // set list view icon size to avoid downscaling const QSize aIconSize - = m_pListView->iconSize().expandedTo(toQSize(pIcon->GetOutputSizePixel())); + = m_pListView->iconSize().expandedTo(toQSize(pIcon->GetSizePixel())); m_pListView->setIconSize(aIconSize); } diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx index 8c94778ae86f..9860a5224a8e 100644 --- a/vcl/source/app/salvtables.cxx +++ b/vcl/source/app/salvtables.cxx @@ -5494,7 +5494,7 @@ void SalInstanceIconView::insert(int pos, const OUString* pStr, const OUString* } void SalInstanceIconView::insert(int pos, const OUString* pStr, const OUString* pId, - const VirtualDevice* pIcon, weld::TreeIter* pRet) + const BitmapEx* pIcon, weld::TreeIter* pRet) { disable_notify_events(); auto nInsertPos = pos == -1 ? TREELIST_APPEND : pos; @@ -5510,9 +5510,7 @@ void SalInstanceIconView::insert(int pos, const OUString* pStr, const OUString* SvTreeListEntry* pEntry = new SvTreeListEntry; if (pIcon) { - const Point aNull(0, 0); - const Size aSize = pIcon->GetOutputSize(); - Image aImage(pIcon->GetBitmapEx(aNull, aSize)); + Image aImage(*pIcon); pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aImage, aImage, false)); } else diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index df4594db17ff..f000864d082e 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -4937,6 +4937,14 @@ namespace return pRet; } + GdkPixbuf* getPixbuf(const BitmapEx& rBitmap) + { + ScopedVclPtr<VirtualDevice> pVDevice(VclPtr<VirtualDevice>::Create()); + pVDevice->SetOutputSizePixel(rBitmap.GetSizePixel()); + pVDevice->DrawBitmapEx(Point(0,0), rBitmap); + return getPixbuf(*pVDevice); + } + #if GTK_CHECK_VERSION(4, 0, 0) cairo_surface_t* render_paintable_to_surface(GdkPaintable *paintable, int nWidth, int nHeight) { @@ -17122,7 +17130,7 @@ private: } } - void insert_item(GtkTreeIter& iter, int pos, const OUString* pId, const OUString* pText, const VirtualDevice* pIcon) + void insert_item(GtkTreeIter& iter, int pos, const OUString* pId, const OUString* pText, const BitmapEx* pIcon) { // m_nTextCol may be -1, so pass it last, to not terminate the sequence before the Id value gtk_tree_store_insert_with_values(m_pTreeStore, &iter, nullptr, pos, @@ -17324,7 +17332,7 @@ public: enable_notify_events(); } - virtual void insert(int pos, const OUString* pText, const OUString* pId, const VirtualDevice* pIcon, weld::TreeIter* pRet) override + virtual void insert(int pos, const OUString* pText, const OUString* pId, const BitmapEx* pIcon, weld::TreeIter* pRet) override { disable_notify_events(); GtkTreeIter iter;