include/vcl/glyphitemcache.hxx | 69 ++++++++++++++++++++++++++++++++++++++++ sc/source/ui/view/output2.cxx | 55 +++---------------------------- vcl/source/gdi/impglyphitem.cxx | 46 ++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 49 deletions(-)
New commits: commit 89fb3f7e87fd7ab9312bc43dffea842ffc34b140 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Fri Mar 11 17:48:41 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Mon Mar 14 08:38:09 2022 +0100 cache also failures in SalLayoutGlyphsCache This is what 3f69ec9ab4236de13d229f675943123aeb42ea29 did in Writer. Change-Id: I40fb49ce83fd24f16050318c523d87603300b06d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131392 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx index 0d8c2241a21e..1fefe68994d2 100644 --- a/vcl/source/gdi/impglyphitem.cxx +++ b/vcl/source/gdi/impglyphitem.cxx @@ -99,8 +99,15 @@ SalLayoutGlyphsCache::GetLayoutGlyphs(const OUString& text, VclPtr<OutputDevice> { const CachedGlyphsKey key(text, outputDevice); auto it = mCachedGlyphs.find(key); - if (it != mCachedGlyphs.end() && it->second.IsValid()) - return &it->second; + if (it != mCachedGlyphs.end()) + { + if (it->second.IsValid()) + return &it->second; + // Do not try to create the layout here. If a cache item exists, it's already + // been attempted and the layout was invalid (this happens with MultiSalLayout). + // So in that case this is a cached failure. + return nullptr; + } std::unique_ptr<SalLayout> layout = outputDevice->ImplLayout( text, 0, text.getLength(), Point(0, 0), 0, {}, SalLayoutFlags::GlyphItemsOnly); if (layout) commit 3e3ef58be1c27e0ac32b0b5694f673f603d23224 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Fri Mar 11 17:47:40 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Mon Mar 14 08:37:53 2022 +0100 move cache for SalLayoutGlyph's from Calc to VCL For reuse later. Change-Id: I43479148a8312a36e56f267435e77acc8bf9bd35 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131390 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/include/vcl/glyphitemcache.hxx b/include/vcl/glyphitemcache.hxx new file mode 100644 index 000000000000..8afc8da0bae6 --- /dev/null +++ b/include/vcl/glyphitemcache.hxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_GLYPHITEMCACHE_HXX +#define INCLUDED_VCL_GLYPHITEMCACHE_HXX + +#include <sal/types.h> +#include <vcl/dllapi.h> + +#include <o3tl/lru_map.hxx> +#include <o3tl/hash_combine.hxx> +#include <vcl/glyphitem.hxx> + +/** +A cache for SalLayoutGlyphs objects. + +Allows caching for OutputDevice::DrawText() and similar calls. Pass the text and the output device +for the call to OutputDevice::ImplLayout(). Items are cached per output device and its font. +If something more changes, call clear(). +*/ +class VCL_DLLPUBLIC SalLayoutGlyphsCache final +{ +public: + SalLayoutGlyphsCache(int size = 1000) + : mCachedGlyphs(size) + { + } + const SalLayoutGlyphs* GetLayoutGlyphs(const OUString& text, + VclPtr<OutputDevice> outputDevice) const; + void clear() { mCachedGlyphs.clear(); } + +private: + struct CachedGlyphsKey + { + OUString text; + VclPtr<OutputDevice> outputDevice; + size_t hashValue; + CachedGlyphsKey(const OUString& t, const VclPtr<OutputDevice>& dev); + bool operator==(const CachedGlyphsKey& other) const; + }; + struct CachedGlyphsHash + { + size_t operator()(const CachedGlyphsKey& key) const { return key.hashValue; } + }; + mutable o3tl::lru_map<CachedGlyphsKey, SalLayoutGlyphs, CachedGlyphsHash> mCachedGlyphs; + + SalLayoutGlyphsCache(const SalLayoutGlyphsCache&) = delete; + SalLayoutGlyphsCache& operator=(const SalLayoutGlyphsCache&) = delete; +}; + +#endif // INCLUDED_VCL_GLYPHITEMCACHE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/view/output2.cxx b/sc/source/ui/view/output2.cxx index ab8e08c9d06f..0c394b0f7945 100644 --- a/sc/source/ui/view/output2.cxx +++ b/sc/source/ui/view/output2.cxx @@ -54,6 +54,7 @@ #include <vcl/settings.hxx> #include <vcl/glyphitem.hxx> #include <vcl/vcllayout.hxx> +#include <vcl/glyphitemcache.hxx> #include <sal/log.hxx> #include <unotools/charclass.hxx> #include <osl/diagnose.h> @@ -120,19 +121,7 @@ class ScDrawStringsVars tools::Long nExpWidth; ScRefCellValue maLastCell; - struct CachedGlyphsKey - { - OUString text; - VclPtr<OutputDevice> outputDevice; - size_t hashValue; - CachedGlyphsKey( const OUString& t, const VclPtr<OutputDevice>& dev ); - bool operator==( const CachedGlyphsKey& other ) const; - }; - struct CachedGlyphsHash - { - size_t operator()( const CachedGlyphsKey& key ) const { return key.hashValue; } - }; - mutable o3tl::lru_map<CachedGlyphsKey, SalLayoutGlyphs, CachedGlyphsHash> mCachedGlyphs; + mutable SalLayoutGlyphsCache mCachedGlyphs; sal_uLong nValueFormat; bool bLineBreak; bool bRepeat; @@ -198,7 +187,10 @@ public: // ScOutputData::LayoutStrings() usually triggers a number of calls that require // to lay out the text, which is relatively slow, so cache that operation. - const SalLayoutGlyphs* GetLayoutGlyphs(const OUString& rString) const; + const SalLayoutGlyphs* GetLayoutGlyphs(const OUString& rString) const + { + return mCachedGlyphs.GetLayoutGlyphs(rString, pOutput->pFmtDevice); + } private: tools::Long GetMaxDigitWidth(); // in logic units @@ -225,7 +217,6 @@ ScDrawStringsVars::ScDrawStringsVars(ScOutputData* pData, bool bPTL) : nSignWidth( 0 ), nDotWidth( 0 ), nExpWidth( 0 ), - mCachedGlyphs( 1000 ), nValueFormat( 0 ), bLineBreak ( false ), bRepeat ( false ), @@ -787,40 +778,6 @@ tools::Long ScDrawStringsVars::GetExpWidth() return nExpWidth; } -inline ScDrawStringsVars::CachedGlyphsKey::CachedGlyphsKey( const OUString& t, const VclPtr<OutputDevice>& d ) - : text( t ) - , outputDevice( d ) -{ - hashValue = 0; - o3tl::hash_combine( hashValue, outputDevice.get()); - SvMemoryStream stream; - WriteFont( stream, outputDevice->GetFont()); - o3tl::hash_combine( hashValue, static_cast<const char*>(stream.GetData()), stream.GetSize()); - o3tl::hash_combine( hashValue, text ); -} - -inline bool ScDrawStringsVars::CachedGlyphsKey::operator==( const CachedGlyphsKey& other ) const -{ - return hashValue == other.hashValue && outputDevice == other.outputDevice && text == other.text; -} - -const SalLayoutGlyphs* ScDrawStringsVars::GetLayoutGlyphs(const OUString& rString) const -{ - const CachedGlyphsKey key( rString, pOutput->pFmtDevice ); - auto it = mCachedGlyphs.find( key ); - if( it != mCachedGlyphs.end() && it->second.IsValid()) - return &it->second; - std::unique_ptr<SalLayout> layout = pOutput->pFmtDevice->ImplLayout( rString, 0, rString.getLength(), - Point( 0, 0 ), 0, {}, SalLayoutFlags::GlyphItemsOnly ); - if( layout ) - { - mCachedGlyphs.insert( std::make_pair( key, layout->GetGlyphs())); - assert(mCachedGlyphs.find( key ) == mCachedGlyphs.begin()); // newly inserted item is first - return &mCachedGlyphs.begin()->second; - } - return nullptr; -} - tools::Long ScDrawStringsVars::GetFmtTextWidth( const OUString& rString ) { return pOutput->pFmtDevice->GetTextWidth( rString, 0, -1, nullptr, GetLayoutGlyphs( rString )); diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx index 5464754bab56..0d8c2241a21e 100644 --- a/vcl/source/gdi/impglyphitem.cxx +++ b/vcl/source/gdi/impglyphitem.cxx @@ -18,6 +18,9 @@ */ #include <impglyphitem.hxx> +#include <vcl/glyphitemcache.hxx> +#include <vcl/vcllayout.hxx> +#include <tools/stream.hxx> SalLayoutGlyphs::SalLayoutGlyphs() {} @@ -91,4 +94,40 @@ bool SalLayoutGlyphsImpl::IsValid() const return true; } +const SalLayoutGlyphs* +SalLayoutGlyphsCache::GetLayoutGlyphs(const OUString& text, VclPtr<OutputDevice> outputDevice) const +{ + const CachedGlyphsKey key(text, outputDevice); + auto it = mCachedGlyphs.find(key); + if (it != mCachedGlyphs.end() && it->second.IsValid()) + return &it->second; + std::unique_ptr<SalLayout> layout = outputDevice->ImplLayout( + text, 0, text.getLength(), Point(0, 0), 0, {}, SalLayoutFlags::GlyphItemsOnly); + if (layout) + { + mCachedGlyphs.insert(std::make_pair(key, layout->GetGlyphs())); + assert(mCachedGlyphs.find(key) == mCachedGlyphs.begin()); // newly inserted item is first + return &mCachedGlyphs.begin()->second; + } + return nullptr; +} + +SalLayoutGlyphsCache::CachedGlyphsKey::CachedGlyphsKey(const OUString& t, + const VclPtr<OutputDevice>& d) + : text(t) + , outputDevice(d) +{ + hashValue = 0; + o3tl::hash_combine(hashValue, outputDevice.get()); + SvMemoryStream stream; + WriteFont(stream, outputDevice->GetFont()); + o3tl::hash_combine(hashValue, static_cast<const char*>(stream.GetData()), stream.GetSize()); + o3tl::hash_combine(hashValue, text); +} + +inline bool SalLayoutGlyphsCache::CachedGlyphsKey::operator==(const CachedGlyphsKey& other) const +{ + return hashValue == other.hashValue && outputDevice == other.outputDevice && text == other.text; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */