[Libreoffice-commits] core.git: include/vcl sw/source vcl/generic vcl/inc vcl/source

Michael Stahl mstahl at redhat.com
Sat Mar 28 08:35:06 PDT 2015


 include/vcl/outdev.hxx              |   20 +++++++----
 sw/source/core/inc/drawfont.hxx     |   16 +++++++--
 sw/source/core/text/guess.cxx       |    7 ++-
 sw/source/core/text/inftxt.cxx      |   35 +++++++++++++++----
 sw/source/core/text/inftxt.hxx      |   25 ++++++++++++--
 sw/source/core/text/porfld.cxx      |    4 ++
 sw/source/core/text/pormulti.cxx    |    3 +
 sw/source/core/txtnode/fntcache.cxx |    7 ++-
 vcl/generic/glyphs/gcach_layout.cxx |   64 +++++++++++++++++++++++++++++++-----
 vcl/inc/generic/glyphcache.hxx      |    3 +
 vcl/inc/sallayout.hxx               |   12 ++++++
 vcl/source/gdi/sallayout.cxx        |   10 +++++
 vcl/source/outdev/text.cxx          |   53 +++++++++++++++++++++++------
 13 files changed, 213 insertions(+), 46 deletions(-)

New commits:
commit 1efe5fe38031f7bc23150c35e4c68940621a1d5b
Author: Michael Stahl <mstahl at redhat.com>
Date:   Tue Mar 3 15:26:10 2015 +0100

    tdf#89666: vcl: speed up HbLayoutEngine with cache in SwTxtFormatInfo
    
    When a SwTxtFormatInfo is created to format a paragraph, pre-compute the
    result of vcl::ScriptRun::next() and cache it for future calls to
    OutputDevice::GetTextBreak() and GetTextWidth().
    
    This requires adapting a bunch of methods to pass the additional
    parameter, and some classes to backup and restore the cache when they
    replace the text of the SwTxtFormatInfo.
    
    There is some code in vcl OutputDevice::ImplPrepareLayoutArgs()
    to modify the passed string and replace digits depending on
    "meTextLanguage" member; try to set it to the correct value when
    creating the layout cache (unfortunately it's not possible if the user
    sets the CTL Numerals config to the non-default "Context" value).
    
    Another issue is the check in OutputDevice::ImplLayout() if there is
    a mpConversion member on the font; apparently this is used to translate
    between different Symbol fonts, so not very important; just ignore the
    cache in this case.
    
    This reduces vcl::ScriptRun::next() from 11 to 0.36 billion callgrind
    cycles when built with GCC 4.9.2 -m32 -Os (which is still 16% of the
    formatting).
    
    Change-Id: I61fb8530333f2e7a9199f767c00cf2181ba49951
    Reviewed-on: https://gerrit.libreoffice.org/14732
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index 7911b66..47c77ad 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -140,6 +140,7 @@ namespace vcl
     class ExtOutDevData;
     class ITextLayout;
     struct FontCapabilities;
+    class TextLayoutCache;
 }
 
 // OutputDevice-Types
@@ -1066,7 +1067,8 @@ public:
 
         See also GetTextBoundRect() for more explanation + code examples.
     */
-    long                        GetTextWidth( const OUString& rStr, sal_Int32 nIndex = 0, sal_Int32 nLen = -1 ) const;
+    long                        GetTextWidth( const OUString& rStr, sal_Int32 nIndex = 0, sal_Int32 nLen = -1,
+                                  vcl::TextLayoutCache const* = nullptr) const;
 
     /** Height where any character of the current font fits; in logic coordinates.
 
@@ -1081,7 +1083,8 @@ public:
                                                sal_Int32 nLen = -1,
                                                int flags = 0);
     long                        GetTextArray( const OUString& rStr, long* pDXAry = NULL,
-                                              sal_Int32 nIndex = 0, sal_Int32 nLen = -1 ) const;
+                                              sal_Int32 nIndex = 0, sal_Int32 nLen = -1,
+                                              vcl::TextLayoutCache const* = nullptr) const;
 
     bool                        GetCaretPositions( const OUString&, long* pCaretXArray,
                                               sal_Int32 nIndex, sal_Int32 nLen,
@@ -1092,11 +1095,14 @@ public:
                                                  sal_Int32 nIndex = 0, sal_Int32 nLen = -1);
     sal_Int32                   GetTextBreak( const OUString& rStr, long nTextWidth,
                                               sal_Int32 nIndex = 0, sal_Int32 nLen = -1,
-                                              long nCharExtra = 0 ) const;
+                                              long nCharExtra = 0,
+                                              vcl::TextLayoutCache const* = nullptr) const;
     sal_Int32                   GetTextBreak( const OUString& rStr, long nTextWidth,
                                               sal_Unicode nExtraChar, sal_Int32& rExtraCharPos,
                                               sal_Int32 nIndex, sal_Int32 nLen,
-                                              long nCharExtra = 0 ) const;
+                                              long nCharExtra = 0,
+                                              vcl::TextLayoutCache const* = nullptr) const;
+    std::shared_ptr<vcl::TextLayoutCache> CreateTextLayoutCache(OUString const&) const;
 
 private:
     SAL_DLLPRIVATE void         ImplInitTextColor();
@@ -1247,9 +1253,11 @@ public:
     virtual bool                HasMirroredGraphics() const;
     SAL_DLLPRIVATE SalLayout*   ImplLayout( const OUString&, sal_Int32 nIndex, sal_Int32 nLen,
                                             const Point& rLogicPos = Point(0,0), long nLogicWidth=0,
-                                            const long* pLogicDXArray=NULL, int flags=0 ) const;
+                                            const long* pLogicDXArray=NULL, int flags=0,
+                                            vcl::TextLayoutCache const* = nullptr) const;
     SAL_DLLPRIVATE ImplLayoutArgs ImplPrepareLayoutArgs( OUString&, const sal_Int32 nIndex, const sal_Int32 nLen,
-                                                         DeviceCoordinate nPixelWidth, const DeviceCoordinate* pPixelDXArray, int flags = 0 ) const;
+                                                         DeviceCoordinate nPixelWidth, const DeviceCoordinate* pPixelDXArray, int flags = 0,
+                vcl::TextLayoutCache const* = nullptr) const;
     SAL_DLLPRIVATE SalLayout*   ImplGlyphFallbackLayout( SalLayout*, ImplLayoutArgs& ) const;
     // tells whether this output device is RTL in an LTR UI or LTR in a RTL UI
     SAL_DLLPRIVATE SalLayout*   getFallbackFont(ImplFontEntry &rFallbackFont,
diff --git a/sw/source/core/inc/drawfont.hxx b/sw/source/core/inc/drawfont.hxx
index 033d490..fee34b1 100644
--- a/sw/source/core/inc/drawfont.hxx
+++ b/sw/source/core/inc/drawfont.hxx
@@ -31,7 +31,10 @@ class Point;
 class SwWrongList;
 class Size;
 class SwFont;
-namespace vcl { class Font; }
+namespace vcl {
+    class Font;
+    class TextLayoutCache;
+}
 class SwUnderlineFont;
 
 // encapsulates information for drawing text
@@ -42,6 +45,7 @@ class SwDrawTextInfo
     SwViewShell const * pSh;
     const SwScriptInfo* pScriptInfo;
     Point m_aPos;
+    vcl::TextLayoutCache const* m_pCachedVclData;
     OUString m_aText;
     const SwWrongList* pWrong;
     const SwWrongList* pGrammarCheck;
@@ -104,7 +108,9 @@ public:
 
     SwDrawTextInfo( SwViewShell const *pS, OutputDevice &rO, const SwScriptInfo* pSI,
                     const OUString &rSt, sal_Int32 nI, sal_Int32 nL,
-                    sal_uInt16 nW = 0, bool bB = false )
+                    sal_uInt16 nW = 0, bool bB = false,
+                    vcl::TextLayoutCache const*const pCachedVclData = nullptr)
+        : m_pCachedVclData(pCachedVclData)
     {
         pFrm = NULL;
         pSh = pS;
@@ -200,6 +206,11 @@ public:
         return pHyphPos;
     }
 
+    vcl::TextLayoutCache const* GetVclCache() const
+    {
+        return m_pCachedVclData;
+    }
+
     const OUString &GetText() const
     {
         return m_aText;
@@ -416,6 +427,7 @@ public:
     void SetText( const OUString &rNew )
     {
         m_aText = rNew;
+        m_pCachedVclData = nullptr; // would any case benefit from save/restore?
     }
 
     void SetWrong( const SwWrongList* pNew )
diff --git a/sw/source/core/text/guess.cxx b/sw/source/core/text/guess.cxx
index 0339646..b379308 100644
--- a/sw/source/core/text/guess.cxx
+++ b/sw/source/core/text/guess.cxx
@@ -152,14 +152,14 @@ bool SwTxtGuess::Guess( const SwTxtPortion& rPor, SwTxtFormatInfo &rInf,
     // considering an additional "-" for hyphenation
     if( bHyph )
     {
-        nCutPos = rInf.GetTxtBreak( nLineWidth, nMaxLen, nMaxComp, nHyphPos );
+        nCutPos = rInf.GetTxtBreak( nLineWidth, nMaxLen, nMaxComp, nHyphPos, rInf.GetCachedVclData().get() );
 
         if ( !nHyphPos && rInf.GetIdx() )
             nHyphPos = rInf.GetIdx() - 1;
     }
     else
     {
-        nCutPos = rInf.GetTxtBreak( nLineWidth, nMaxLen, nMaxComp );
+        nCutPos = rInf.GetTxtBreak( nLineWidth, nMaxLen, nMaxComp, rInf.GetCachedVclData().get() );
 
 #if OSL_DEBUG_LEVEL > 1
         if ( COMPLETE_STRING != nCutPos )
@@ -504,7 +504,8 @@ bool SwTxtGuess::Guess( const SwTxtPortion& rPor, SwTxtFormatInfo &rInf,
     if( nPorLen )
     {
         rInf.GetTxtSize( &rSI, rInf.GetIdx(), nPorLen,
-                         nMaxComp, nBreakWidth, nMaxSizeDiff );
+                         nMaxComp, nBreakWidth, nMaxSizeDiff,
+                         rInf.GetCachedVclData().get() );
 
         // save maximum width for later use
         if ( nMaxSizeDiff )
diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx
index 6a622e4..b738d9f 100644
--- a/sw/source/core/text/inftxt.cxx
+++ b/sw/source/core/text/inftxt.cxx
@@ -21,6 +21,7 @@
 #include <unotools/linguprops.hxx>
 #include <unotools/lingucfg.hxx>
 #include <hintids.hxx>
+#include <svl/ctloptions.hxx>
 #include <sfx2/printer.hxx>
 #include <editeng/hyphenzoneitem.hxx>
 #include <editeng/escapementitem.hxx>
@@ -360,7 +361,7 @@ SwPosSize SwTxtSizeInfo::GetTxtSize( OutputDevice* pOutDev,
                                      const OUString& rTxt,
                                      const sal_Int32 nIndex,
                                      const sal_Int32 nLength,
-                                     const sal_uInt16 nComp ) const
+                                     const sal_uInt16 nComp) const
 {
     SwDrawTextInfo aDrawInf( m_pVsh, *pOutDev, pSI, rTxt, nIndex, nLength );
     aDrawInf.SetFrm( m_pFrm );
@@ -393,9 +394,11 @@ SwPosSize SwTxtSizeInfo::GetTxtSize() const
 
 void SwTxtSizeInfo::GetTxtSize( const SwScriptInfo* pSI, const sal_Int32 nIndex,
                                 const sal_Int32 nLength, const sal_uInt16 nComp,
-                                sal_uInt16& nMinSize, sal_uInt16& nMaxSizeDiff ) const
+                                sal_uInt16& nMinSize, sal_uInt16& nMaxSizeDiff,
+                                vcl::TextLayoutCache const*const pCache) const
 {
-    SwDrawTextInfo aDrawInf( m_pVsh, *m_pOut, pSI, *m_pTxt, nIndex, nLength );
+    SwDrawTextInfo aDrawInf( m_pVsh, *m_pOut, pSI, *m_pTxt, nIndex, nLength,
+            0, false, pCache);
     aDrawInf.SetFrm( m_pFrm );
     aDrawInf.SetFont( m_pFnt );
     aDrawInf.SetSnapToGrid( SnapToGrid() );
@@ -407,14 +410,15 @@ void SwTxtSizeInfo::GetTxtSize( const SwScriptInfo* pSI, const sal_Int32 nIndex,
 
 sal_Int32 SwTxtSizeInfo::GetTxtBreak( const long nLineWidth,
                                        const sal_Int32 nMaxLen,
-                                       const sal_uInt16 nComp ) const
+                                       const sal_uInt16 nComp,
+                                       vcl::TextLayoutCache const*const pCache) const
 {
     const SwScriptInfo& rScriptInfo =
                      const_cast<SwParaPortion*>(GetParaPortion())->GetScriptInfo();
 
     OSL_ENSURE( m_pRef == m_pOut, "GetTxtBreak is supposed to use the RefDev" );
     SwDrawTextInfo aDrawInf( m_pVsh, *m_pOut, &rScriptInfo,
-                             *m_pTxt, GetIdx(), nMaxLen );
+                             *m_pTxt, GetIdx(), nMaxLen,  0, false, pCache );
     aDrawInf.SetFrm( m_pFrm );
     aDrawInf.SetFont( m_pFnt );
     aDrawInf.SetSnapToGrid( SnapToGrid() );
@@ -427,14 +431,15 @@ sal_Int32 SwTxtSizeInfo::GetTxtBreak( const long nLineWidth,
 sal_Int32 SwTxtSizeInfo::GetTxtBreak( const long nLineWidth,
                                        const sal_Int32 nMaxLen,
                                        const sal_uInt16 nComp,
-                                       sal_Int32& rExtraCharPos ) const
+                                       sal_Int32& rExtraCharPos,
+                                       vcl::TextLayoutCache const*const pCache) const
 {
     const SwScriptInfo& rScriptInfo =
                      const_cast<SwParaPortion*>(GetParaPortion())->GetScriptInfo();
 
     OSL_ENSURE( m_pRef == m_pOut, "GetTxtBreak is supposed to use the RefDev" );
     SwDrawTextInfo aDrawInf( m_pVsh, *m_pOut, &rScriptInfo,
-                             *m_pTxt, GetIdx(), nMaxLen );
+                             *m_pTxt, GetIdx(), nMaxLen, 0, false, pCache );
     aDrawInf.SetFrm( m_pFrm );
     aDrawInf.SetFont( m_pFnt );
     aDrawInf.SetSnapToGrid( SnapToGrid() );
@@ -1339,6 +1344,19 @@ void SwTxtFormatInfo::CtorInitTxtFormatInfo( SwTxtFrm *pNewFrm, const bool bNewI
     nLineHeight = 0;
     nLineNetHeight = 0;
     SetLineStart(0);
+
+    SvtCTLOptions::TextNumerals const nTextNumerals(
+            SW_MOD()->GetCTLOptions().GetCTLTextNumerals());
+    // cannot cache for NUMERALS_CONTEXT because we need to know the string
+    // for the whole paragraph now
+    if (nTextNumerals != SvtCTLOptions::NUMERALS_CONTEXT)
+    {
+        // set digit mode to what will be used later to get same results
+        SwDigitModeModifier const m(*m_pRef, LANGUAGE_NONE /*dummy*/);
+        assert(m_pRef->GetDigitLanguage() != LANGUAGE_NONE);
+        SetCachedVclData(m_pRef->CreateTextLayoutCache(*m_pTxt));
+    }
+
     Init();
 }
 
@@ -1642,9 +1660,11 @@ SwTxtSlot::SwTxtSlot(
         nIdx = pInf->GetIdx();
         nLen = pInf->GetLen();
         pOldTxt = &(pInf->GetTxt());
+        m_pOldCachedVclData = pInf->GetCachedVclData();
         pInf->SetTxt( aTxt );
         pInf->SetIdx( 0 );
         pInf->SetLen( bTxtLen ? pInf->GetTxt().getLength() : pPor->GetLen() );
+        pInf->SetCachedVclData(nullptr);
 
         // ST2
         if ( bExgLists )
@@ -1689,6 +1709,7 @@ SwTxtSlot::~SwTxtSlot()
 {
     if( bOn )
     {
+        pInf->SetCachedVclData(m_pOldCachedVclData);
         pInf->SetTxt( *pOldTxt );
         pInf->SetIdx( nIdx );
         pInf->SetLen( nLen );
diff --git a/sw/source/core/text/inftxt.hxx b/sw/source/core/text/inftxt.hxx
index a0b627c..4568016 100644
--- a/sw/source/core/text/inftxt.hxx
+++ b/sw/source/core/text/inftxt.hxx
@@ -158,6 +158,11 @@ protected:
     OutputDevice* m_pOut;
     OutputDevice* m_pRef;
 
+    // performance hack - this is only used by SwTxtFormatInfo but
+    // because it's not even possible to dynamic_cast these things
+    // currently it has to be stored here
+    std::shared_ptr<vcl::TextLayoutCache> m_pCachedVclData;
+
     SwFont *m_pFnt;
     SwUnderlineFont *m_pUnderFnt; // Font for underlining
     SwTxtFrm *m_pFrm;
@@ -295,18 +300,21 @@ public:
     SwPosSize GetTxtSize() const;
     void GetTxtSize( const SwScriptInfo* pSI, const sal_Int32 nIdx,
                       const sal_Int32 nLen, const sal_uInt16 nComp,
-                      sal_uInt16& nMinSize, sal_uInt16& nMaxSizeDiff ) const;
+                      sal_uInt16& nMinSize, sal_uInt16& nMaxSizeDiff,
+                      vcl::TextLayoutCache const* = nullptr) const;
     inline SwPosSize GetTxtSize( const SwScriptInfo* pSI, const sal_Int32 nIdx,
                                  const sal_Int32 nLen, const sal_uInt16 nComp ) const;
     inline SwPosSize GetTxtSize( const OUString &rTxt ) const;
 
     sal_Int32 GetTxtBreak( const long nLineWidth,
                                            const sal_Int32 nMaxLen,
-                                           const sal_uInt16 nComp ) const;
+                                           const sal_uInt16 nComp,
+                           vcl::TextLayoutCache const* = nullptr) const;
     sal_Int32 GetTxtBreak( const long nLineWidth,
                                            const sal_Int32 nMaxLen,
                                            const sal_uInt16 nComp,
-                                           sal_Int32& rExtraCharPos ) const;
+                                           sal_Int32& rExtraCharPos,
+                           vcl::TextLayoutCache const* = nullptr) const;
 
     sal_uInt16 GetAscent() const;
 
@@ -371,6 +379,15 @@ public:
         { return ( m_pKanaComp && m_nKanaIdx < m_pKanaComp->size() )
                    ? (*m_pKanaComp)[m_nKanaIdx] : 0; }
 
+    std::shared_ptr<vcl::TextLayoutCache> GetCachedVclData() const
+    {
+        return m_pCachedVclData;
+    }
+    void SetCachedVclData(std::shared_ptr<vcl::TextLayoutCache> const& pCachedVclData)
+    {
+        m_pCachedVclData = pCachedVclData;
+    }
+
 #ifdef DBG_UTIL
     bool IsOptDbg() const;
 #endif
@@ -725,6 +742,7 @@ public:
 
     inline void SetTabOverflow( bool bOverflow ) { bTabOverflow = bOverflow; }
     inline bool IsTabOverflow() { return bTabOverflow; }
+
 };
 
 /**
@@ -737,6 +755,7 @@ public:
 class SwTxtSlot
 {
     OUString aTxt;
+    std::shared_ptr<vcl::TextLayoutCache> m_pOldCachedVclData;
     const OUString *pOldTxt;
     const SwWrongList* pOldSmartTagList;
     const SwWrongList* pOldGrammarCheckList;
diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx
index ae44617..95b1542 100644
--- a/sw/source/core/text/porfld.cxx
+++ b/sw/source/core/text/porfld.cxx
@@ -136,6 +136,7 @@ sal_uInt16 SwFldPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
  */
 class SwFldSlot
 {
+    std::shared_ptr<vcl::TextLayoutCache> m_pOldCachedVclData;
     const OUString *pOldTxt;
     OUString aTxt;
     sal_Int32 nIdx;
@@ -162,7 +163,9 @@ SwFldSlot::SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor )
         nIdx = pInf->GetIdx();
         nLen = pInf->GetLen();
         pOldTxt = &(pInf->GetTxt());
