2022-03-11 17:47:40 +01:00
|
|
|
/* -*- 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 <vcl/glyphitem.hxx>
|
2022-05-16 13:11:17 +02:00
|
|
|
#include <vcl/metric.hxx>
|
2022-03-15 14:07:01 +01:00
|
|
|
#include <vcl/outdev.hxx>
|
|
|
|
#include <vcl/vclptr.hxx>
|
2022-03-11 17:47:40 +01:00
|
|
|
|
2022-04-08 21:17:58 +02:00
|
|
|
#include <optional>
|
|
|
|
|
2022-03-11 17:47:40 +01:00
|
|
|
/**
|
|
|
|
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:
|
2022-04-08 21:17:58 +02:00
|
|
|
// NOTE: The lifetime of the returned value is guaranteed only until the next call
|
|
|
|
// to any function in this class.
|
2023-12-31 20:20:00 +00:00
|
|
|
const SalLayoutGlyphs* GetLayoutGlyphs(const VclPtr<const OutputDevice>& outputDevice,
|
2022-04-08 21:17:58 +02:00
|
|
|
const OUString& text,
|
|
|
|
const vcl::text::TextLayoutCache* layoutCache = nullptr)
|
2022-03-15 14:07:01 +01:00
|
|
|
{
|
2022-04-07 12:25:09 +02:00
|
|
|
return GetLayoutGlyphs(outputDevice, text, 0, text.getLength(), 0, layoutCache);
|
2022-03-15 14:07:01 +01:00
|
|
|
}
|
2023-12-31 20:20:00 +00:00
|
|
|
const SalLayoutGlyphs* GetLayoutGlyphs(const VclPtr<const OutputDevice>& outputDevice,
|
2022-04-08 21:17:58 +02:00
|
|
|
const OUString& text, sal_Int32 nIndex, sal_Int32 nLen,
|
|
|
|
tools::Long nLogicWidth = 0,
|
|
|
|
const vcl::text::TextLayoutCache* layoutCache = nullptr);
|
2024-05-07 02:43:00 -06:00
|
|
|
const SalLayoutGlyphs* GetLayoutGlyphs(const VclPtr<const OutputDevice>& outputDevice,
|
|
|
|
const OUString& text, sal_Int32 nIndex, sal_Int32 nLen,
|
|
|
|
sal_Int32 nDrawMinCharPos, sal_Int32 nDrawEndCharPos,
|
|
|
|
tools::Long nLogicWidth = 0,
|
|
|
|
const vcl::text::TextLayoutCache* layoutCache = nullptr);
|
2022-05-31 16:50:34 +02:00
|
|
|
void clear();
|
2022-03-11 17:47:40 +01:00
|
|
|
|
2022-10-25 11:16:47 +02:00
|
|
|
/// Normally, we cannot cache glyphs when doing font fallback, because the font fallbacks
|
|
|
|
/// can cache during the lifetime of the cache, and they are not included in the cache key.
|
|
|
|
/// But during some processes, we can turn this on, as long as we remember to turn it off
|
|
|
|
/// at the end.
|
|
|
|
void SetCacheGlyphsWhenDoingFallbackFonts(bool bOK);
|
|
|
|
|
2022-04-07 12:06:27 +02:00
|
|
|
static SalLayoutGlyphsCache* self();
|
2024-10-21 14:36:51 +02:00
|
|
|
SalLayoutGlyphsCache(int size) // needs to be public for tools::DeleteOnDeinit
|
2022-04-07 12:06:27 +02:00
|
|
|
: mCachedGlyphs(size)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
tdf#162280 vcl: consider font family type for glyph caching
Open tdf105820-1.doc from crashtesting in a dbgutil build, save as PDF,
we assert in checkGlyphsEqual().
This is a problem since commit 6dfac38bacd449c64a13363797b56aff49cf8f52
(tdf#162072 vcl, fontconfig: consider font-family-generic for
substitute, 2024-07-18), because now the font name no longer determines
the fallback name alone, so 2 paragraphs may share the cached vcl-level
text layout, even if the underlying fallback font is different. One
would naively expect that in the SalLayoutGlyphsCache::CachedGlyphsKey
ctor, the fontMetric.GetFamilyType() already has the correct family
type, but it turns out that is always the default, and only
outputDevice->GetFont().GetFamilyType() has the up to date setting:
debug:12372:12372: SalLayoutGlyphsCache ctor: output device font family name is 'Verdana', output device font family type is roman, font metric family name is 'Verdana', font metric family type is 'swiss'
debug:12372:12372: SalLayoutGlyphsCache ctor: output device font family name is 'Verdana', output device font family type is swiss, font metric family name is 'Verdana', font metric family type is 'swiss'
Fix the problem by explicitly including the output device font family
type in the cache key.
Note that this only happens in practice if the same font is used in the
document with different family types, which is probably never the
intention of the user. E.g. Verdana is meant to be sans, a serif Verdana
is some weird corner-case.
Change-Id: Id6cc60809a35a3dcdc6e83122a559ddfbe5d5d0c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171280
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
2024-07-31 13:08:42 +02:00
|
|
|
struct CachedGlyphsKey
|
2022-03-11 17:47:40 +01:00
|
|
|
{
|
|
|
|
OUString text;
|
2022-03-15 14:07:01 +01:00
|
|
|
sal_Int32 index;
|
|
|
|
sal_Int32 len;
|
|
|
|
tools::Long logicWidth;
|
2022-05-16 13:11:17 +02:00
|
|
|
FontMetric fontMetric;
|
2022-04-28 08:38:17 +02:00
|
|
|
double fontScaleX;
|
|
|
|
double fontScaleY;
|
2022-04-11 12:43:05 +02:00
|
|
|
MapMode mapMode;
|
2022-04-07 12:07:02 +02:00
|
|
|
LanguageType digitLanguage;
|
2023-10-10 13:25:36 +02:00
|
|
|
vcl::text::ComplexTextLayoutFlags layoutMode;
|
|
|
|
bool rtl : 1;
|
|
|
|
bool disabledLigatures : 1; // because of fixed pitch
|
|
|
|
bool artificialItalic : 1;
|
|
|
|
bool artificialBold : 1;
|
2022-03-11 17:47:40 +01:00
|
|
|
size_t hashValue;
|
2022-07-12 15:52:29 +02:00
|
|
|
CachedGlyphsKey(const VclPtr<const OutputDevice>& dev, OUString t, sal_Int32 i, sal_Int32 l,
|
|
|
|
tools::Long w);
|
2022-03-11 17:47:40 +01:00
|
|
|
bool operator==(const CachedGlyphsKey& other) const;
|
|
|
|
};
|
tdf#162280 vcl: consider font family type for glyph caching
Open tdf105820-1.doc from crashtesting in a dbgutil build, save as PDF,
we assert in checkGlyphsEqual().
This is a problem since commit 6dfac38bacd449c64a13363797b56aff49cf8f52
(tdf#162072 vcl, fontconfig: consider font-family-generic for
substitute, 2024-07-18), because now the font name no longer determines
the fallback name alone, so 2 paragraphs may share the cached vcl-level
text layout, even if the underlying fallback font is different. One
would naively expect that in the SalLayoutGlyphsCache::CachedGlyphsKey
ctor, the fontMetric.GetFamilyType() already has the correct family
type, but it turns out that is always the default, and only
outputDevice->GetFont().GetFamilyType() has the up to date setting:
debug:12372:12372: SalLayoutGlyphsCache ctor: output device font family name is 'Verdana', output device font family type is roman, font metric family name is 'Verdana', font metric family type is 'swiss'
debug:12372:12372: SalLayoutGlyphsCache ctor: output device font family name is 'Verdana', output device font family type is swiss, font metric family name is 'Verdana', font metric family type is 'swiss'
Fix the problem by explicitly including the output device font family
type in the cache key.
Note that this only happens in practice if the same font is used in the
document with different family types, which is probably never the
intention of the user. E.g. Verdana is meant to be sans, a serif Verdana
is some weird corner-case.
Change-Id: Id6cc60809a35a3dcdc6e83122a559ddfbe5d5d0c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171280
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
2024-07-31 13:08:42 +02:00
|
|
|
|
|
|
|
private:
|
2022-03-11 17:47:40 +01:00
|
|
|
struct CachedGlyphsHash
|
|
|
|
{
|
|
|
|
size_t operator()(const CachedGlyphsKey& key) const { return key.hashValue; }
|
|
|
|
};
|
2024-02-08 14:15:37 +02:00
|
|
|
struct SAL_DLLPRIVATE GlyphsCost
|
2022-05-01 19:14:50 +02:00
|
|
|
{
|
|
|
|
size_t operator()(const SalLayoutGlyphs&) const;
|
|
|
|
};
|
|
|
|
typedef o3tl::lru_map<CachedGlyphsKey, SalLayoutGlyphs, CachedGlyphsHash,
|
|
|
|
std::equal_to<CachedGlyphsKey>, GlyphsCost>
|
|
|
|
GlyphsCache;
|
2022-04-08 21:17:58 +02:00
|
|
|
GlyphsCache mCachedGlyphs;
|
|
|
|
// Last temporary glyphs returned (pointer is returned, so the object needs to be kept somewhere).
|
|
|
|
std::optional<CachedGlyphsKey> mLastTemporaryKey;
|
|
|
|
SalLayoutGlyphs mLastTemporaryGlyphs;
|
2022-05-04 06:37:08 +02:00
|
|
|
// If set, info about the last call which wanted a substring of the full text.
|
|
|
|
std::optional<CachedGlyphsKey> mLastSubstringKey;
|
2022-10-25 11:16:47 +02:00
|
|
|
bool mbCacheGlyphsWhenDoingFallbackFonts = false;
|
2022-03-11 17:47:40 +01:00
|
|
|
|
|
|
|
SalLayoutGlyphsCache(const SalLayoutGlyphsCache&) = delete;
|
|
|
|
SalLayoutGlyphsCache& operator=(const SalLayoutGlyphsCache&) = delete;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif // INCLUDED_VCL_GLYPHITEMCACHE_HXX
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|