include/svx/SvxColorIconView.hxx | 2 + svx/source/tbxctrls/Palette.cxx | 10 ++++-- svx/source/tbxctrls/PaletteManager.cxx | 16 ++++++---- svx/source/tbxctrls/SvxColorIconView.cxx | 46 +++++++++++++++++-------------- 4 files changed, 43 insertions(+), 31 deletions(-)
New commits: commit 034380cbb364c44fbd8aa6dad858828f89ba80d8 Author: Andras Timar <[email protected]> AuthorDate: Fri Feb 20 17:12:34 2026 +0100 Commit: Caolán McNamara <[email protected]> CommitDate: Fri Feb 27 11:50:46 2026 +0100 color icon view: reuse single VirtualDevice per palette load Follow-up to commit c5f6227d8e71 (use ScopedVclPtr to avoid leaks). That fix ensures each per-color VirtualDevice is properly disposed, but still creates and destroys ~120 VDs per palette load — each one allocating a GDI DC + DIB section on Windows. Reuse a single VirtualDevice across the entire loop instead: create it once via createColorDevice(), redraw it for each color via drawColor(), and pass it to IconView::insert() which copies the bitmap immediately. This reduces GDI allocations from ~120 to 1 per palette population. Also removes the GetBitmapEx+Scale+DrawBitmapEx roundtrip from createColorVirtualDevice: the VD is now created at the correct DPI-scaled size from the start, eliminating an extra temporary GDI bitmap allocation per entry at HiDPI. Change-Id: I676cdf49cbd34a4a01b46f8ba516bf34a19ff23c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199894 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Mike Kaganski <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200590 Reviewed-by: Caolán McNamara <[email protected]> diff --git a/include/svx/SvxColorIconView.hxx b/include/svx/SvxColorIconView.hxx index bb7c8d9eb7c2..1ef4f20aa3a4 100644 --- a/include/svx/SvxColorIconView.hxx +++ b/include/svx/SvxColorIconView.hxx @@ -34,6 +34,8 @@ public: static void addEntriesForColorSet(weld::IconView& pIconView, const std::set<Color>& rColorSet, std::u16string_view rNamePrefix); + static VclPtr<VirtualDevice> createColorDevice(); + static void drawColor(VirtualDevice& rDev, const Color& rColor); static ScopedVclPtr<VirtualDevice> createColorVirtualDevice(const Color& rColor); }; diff --git a/svx/source/tbxctrls/Palette.cxx b/svx/source/tbxctrls/Palette.cxx index c06de53f9458..c01636c71dc8 100644 --- a/svx/source/tbxctrls/Palette.cxx +++ b/svx/source/tbxctrls/Palette.cxx @@ -57,10 +57,11 @@ void PaletteASE::LoadColorSet(weld::IconView& pIconView) { pIconView.clear(); int nIx = 0; + ScopedVclPtr<VirtualDevice> pVDev = SvxColorIconView::createColorDevice(); for (const auto& rColor : maColors) { - auto pColorVDev = SvxColorIconView::createColorVirtualDevice(rColor.m_aColor); - Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + SvxColorIconView::drawColor(*pVDev, rColor.m_aColor); + Bitmap aBmp = pVDev->GetBitmap(Point(), pVDev->GetOutputSizePixel()); OUString sColorName = rColor.m_aName; OUString sId = OUString::number(nIx); pIconView.insert(nIx, &sColorName, &sId, &aBmp, nullptr); @@ -335,10 +336,11 @@ void PaletteGPL::LoadColorSet(weld::IconView& pIconView) pIconView.clear(); int nIx = 0; + ScopedVclPtr<VirtualDevice> pVDev = SvxColorIconView::createColorDevice(); for (const auto& rColor : maColors) { - auto pColorVDev = SvxColorIconView::createColorVirtualDevice(rColor.m_aColor); - Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + SvxColorIconView::drawColor(*pVDev, rColor.m_aColor); + Bitmap aBmp = pVDev->GetBitmap(Point(), pVDev->GetOutputSizePixel()); OUString sColorName = rColor.m_aName; OUString sId = OUString::number(nIx); pIconView.insert(nIx, &sColorName, &sId, &aBmp, nullptr); diff --git a/svx/source/tbxctrls/PaletteManager.cxx b/svx/source/tbxctrls/PaletteManager.cxx index 7163c2cbcdc3..2e0e14849104 100644 --- a/svx/source/tbxctrls/PaletteManager.cxx +++ b/svx/source/tbxctrls/PaletteManager.cxx @@ -250,11 +250,12 @@ void PaletteManager::ReloadColorSet(weld::IconView &pIconView) pIconView.clear(); css::uno::Sequence< sal_Int32 > CustomColorList( officecfg::Office::Common::UserColors::CustomColor::get() ); css::uno::Sequence< OUString > CustomColorNameList( officecfg::Office::Common::UserColors::CustomColorName::get() ); + ScopedVclPtr<VirtualDevice> pVDev = SvxColorIconView::createColorDevice(); for (int i = 0; i < CustomColorList.getLength(); ++i) { Color aColor(ColorTransparency, CustomColorList[i]); - auto pColorVDev = SvxColorIconView::createColorVirtualDevice(aColor); - Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + SvxColorIconView::drawColor(*pVDev, aColor); + Bitmap aBmp = pVDev->GetBitmap(Point(), pVDev->GetOutputSizePixel()); OUString sId = OUString::number(i); OUString sColorName = CustomColorNameList[i]; pIconView.insert(i, &sColorName, &sId, &aBmp, nullptr); @@ -277,15 +278,15 @@ void PaletteManager::ReloadColorSet(weld::IconView &pIconView) moThemePaletteCollection = aThemeColorManager.generate(); // Each row is one effect type (no effect + each type). + ScopedVclPtr<VirtualDevice> pVDev = SvxColorIconView::createColorDevice(); for (size_t nEffect : {0, 1, 2, 3, 4, 5}) { // Each column is one color type. for (auto const& rColorData : moThemePaletteCollection->maColors) { auto const& rEffect = rColorData.maEffects[nEffect]; - Color aColor = rEffect.maColor; - auto pColorVDev = SvxColorIconView::createColorVirtualDevice(aColor); - Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + SvxColorIconView::drawColor(*pVDev, rEffect.maColor); + Bitmap aBmp = pVDev->GetBitmap(Point(), pVDev->GetOutputSizePixel()); OUString sColorName = rEffect.maColorName; OUString sId = OUString::number(nItemId); pIconView.insert(nItemId, &sColorName, &sId, &aBmp, nullptr); @@ -321,11 +322,12 @@ void PaletteManager::ReloadRecentColorSet(weld::IconView& pIconView) css::uno::Sequence< OUString > ColorNamelist(officecfg::Office::Common::UserColors::RecentColorName::get()); int nIx = 0; const bool bHasColorNames = Colorlist.getLength() == ColorNamelist.getLength(); + ScopedVclPtr<VirtualDevice> pVDev = SvxColorIconView::createColorDevice(); for (int i = 0; i < Colorlist.getLength(); ++i) { Color aColor(ColorTransparency, Colorlist[i]); - auto pColorVDev = SvxColorIconView::createColorVirtualDevice(aColor); - Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + SvxColorIconView::drawColor(*pVDev, aColor); + Bitmap aBmp = pVDev->GetBitmap(Point(), pVDev->GetOutputSizePixel()); OUString sColorName = bHasColorNames ? ColorNamelist[i] : ("#" + aColor.AsRGBHexString().toAsciiUpperCase()); maRecentColors.emplace_back(aColor, sColorName); OUString sId = OUString::number(nIx); diff --git a/svx/source/tbxctrls/SvxColorIconView.cxx b/svx/source/tbxctrls/SvxColorIconView.cxx index 66b23eb8cdbd..96e102a14fd9 100644 --- a/svx/source/tbxctrls/SvxColorIconView.cxx +++ b/svx/source/tbxctrls/SvxColorIconView.cxx @@ -42,6 +42,7 @@ void SvxColorIconView::addEntriesForXColorList(weld::IconView& pIconView, sal_uInt32 nStartIndex) { const sal_uInt32 nColorCount(rXColorList.Count()); + ScopedVclPtr<VirtualDevice> pVDev = createColorDevice(); for (sal_uInt32 nIndex(0); nIndex < nColorCount; nIndex++, nStartIndex++) { @@ -49,8 +50,8 @@ void SvxColorIconView::addEntriesForXColorList(weld::IconView& pIconView, if (pEntry) { - auto pColorVDev = createColorVirtualDevice(pEntry->GetColor()); - Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + drawColor(*pVDev, pEntry->GetColor()); + Bitmap aBmp = pVDev->GetBitmap(Point(), pVDev->GetOutputSizePixel()); OUString sColorName = pEntry->GetName(); OUString sId = OUString::number(nIndex); pIconView.insert(nIndex, &sColorName, &sId, &aBmp, nullptr); @@ -67,12 +68,14 @@ void SvxColorIconView::addEntriesForColorSet(weld::IconView& pIconView, std::u16string_view rNamePrefix) { sal_uInt32 nStartIndex = 0; + ScopedVclPtr<VirtualDevice> pVDev = createColorDevice(); + if (!rNamePrefix.empty()) { for (const auto& rColor : rColorSet) { - auto pColorVDev = createColorVirtualDevice(rColor); - Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + drawColor(*pVDev, rColor); + Bitmap aBmp = pVDev->GetBitmap(Point(), pVDev->GetOutputSizePixel()); OUString sName = OUString::Concat(rNamePrefix) + OUString::number(nStartIndex); OUString sId = OUString::number(nStartIndex); pIconView.insert(nStartIndex, &sName, &sId, &aBmp, nullptr); @@ -83,8 +86,8 @@ void SvxColorIconView::addEntriesForColorSet(weld::IconView& pIconView, { for (const auto& rColor : rColorSet) { - auto pColorVDev = createColorVirtualDevice(rColor); - Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + drawColor(*pVDev, rColor); + Bitmap aBmp = pVDev->GetBitmap(Point(), pVDev->GetOutputSizePixel()); OUString sId = OUString::number(nStartIndex); OUString sName = u""_ustr; pIconView.insert(nStartIndex, &sName, &sId, &aBmp, nullptr); @@ -93,25 +96,28 @@ void SvxColorIconView::addEntriesForColorSet(weld::IconView& pIconView, } } -ScopedVclPtr<VirtualDevice> SvxColorIconView::createColorVirtualDevice(const Color& rColor) +VclPtr<VirtualDevice> SvxColorIconView::createColorDevice() { const sal_uInt32 nEdgeLength = getEntryEdgeLength() - 2; VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create(); - pVDev->SetOutputSizePixel(Size(nEdgeLength, nEdgeLength)); - - // Fill with the color - pVDev->SetFillColor(rColor); - pVDev->SetLineColor(COL_BLACK); - pVDev->DrawRect(tools::Rectangle(Point(0, 0), Size(nEdgeLength, nEdgeLength))); + const sal_Int32 nScaleFactor = pVDev->GetDPIScaleFactor(); + const sal_uInt32 nScaledEdge = nEdgeLength * nScaleFactor; + pVDev->SetOutputSizePixel(Size(nScaledEdge, nScaledEdge)); + return pVDev; +} - Bitmap aPreviewBitmap = pVDev->GetBitmap(Point(0, 0), Size(nEdgeLength, nEdgeLength)); - const Point aNull(0, 0); - if (pVDev->GetDPIScaleFactor() > 1) - aPreviewBitmap.Scale(pVDev->GetDPIScaleFactor(), pVDev->GetDPIScaleFactor()); - const Size aSize(aPreviewBitmap.GetSizePixel()); - pVDev->SetOutputSizePixel(aSize); - pVDev->DrawBitmap(aNull, aPreviewBitmap); +void SvxColorIconView::drawColor(VirtualDevice& rDev, const Color& rColor) +{ + const Size aSize = rDev.GetOutputSizePixel(); + rDev.SetFillColor(rColor); + rDev.SetLineColor(COL_BLACK); + rDev.DrawRect(tools::Rectangle(Point(0, 0), aSize)); +} +ScopedVclPtr<VirtualDevice> SvxColorIconView::createColorVirtualDevice(const Color& rColor) +{ + VclPtr<VirtualDevice> pVDev = createColorDevice(); + drawColor(*pVDev, rColor); return pVDev; }