+        m_pOldCachedVclData = pInf->GetCachedVclData();
         pInf->SetLen( aTxt.getLength() );
+        pInf->SetCachedVclData(nullptr);
         if( pPor->IsFollow() )
         {
             pInf->SetFakeLineStart( nIdx > pInf->GetLineStart() );
@@ -180,6 +183,7 @@ SwFldSlot::~SwFldSlot()
 {
     if( bOn )
     {
+        pInf->SetCachedVclData(m_pOldCachedVclData);
         pInf->SetTxt( *pOldTxt );
         pInf->SetIdx( nIdx );
         pInf->SetLen( nLen );
diff --git a/sw/source/core/text/pormulti.cxx b/sw/source/core/text/pormulti.cxx
index 9df8de4..2bb8217 100644
--- a/sw/source/core/text/pormulti.cxx
+++ b/sw/source/core/text/pormulti.cxx
@@ -1735,6 +1735,8 @@ bool SwTxtFormatter::BuildMultiPortion( SwTxtFormatInfo &rInf,
     // save some values
     const OUString* pOldTxt = &(rInf.GetTxt());
     const SwTwips nOldPaintOfst = rInf.GetPaintOfst();
+    std::shared_ptr<vcl::TextLayoutCache> const pOldCachedVclData(rInf.GetCachedVclData());
+    rInf.SetCachedVclData(nullptr);
 
     OUString const aMultiStr( rInf.GetTxt().copy(0, nMultiLen + rInf.GetIdx()) );
     rInf.SetTxt( aMultiStr );
@@ -2053,6 +2055,7 @@ bool SwTxtFormatter::BuildMultiPortion( SwTxtFormatInfo &rInf,
         rInf.SetRest( pTmp );
     }
 
+    rInf.SetCachedVclData(pOldCachedVclData);
     rInf.SetTxt( *pOldTxt );
     rInf.SetPaintOfst( nOldPaintOfst );
     rInf.SetStop( aInf.IsStop() );
diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx
index 7a837ed..9ba646d 100644
--- a/sw/source/core/txtnode/fntcache.cxx
+++ b/sw/source/core/txtnode/fntcache.cxx
@@ -1973,7 +1973,8 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf )
         else
         {
             aTxtSize.Width() = rInf.GetOut().GetTextWidth( rInf.GetText(),
-                                                           rInf.GetIdx(), nLn );
+                                                           rInf.GetIdx(), nLn,
+                                                           rInf.GetVclCache());
             rInf.SetKanaDiff( 0 );
         }
 
@@ -2430,12 +2431,12 @@ sal_Int32 SwFont::GetTxtBreak( SwDrawTextInfo& rInf, long nTextWidth )
             sal_Int32 nHyphPos = *rInf.GetHyphPos();
             nTxtBreak = rInf.GetOut().GetTextBreak( *pTmpText, nTextWidth,
                              static_cast<sal_Unicode>('-'), nHyphPos,
-                             nTmpIdx, nTmpLen, nKern );
+                             nTmpIdx, nTmpLen, nKern, rInf.GetVclCache());
             *rInf.GetHyphPos() = (nHyphPos == -1) ? COMPLETE_STRING : nHyphPos;
         }
         else
             nTxtBreak = rInf.GetOut().GetTextBreak( *pTmpText, nTextWidth,
-                                                    nTmpIdx, nTmpLen, nKern );
+                             nTmpIdx, nTmpLen, nKern, rInf.GetVclCache());
 
         if ( bTextReplaced && nTxtBreak != -1 )
         {
diff --git a/vcl/generic/glyphs/gcach_layout.cxx b/vcl/generic/glyphs/gcach_layout.cxx
index 5010423c..8e9deeb 100644
--- a/vcl/generic/glyphs/gcach_layout.cxx
+++ b/vcl/generic/glyphs/gcach_layout.cxx
@@ -349,6 +349,41 @@ struct HbScriptRun
 
 typedef std::vector<HbScriptRun> HbScriptRuns;
 
+namespace vcl {
+    struct Run
+    {
+        int32_t nStart;
+        int32_t nEnd;
+        UScriptCode nCode;
+        Run(int32_t nStart_, int32_t nEnd_, UScriptCode nCode_)
+            : nStart(nStart_), nEnd(nEnd_), nCode(nCode_)
+        {}
+    };
+
+    class TextLayoutCache
+    {
+    public:
+        std::vector<vcl::Run> runs;
+        TextLayoutCache(OUString const& rString, sal_Int32 const nEnd)
+        {
+            vcl::ScriptRun aScriptRun(
+                reinterpret_cast<const UChar *>(rString.getStr()),
+                nEnd);
+            while (aScriptRun.next())
+            {
+                runs.push_back(Run(aScriptRun.getScriptStart(),
+                    aScriptRun.getScriptEnd(), aScriptRun.getScriptCode()));
+            }
+        }
+    };
+}
+
+std::shared_ptr<vcl::TextLayoutCache> ServerFontLayout::CreateTextLayoutCache(
+        OUString const& rString) const
+{
+    return std::make_shared<vcl::TextLayoutCache>(rString, rString.getLength());
+}
+
 bool HbLayoutEngine::Layout(ServerFontLayout& rLayout, ImplLayoutArgs& rArgs)
 {
     ServerFont& rFont = rLayout.GetServerFont();
@@ -370,7 +405,18 @@ bool HbLayoutEngine::Layout(ServerFontLayout& rLayout, ImplLayoutArgs& rArgs)
 
     rLayout.Reserve(nGlyphCapacity);
 
-    vcl::ScriptRun aScriptRun(reinterpret_cast<const UChar *>(rArgs.mpStr), rArgs.mnEndCharPos);
+    std::unique_ptr<vcl::TextLayoutCache> pNewScriptRun;
+    vcl::TextLayoutCache const* pTextLayout;
+    if (rArgs.m_pTextLayoutCache)
+    {
+        pTextLayout = rArgs.m_pTextLayoutCache; // use cache!
+    }
+    else
+    {
+        pNewScriptRun.reset(new vcl::TextLayoutCache(
+            reinterpret_cast<const UChar *>(rArgs.mpStr), rArgs.mnEndCharPos));
+        pTextLayout = pNewScriptRun.get();
+    }
 
     Point aCurrPos(0, 0);
     while (true)
@@ -383,21 +429,25 @@ bool HbLayoutEngine::Layout(ServerFontLayout& rLayout, ImplLayoutArgs& rArgs)
         // Find script subruns.
         int nCurrentPos = nBidiMinRunPos;
         HbScriptRuns aScriptSubRuns;
-        while (aScriptRun.next())
+        size_t k = 0;
+        for (; k < pTextLayout->runs.size(); ++k)
         {
-            if (aScriptRun.getScriptStart() <= nCurrentPos && aScriptRun.getScriptEnd() > nCurrentPos)
+            vcl::Run const& rRun(pTextLayout->runs[k]);
+            if (rRun.nStart <= nCurrentPos && nCurrentPos < rRun.nEnd)
+            {
                 break;
+            }
         }
 
         while (nCurrentPos < nBidiEndRunPos)
         {
             int32_t nMinRunPos = nCurrentPos;
-            int32_t nEndRunPos = std::min(aScriptRun.getScriptEnd(), nBidiEndRunPos);
-            HbScriptRun aRun(nMinRunPos, nEndRunPos, aScriptRun.getScriptCode());
+            int32_t nEndRunPos = std::min(pTextLayout->runs[k].nEnd, nBidiEndRunPos);
+            HbScriptRun aRun(nMinRunPos, nEndRunPos, pTextLayout->runs[k].nCode);
             aScriptSubRuns.push_back(aRun);
 
             nCurrentPos = nEndRunPos;
-            aScriptRun.next();
+            ++k;
         }
 
         // RTL subruns should be reversed to ensure that final glyph order is
@@ -405,8 +455,6 @@ bool HbLayoutEngine::Layout(ServerFontLayout& rLayout, ImplLayoutArgs& rArgs)
         if (bRightToLeft)
             std::reverse(aScriptSubRuns.begin(), aScriptSubRuns.end());
 
-        aScriptRun.reset();
-
         for (HbScriptRuns::iterator it = aScriptSubRuns.begin(); it != aScriptSubRuns.end(); ++it)
         {
             int nMinRunPos = it->mnMin;
diff --git a/vcl/inc/generic/glyphcache.hxx b/vcl/inc/generic/glyphcache.hxx
index c8d3552..ae9e30b 100644
--- a/vcl/inc/generic/glyphcache.hxx
+++ b/vcl/inc/generic/glyphcache.hxx
@@ -299,6 +299,9 @@ public:
 
     ServerFont&             GetServerFont() const   { return mrServerFont; }
 
+    virtual std::shared_ptr<vcl::TextLayoutCache>
+        CreateTextLayoutCache(OUString const&) const SAL_OVERRIDE;
+
 private:
     ServerFont&             mrServerFont;
     com::sun::star::uno::Reference<com::sun::star::i18n::XBreakIterator> mxBreak;
diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx
index 943f8eb..7ad8866 100644
--- a/vcl/inc/sallayout.hxx
+++ b/vcl/inc/sallayout.hxx
@@ -41,6 +41,9 @@ typedef unsigned short LanguageType;
 class SalGraphics;
 class PhysicalFontFace;
 
+namespace vcl {
+    class TextLayoutCache;
+}
 
 // used for managing runs e.g. for BiDi, glyph and script fallback
 class VCL_PLUGIN_PUBLIC ImplLayoutRuns
@@ -76,6 +79,9 @@ public:
     int                 mnEndCharPos;
     const sal_Unicode*  mpStr;
 
+    // performance hack
+    vcl::TextLayoutCache const* m_pTextLayoutCache;
+
     // positioning related inputs
     const DeviceCoordinate* mpDXArray;     // in pixel units
     DeviceCoordinate    mnLayoutWidth;      // in pixel units
@@ -88,7 +94,8 @@ public:
 public:
                 ImplLayoutArgs( const sal_Unicode* pStr, int nLength,
                                 int nMinCharPos, int nEndCharPos, int nFlags,
-                                const LanguageTag& rLanguageTag );
+                                const LanguageTag& rLanguageTag,
+                                vcl::TextLayoutCache const* pLayoutCache);
 
     void        SetLayoutWidth( DeviceCoordinate nWidth )       { mnLayoutWidth = nWidth; }
     void        SetDXArray( const DeviceCoordinate* pDXArray )  { mpDXArray = pDXArray; }
@@ -194,6 +201,9 @@ public:
     virtual void    Simplify( bool bIsBase ) = 0;
     virtual void    DisableGlyphInjection( bool /*bDisable*/ ) {}
 
+    virtual std::shared_ptr<vcl::TextLayoutCache>
+        CreateTextLayoutCache(OUString const&) const;
+
 protected:
     // used by layout engines
                     SalLayout();
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
index 9ba3dcc..c6897f2 100644
--- a/vcl/source/gdi/sallayout.cxx
+++ b/vcl/source/gdi/sallayout.cxx
@@ -486,7 +486,8 @@ bool ImplLayoutRuns::GetRun( int* nMinRunPos, int* nEndRunPos, bool* bRightToLef
 }
 
 ImplLayoutArgs::ImplLayoutArgs( const sal_Unicode* pStr, int nLen,
-    int nMinCharPos, int nEndCharPos, int nFlags, const LanguageTag& rLanguageTag )
+    int nMinCharPos, int nEndCharPos, int nFlags, const LanguageTag& rLanguageTag,
+    vcl::TextLayoutCache const*const pLayoutCache)
 :
     maLanguageTag( rLanguageTag ),
     mnFlags( nFlags ),
@@ -494,6 +495,7 @@ ImplLayoutArgs::ImplLayoutArgs( const sal_Unicode* pStr, int nLen,
     mnMinCharPos( nMinCharPos ),
     mnEndCharPos( nEndCharPos ),
     mpStr( pStr ),
+    m_pTextLayoutCache(pLayoutCache),
     mpDXArray( NULL ),
     mnLayoutWidth( 0 ),
     mnOrientation( 0 )
@@ -2128,4 +2130,10 @@ bool MultiSalLayout::GetOutline( SalGraphics& rGraphics,
     return bRet;
 }
 
+std::shared_ptr<vcl::TextLayoutCache> SalLayout::CreateTextLayoutCache(
+        OUString const&) const
+{
+    return 0; // by default, nothing to cache
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx
index 9b97d1d..6dfe1098 100644
--- a/vcl/source/outdev/text.cxx
+++ b/vcl/source/outdev/text.cxx
@@ -925,10 +925,11 @@ void OutputDevice::DrawText( const Point& rStartPt, const OUString& rStr,
         mpAlphaVDev->DrawText( rStartPt, rStr, nIndex, nLen, pVector, pDisplayText );
 }
 
-long OutputDevice::GetTextWidth( const OUString& rStr, sal_Int32 nIndex, sal_Int32 nLen ) const
+long OutputDevice::GetTextWidth( const OUString& rStr, sal_Int32 nIndex, sal_Int32 nLen,
+     vcl::TextLayoutCache const*const pLayoutCache) const
 {
 
-    long nWidth = GetTextArray( rStr, NULL, nIndex, nLen );
+    long nWidth = GetTextArray( rStr, NULL, nIndex, nLen, pLayoutCache );
 
     return nWidth;
 }
@@ -993,7 +994,8 @@ void OutputDevice::DrawTextArray( const Point& rStartPt, const OUString& rStr,
 }
 
 long OutputDevice::GetTextArray( const OUString& rStr, long* pDXAry,
-                                 sal_Int32 nIndex, sal_Int32 nLen ) const
+                                 sal_Int32 nIndex, sal_Int32 nLen,
+                                 vcl::TextLayoutCache const*const pLayoutCache) const
 {
     if(nLen == 0x0FFFF)
     {
@@ -1009,7 +1011,8 @@ long OutputDevice::GetTextArray( const OUString& rStr, long* pDXAry,
         nLen = rStr.getLength() - nIndex;
     }
     // do layout
-    SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
+    SalLayout *const pSalLayout = ImplLayout(rStr, nIndex, nLen,
+            Point(0,0), 0, nullptr, 0, pLayoutCache);
     if( !pSalLayout )
         return 0;
 #if VCL_FLOAT_DEVICE_PIXEL
@@ -1191,7 +1194,8 @@ void OutputDevice::DrawStretchText( const Point& rStartPt, sal_uLong nWidth,
 ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( OUString& rStr,
                                                     const sal_Int32 nMinIndex, const sal_Int32 nLen,
                                                     DeviceCoordinate nPixelWidth, const DeviceCoordinate* pDXArray,
-                                                    int nLayoutFlags ) const
+                                                    int nLayoutFlags,
+         vcl::TextLayoutCache const*const pLayoutCache) const
 {
     assert(nMinIndex >= 0);
     assert(nLen >= 0);
@@ -1290,7 +1294,7 @@ ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( OUString& rStr,
         nLayoutFlags |= SAL_LAYOUT_RIGHT_ALIGN;
 
     // set layout options
-    ImplLayoutArgs aLayoutArgs( rStr.getStr(), rStr.getLength(), nMinIndex, nEndIndex, nLayoutFlags, maFont.GetLanguageTag() );
+    ImplLayoutArgs aLayoutArgs( rStr.getStr(), rStr.getLength(), nMinIndex, nEndIndex, nLayoutFlags, maFont.GetLanguageTag(), pLayoutCache );
 
     int nOrientation = mpFontEntry ? mpFontEntry->mnOrientation : 0;
     aLayoutArgs.SetOrientation( nOrientation );
@@ -1304,7 +1308,8 @@ ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( OUString& rStr,
 SalLayout* OutputDevice::ImplLayout(const OUString& rOrigStr,
                                     sal_Int32 nMinIndex, sal_Int32 nLen,
                                     const Point& rLogicalPos, long nLogicalWidth,
-                                    const long* pDXArray, int flags) const
+                                    const long* pDXArray, int flags,
+         vcl::TextLayoutCache const* pLayoutCache) const
 {
     // we need a graphics
     if( !mpGraphics )
@@ -1333,6 +1338,7 @@ SalLayout* OutputDevice::ImplLayout(const OUString& rOrigStr,
     // recode string if needed
     if( mpFontEntry->mpConversion ) {
         mpFontEntry->mpConversion->RecodeString( aStr, 0, aStr.getLength() );
+        pLayoutCache = nullptr; // don't use cache with modified string!
     }
     DeviceCoordinate nPixelWidth = (DeviceCoordinate)nLogicalWidth;
     DeviceCoordinate* pDXPixelArray = NULL;
@@ -1368,7 +1374,8 @@ SalLayout* OutputDevice::ImplLayout(const OUString& rOrigStr,
         }
     }
 
-    ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen, nPixelWidth, pDXPixelArray, flags);
+    ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen,
+            nPixelWidth, pDXPixelArray, flags, pLayoutCache);
 
     // get matching layout object for base font
     SalLayout* pSalLayout = mpGraphics->GetTextLayout( aLayoutArgs, 0 );
@@ -1407,6 +1414,24 @@ SalLayout* OutputDevice::ImplLayout(const OUString& rOrigStr,
     return pSalLayout;
 }
 
+std::shared_ptr<vcl::TextLayoutCache> OutputDevice::CreateTextLayoutCache(
+        OUString const& rString) const
+{
+    if (!mpGraphics) // can happen in e.g Insert Index/Table dialog
+        return nullptr;
+    OUString copyBecausePrepareModifiesIt(rString);
+    ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs(copyBecausePrepareModifiesIt,
+            0, rString.getLength(), 0, nullptr, 0, nullptr);
+
+    SalLayout *const pSalLayout = mpGraphics->GetTextLayout( aLayoutArgs, 0 );
+    if (!pSalLayout)
+        return nullptr;
+    std::shared_ptr<vcl::TextLayoutCache> const ret(
+            pSalLayout->CreateTextLayoutCache(copyBecausePrepareModifiesIt));
+    pSalLayout->Release();
+    return ret;
+}
+
 bool OutputDevice::GetTextIsRTL( const OUString& rString, sal_Int32 nIndex, sal_Int32 nLen ) const
 {
     OUString aStr( rString );
@@ -1420,9 +1445,11 @@ bool OutputDevice::GetTextIsRTL( const OUString& rString, sal_Int32 nIndex, sal_
 
 sal_Int32 OutputDevice::GetTextBreak( const OUString& rStr, long nTextWidth,
                                        sal_Int32 nIndex, sal_Int32 nLen,
-                                       long nCharExtra ) const
+                                       long nCharExtra,
+         vcl::TextLayoutCache const*const pLayoutCache) const
 {
-    SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
+    SalLayout *const pSalLayout = ImplLayout( rStr, nIndex, nLen,
+            Point(0,0), 0, nullptr, 0, pLayoutCache);
     sal_Int32 nRetVal = -1;
     if( pSalLayout )
     {
@@ -1451,11 +1478,13 @@ sal_Int32 OutputDevice::GetTextBreak( const OUString& rStr, long nTextWidth,
 sal_Int32 OutputDevice::GetTextBreak( const OUString& rStr, long nTextWidth,
                                        sal_Unicode nHyphenChar, sal_Int32& rHyphenPos,
                                        sal_Int32 nIndex, sal_Int32 nLen,
-                                       long nCharExtra ) const
+                                       long nCharExtra,
+         vcl::TextLayoutCache const*const pLayoutCache) const
 {
     rHyphenPos = -1;
 
-    SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
+    SalLayout *const pSalLayout = ImplLayout( rStr, nIndex, nLen,
+            Point(0,0), 0, nullptr, 0, pLayoutCache);
     sal_Int32 nRetVal = -1;
     if( pSalLayout )
     {


More information about the Libreoffice-commits mailing list