sc/source/ui/view/output2.cxx |   47 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 41 insertions(+), 6 deletions(-)

New commits:
commit d62ad3efe3c8778cfda00799f1cd7bb3349e0b75
Author:     Luboš Luňák <[email protected]>
AuthorDate: Tue Jan 19 18:58:25 2021 +0100
Commit:     Luboš Luňák <[email protected]>
CommitDate: Thu Jan 21 11:33:31 2021 +0100

    cache SalLayoutGlyphs in ScOutputData::LayoutStrings()
    
    OutputDevice::GetTextWidth() requires the layout, and DrawText()
    requires it as well. Moreover GetTextWidth() may be called multiple
    times (e.g. if the whole string doesn't fit the cell).
    Cache up to 1000 layouts, they get cleaned up after LayoutStrings(),
    and with larger cells there won't be that many of them, and with
    smaller cells they should generally contain short strings.
    
    Change-Id: I42defd275467078b2c02c7700ca9bbc2c6e65e15
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/109708
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <[email protected]>

diff --git a/sc/source/ui/view/output2.cxx b/sc/source/ui/view/output2.cxx
index 764919b9d37a..e7083ed2c45c 100644
--- a/sc/source/ui/view/output2.cxx
+++ b/sc/source/ui/view/output2.cxx
@@ -51,6 +51,8 @@
 #include <vcl/outdev.hxx>
 #include <vcl/pdfextoutdevdata.hxx>
 #include <vcl/settings.hxx>
+#include <vcl/glyphitem.hxx>
+#include <vcl/vcllayout.hxx>
 #include <sal/log.hxx>
 #include <unotools/charclass.hxx>
 #include <osl/diagnose.h>
@@ -74,6 +76,7 @@
 
 #include <memory>
 #include <vector>
+#include <o3tl/lru_map.hxx>
 
 #include <math.h>
 
@@ -113,6 +116,7 @@ class ScDrawStringsVars
     tools::Long                nExpWidth;
 
     ScRefCellValue      maLastCell;
+    mutable o3tl::lru_map<OUString, SalLayoutGlyphs> mCachedGlyphs;
     sal_uLong           nValueFormat;
     bool                bLineBreak;
     bool                bRepeat;
@@ -155,6 +159,7 @@ public:
     const OUString&         GetString() const        { return aString; }
     const Size&             GetTextSize() const      { return aTextSize; }
     tools::Long                    GetOriginalWidth() const { return 
nOriginalWidth; }
+    tools::Long             GetFmtTextWidth(const OUString& rString);
 
     // Get the effective number format, including formula result types.
     // This assumes that a formula cell has already been calculated.
@@ -175,6 +180,10 @@ public:
 
     bool    HasEditCharacters() const;
 
+    // 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;
+
 private:
     tools::Long        GetMaxDigitWidth();     // in logic units
     tools::Long        GetSignWidth();
@@ -200,6 +209,7 @@ ScDrawStringsVars::ScDrawStringsVars(ScOutputData* pData, 
bool bPTL) :
     nSignWidth( 0 ),
     nDotWidth( 0 ),
     nExpWidth( 0 ),
+    mCachedGlyphs( 1000 ),
     nValueFormat( 0 ),
     bLineBreak  ( false ),
     bRepeat     ( false ),
@@ -291,6 +301,7 @@ void ScDrawStringsVars::SetPattern(
     nSignWidth     = 0;
     nDotWidth      = 0;
     nExpWidth      = 0;
+    mCachedGlyphs.clear();
 
     pPattern = pNew;
     pCondSet = pSet;
@@ -445,6 +456,7 @@ void ScDrawStringsVars::SetPatternSimple( const 
ScPatternAttr* pNew, const SfxIt
     nSignWidth     = 0;
     nDotWidth      = 0;
     nExpWidth      = 0;
+    mCachedGlyphs.clear();
 
     // Is called, when the font variables do not change (!StringDiffer)
 
@@ -558,7 +570,7 @@ void ScDrawStringsVars::RepeatToFill( tools::Long nColWidth 
)
     if ( nRepeatPos == -1 || nRepeatPos > aString.getLength() )
         return;
 
-    tools::Long nCharWidth = 
pOutput->pFmtDevice->GetTextWidth(OUString(nRepeatChar));
+    tools::Long nCharWidth = GetFmtTextWidth(OUString(nRepeatChar));
 
     if ( nCharWidth < 1 || (bPixelToLogic && nCharWidth < 
pOutput->mpRefDevice->PixelToLogic(Size(1,0)).Width()) )
         return;
@@ -675,7 +687,7 @@ void ScDrawStringsVars::SetTextToWidthOrHash( 
ScRefCellValue& rCell, tools::Long
         aString = sTempOut;
     }
 
-    tools::Long nActualTextWidth = pOutput->pFmtDevice->GetTextWidth(aString);
+    tools::Long nActualTextWidth = GetFmtTextWidth(aString);
     if (nActualTextWidth > nWidth)
     {
         // Even after the decimal adjustment the text doesn't fit.  Give up.
@@ -693,7 +705,7 @@ void ScDrawStringsVars::SetAutoText( const OUString& 
rAutoText )
 
     OutputDevice* pRefDevice = pOutput->mpRefDevice;
     OutputDevice* pFmtDevice = pOutput->pFmtDevice;
-    aTextSize.setWidth( pFmtDevice->GetTextWidth( aString ) );
+    aTextSize.setWidth( GetFmtTextWidth( aString ) );
     aTextSize.setHeight( pFmtDevice->GetTextHeight() );
 
     if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == 
OUTDEV_PRINTER )
@@ -725,6 +737,7 @@ tools::Long ScDrawStringsVars::GetMaxDigitWidth()
     for (char i = 0; i < 10; ++i)
     {
         char cDigit = '0' + i;
+        // Do not cache this with GetFmtTextWidth(), nMaxDigitWidth is already 
cached.
         tools::Long n = pOutput->pFmtDevice->GetTextWidth(OUString(cDigit));
         nMaxDigitWidth = ::std::max(nMaxDigitWidth, n);
     }
@@ -759,11 +772,32 @@ tools::Long ScDrawStringsVars::GetExpWidth()
     return nExpWidth;
 }
 
+const SalLayoutGlyphs* ScDrawStringsVars::GetLayoutGlyphs(const OUString& 
rString) const
+{
+    auto it = mCachedGlyphs.find( rString );
+    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, nullptr, SalLayoutFlags::GlyphItemsOnly );
+    if( layout && layout->GetGlyphs())
+    {
+        mCachedGlyphs.insert( std::make_pair( rString, *layout->GetGlyphs()));
+        assert(mCachedGlyphs.find( rString ) == 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 ));
+}
+
 void ScDrawStringsVars::TextChanged()
 {
     OutputDevice* pRefDevice = pOutput->mpRefDevice;
     OutputDevice* pFmtDevice = pOutput->pFmtDevice;
-    aTextSize.setWidth( pFmtDevice->GetTextWidth( aString ) );
+    aTextSize.setWidth( GetFmtTextWidth( aString ) );
     aTextSize.setHeight( pFmtDevice->GetTextHeight() );
 
     if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == 
OUTDEV_PRINTER )
@@ -2043,7 +2077,7 @@ tools::Rectangle ScOutputData::LayoutStrings(bool 
bPixelToLogic, bool bPaint, co
                                         aShort = 
aShort.copy(nTextLen-nShortLen);
 
                                         // Adjust the text position after 
shortening of the string.
-                                        double fShortWidth = 
pFmtDevice->GetTextWidth(aShort);
+                                        double fShortWidth = 
aVars.GetFmtTextWidth(aShort);
                                         double fOffset = fTextWidth - 
fShortWidth;
                                         aDrawTextPos.Move(fOffset, 0);
                                     }
@@ -2082,7 +2116,8 @@ tools::Rectangle ScOutputData::LayoutStrings(bool 
bPixelToLogic, bool bPaint, co
                             else
                             {
                                 if (bPaint)
-                                    mpDev->DrawText(aDrawTextPos, aShort);
+                                    mpDev->DrawText(aDrawTextPos, aShort, 0, 
-1, nullptr, nullptr,
+                                        aVars.GetLayoutGlyphs(aShort));
                             }
                         }
 
_______________________________________________
Libreoffice-commits mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to