sw/source/core/inc/fntcache.hxx     |   23 ++----
 sw/source/core/txtnode/fntcache.cxx |  136 +++++++++++++++++++++++++-----------
 2 files changed, 103 insertions(+), 56 deletions(-)

New commits:
commit 3f69ec9ab4236de13d229f675943123aeb42ea29
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Thu Mar 11 15:34:41 2021 +0100
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Wed Mar 17 22:48:45 2021 +0100

    improve font caching in SwFntObj
    
    The code previously cached only SalGlyphItems, but such caching
    fails if SalLayout::GetGlyphs() does not return valid glyphs,
    which is the case with MultiSalLayout. Worse, it not only fails,
    but layout is once computed for caching, that fails, and is computed
    a second time for actual use.
    
    This improved cache caches the result of GetTextWidth(), which
    itself improves the performance a bit, but it also allows caching
    the value for GetGlyph() not returning valid glyphs. Moreover this
    also caches failures to get valid glyphs from GetGlyphs().
    
    There are quite some calls to GetTextArray(), I didn't cache those,
    but it might be added if needed.
    
    Change-Id: Ia2589fb1b778f4f154c88f65d9906584284239da
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112588
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sw/source/core/inc/fntcache.hxx b/sw/source/core/inc/fntcache.hxx
index 61564de93e72..848ad3611c10 100644
--- a/sw/source/core/inc/fntcache.hxx
+++ b/sw/source/core/inc/fntcache.hxx
@@ -60,19 +60,9 @@ void SwClearFntCacheTextGlyphs();
 extern SwFntCache *pFntCache;
 extern SwFntObj *pLastFont;
 
-/**
- * Defines a substring on a given output device, to be used as an std::map<>
- * key.
- */
-struct SwTextGlyphsKey
-{
-    VclPtr<OutputDevice> m_pOutputDevice;
-    OUString m_aText;
-    sal_Int32 m_nIndex;
-    sal_Int32 m_nLength;
-
-};
+struct SwTextGlyphsKey;
 bool operator<(const SwTextGlyphsKey& l, const SwTextGlyphsKey& r);
+struct SwTextGlyphsData;
 
 class SwFntObj : public SwCacheObj
 {
@@ -95,8 +85,8 @@ class SwFntObj : public SwCacheObj
     bool m_bSymbol : 1;
     bool m_bPaintBlank : 1;
 
-    /// Cache of already calculated layout glyphs.
-    std::map<SwTextGlyphsKey, SalLayoutGlyphs> m_aTextGlyphs;
+    /// Cache of already calculated layout glyphs and text widths.
+    std::map<SwTextGlyphsKey, SwTextGlyphsData> m_aTextGlyphs;
 
     static tools::Long nPixWidth;
     static MapMode *pPixMap;
@@ -125,7 +115,10 @@ public:
     sal_uInt16   GetZoom() const { return m_nZoom; }
     sal_uInt16   GetPropWidth() const { return m_nPropWidth; }
     bool     IsSymbol() const { return m_bSymbol; }
-    std::map<SwTextGlyphsKey, SalLayoutGlyphs>& GetTextGlyphs() { return 
m_aTextGlyphs; }
+
+    tools::Long GetCachedTextWidth(const SwTextGlyphsKey& key, const 
vcl::TextLayoutCache* vclCache);
+    SalLayoutGlyphs* GetCachedSalLayoutGlyphs(const SwTextGlyphsKey& key);
+    void ClearCachedTextGlyphs();
 
     void   DrawText( SwDrawTextInfo &rInf );
     /// determine the TextSize (of the printer)
diff --git a/sw/source/core/txtnode/fntcache.cxx 
b/sw/source/core/txtnode/fntcache.cxx
index 5b8661b4cf5a..b0ed8eb4d72b 100644
--- a/sw/source/core/txtnode/fntcache.cxx
+++ b/sw/source/core/txtnode/fntcache.cxx
@@ -71,6 +71,28 @@ tools::Long SwFntObj::nPixWidth;
 MapMode* SwFntObj::pPixMap = nullptr;
 static vcl::DeleteOnDeinit< VclPtr<OutputDevice> > s_pFntObjPixOut( new 
VclPtr<OutputDevice> );
 
+/**
+ * Defines a substring on a given output device, to be used as an std::map<>
+ * key.
+ */
+struct SwTextGlyphsKey
+{
+    VclPtr<OutputDevice> m_pOutputDevice;
+    OUString m_aText;
+    sal_Int32 m_nIndex;
+    sal_Int32 m_nLength;
+
+};
+
+/**
+ * Glyphs and text width for the given SwTextGlyphsKey.
+ */
+struct SwTextGlyphsData
+{
+    SalLayoutGlyphs m_aTextGlyphs;
+    tools::Long m_nTextWidth = -1; // -1 = not computed yet
+};
+
 namespace
 {
 
@@ -93,36 +115,6 @@ tools::Long EvalGridWidthAdd( const SwTextGridItem *const 
pGrid, const SwDrawTex
     return nGridWidthAdd;
 }
 
-/**
- * Pre-calculates glyph items for the rendered subset of rKey's text, assuming
- * outdev state does not change between the outdev calls.
- */
-SalLayoutGlyphs* lcl_CreateLayout(const SwTextGlyphsKey& rKey, 
SalLayoutGlyphs& rTextGlyphs)
-{
-    // Use pre-calculated result.
-    if (rTextGlyphs.IsValid())
-        return &rTextGlyphs;
-
-    if (rKey.m_nIndex >= rKey.m_aText.getLength())
-        // Same as in OutputDevice::GetTextArray().
-        return nullptr;
-
-    // Calculate glyph items.
-    std::unique_ptr<SalLayout> pLayout
-        = rKey.m_pOutputDevice->ImplLayout(rKey.m_aText, rKey.m_nIndex, 
rKey.m_nLength, Point(0, 0), 0,
-                                         nullptr, 
SalLayoutFlags::GlyphItemsOnly);
-    if (!pLayout)
-        return nullptr;
-
-    const SalLayoutGlyphs* pGlyphs = pLayout->GetGlyphs();
-    if (!pGlyphs)
-        return nullptr;
-
-    // Remember the calculation result.
-    rTextGlyphs = *pGlyphs;
-
-    return &rTextGlyphs;
-}
 }
 
 bool operator<(const SwTextGlyphsKey& l, const SwTextGlyphsKey& r)
@@ -223,6 +215,72 @@ void SwFntObj::CreatePrtFont( const OutputDevice& rPrt )
 
 }
 
+/**
+ * Pre-calculates glyph items for the rendered subset of rKey's text, assuming
+ * outdev state does not change between the outdev calls.
+ */
+static SalLayoutGlyphs* lcl_CreateLayout(const SwTextGlyphsKey& rKey, 
std::map<SwTextGlyphsKey, SwTextGlyphsData>::iterator it)
+{
+    assert (!it->second.m_aTextGlyphs.IsValid());
+
+    if (rKey.m_nIndex >= rKey.m_aText.getLength())
+        // Same as in OutputDevice::GetTextArray().
+        return nullptr;
+
+    // Calculate glyph items.
+    std::unique_ptr<SalLayout> pLayout
+        = rKey.m_pOutputDevice->ImplLayout(rKey.m_aText, rKey.m_nIndex, 
rKey.m_nLength, Point(0, 0), 0,
+                                         nullptr, 
SalLayoutFlags::GlyphItemsOnly);
+    if (!pLayout)
+        return nullptr;
+
+    const SalLayoutGlyphs* pGlyphs = pLayout->GetGlyphs();
+    if (!pGlyphs)
+        return nullptr;
+
+    // Remember the calculation result.
+    it->second.m_aTextGlyphs = *pGlyphs;
+
+    return &it->second.m_aTextGlyphs;
+}
+
+SalLayoutGlyphs* SwFntObj::GetCachedSalLayoutGlyphs(const SwTextGlyphsKey& key)
+{
+    std::map<SwTextGlyphsKey, SwTextGlyphsData>::iterator it = 
m_aTextGlyphs.find(key);
+    if(it != m_aTextGlyphs.end())
+    {
+        if( it->second.m_aTextGlyphs.IsValid())
+            return &it->second.m_aTextGlyphs;
+        // 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;
+    }
+    it = m_aTextGlyphs.insert_or_assign( it, key, SwTextGlyphsData());
+    return lcl_CreateLayout(key, it);
+}
+
+tools::Long SwFntObj::GetCachedTextWidth(const SwTextGlyphsKey& key, const 
vcl::TextLayoutCache* vclCache)
+{
+    std::map<SwTextGlyphsKey, SwTextGlyphsData>::iterator it = 
m_aTextGlyphs.find(key);
+    if(it != m_aTextGlyphs.end() && it->second.m_nTextWidth >= 0)
+        return it->second.m_nTextWidth;
+    if(it == m_aTextGlyphs.end())
+    {
+        it = m_aTextGlyphs.insert_or_assign( it, key, SwTextGlyphsData());
+        lcl_CreateLayout(key, it);
+    }
+    it->second.m_nTextWidth = key.m_pOutputDevice->GetTextWidth(key.m_aText, 
key.m_nIndex, key.m_nLength, vclCache,
+        it->second.m_aTextGlyphs.IsValid() ? &it->second.m_aTextGlyphs : 
nullptr );
+    assert(it->second.m_nTextWidth >= 0);
+    return it->second.m_nTextWidth;
+}
+
+void SwFntObj::ClearCachedTextGlyphs()
+{
+    m_aTextGlyphs.clear();
+}
+
 /*
  *  returns whether we have to adjust the output font to resemble
  *  the formatting font
@@ -1472,7 +1530,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
         // get screen array
         std::unique_ptr<tools::Long[]> pScrArray(new 
tools::Long[sal_Int32(rInf.GetLen())]);
         SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), rInf.GetText(), 
sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) };
-        SalLayoutGlyphs* pGlyphs = lcl_CreateLayout(aGlyphsKey, 
m_aTextGlyphs[aGlyphsKey]);
+        SalLayoutGlyphs* pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey);
         rInf.GetOut().GetTextArray( rInf.GetText(), pScrArray.get(),
                         sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), 
nullptr, pGlyphs);
 
@@ -1487,7 +1545,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                     m_pPrinter->SetFont( *m_pPrtFont );
             }
             aGlyphsKey = SwTextGlyphsKey{ m_pPrinter, rInf.GetText(), 
sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) };
-            pGlyphs = lcl_CreateLayout(aGlyphsKey, m_aTextGlyphs[aGlyphsKey]);
+            pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey);
             m_pPrinter->GetTextArray(rInf.GetText(), pKernArray.get(),
                     sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), 
nullptr, pGlyphs);
         }
@@ -1826,7 +1884,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf )
                             ? (rInf.GetIdx() ? 1 : 0)
                             : sal_Int32(rInf.GetIdx());
                 aGlyphsKey = SwTextGlyphsKey{ &rInf.GetOut(), *pStr, nTmpIdx, 
nLen };
-                pGlyphs = lcl_CreateLayout(aGlyphsKey, 
m_aTextGlyphs[aGlyphsKey]);
+                pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey);
                 rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, 
pKernArray.get(),
                                              nTmpIdx , nLen, 
SalLayoutFlags::NONE, pGlyphs );
                 if (bBullet)
@@ -2061,10 +2119,7 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
         else
         {
             SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), rInf.GetText(), 
sal_Int32(rInf.GetIdx()), sal_Int32(nLn) };
-            SalLayoutGlyphs* pGlyphs = lcl_CreateLayout(aGlyphsKey, 
m_aTextGlyphs[aGlyphsKey]);
-            aTextSize.setWidth( rInf.GetOut().GetTextWidth( rInf.GetText(),
-                                   sal_Int32(rInf.GetIdx()), sal_Int32(nLn),
-                                                           rInf.GetVclCache(), 
pGlyphs) );
+            aTextSize.setWidth( GetCachedTextWidth(aGlyphsKey, 
rInf.GetVclCache()));
             rInf.SetKanaDiff( 0 );
         }
 
@@ -2098,7 +2153,7 @@ TextFrameIndex 
SwFntObj::GetModelPositionForViewPoint(SwDrawTextInfo &rInf)
         m_pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() );
         m_pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() );
         SwTextGlyphsKey aGlyphsKey{ m_pPrinter, rInf.GetText(), 
sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) };
-        SalLayoutGlyphs* pGlyphs = lcl_CreateLayout(aGlyphsKey, 
m_aTextGlyphs[aGlyphsKey]);
+        SalLayoutGlyphs* pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey);
         m_pPrinter->GetTextArray( rInf.GetText(), pKernArray.get(),
                 sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), nullptr, 
pGlyphs);
     }
@@ -2514,8 +2569,7 @@ TextFrameIndex SwFont::GetTextBreak(SwDrawTextInfo const 
& rInf, tools::Long nTe
             SwFntAccess aFntAccess(m_aSub[m_nActual].m_nFontCacheId, 
m_aSub[m_nActual].m_nFontIndex,
                                    &m_aSub[m_nActual], rInf.GetShell());
             SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), *pTmpText, 
sal_Int32(nTmpIdx), sal_Int32(nTmpLen) };
-            SalLayoutGlyphs* pGlyphs
-                = lcl_CreateLayout(aGlyphsKey, 
aFntAccess.Get()->GetTextGlyphs()[aGlyphsKey]);
+            SalLayoutGlyphs* pGlyphs = 
aFntAccess.Get()->GetCachedSalLayoutGlyphs(aGlyphsKey);
             nTextBreak = TextFrameIndex(rInf.GetOut().GetTextBreak(
                              *pTmpText, nTextWidth,
                              sal_Int32(nTmpIdx), sal_Int32(nTmpLen),
@@ -2713,7 +2767,7 @@ bool SwDrawTextInfo::ApplyAutoColor( vcl::Font* pFont )
 void SwClearFntCacheTextGlyphs()
 {
     for (SwFntObj* pFntObj = pFntCache->First(); pFntObj; pFntObj = 
SwFntCache::Next(pFntObj))
-        pFntObj->GetTextGlyphs().clear();
+        pFntObj->ClearCachedTextGlyphs();
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to