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.lunak@collabora.com>
This commit is contained in:
Luboš Luňák 2022-03-11 17:47:40 +01:00
parent ef82ccdda9
commit 3e3ef58be1
3 changed files with 114 additions and 49 deletions

View file

@ -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: */

View file

@ -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 ));

View file

@ -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: */