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

Tamas Bunth tamas.bunth at collabora.co.uk
Fri Jun 9 14:30:01 UTC 2017


 include/vcl/outdev.hxx       |    9 ++-
 vcl/source/outdev/text.cxx   |  103 +++++++++++++++++++++++++++++++++----------
 vcl/source/window/status.cxx |   80 +++++++++++++++++++++++++--------
 3 files changed, 147 insertions(+), 45 deletions(-)

New commits:
commit f0821f9a347c7752a3c741c3451a2f1630173720
Author: Tamas Bunth <tamas.bunth at collabora.co.uk>
Date:   Thu Jun 8 19:56:28 2017 +0200

    Cache text layout of statusbar items
    
    Extend lifecycle of SalLayout created by the output device.
    A layout is stored for each status bar item and used as a cache.
    The layout may be updated through output device method parameters.
    
    This way it's no longer necessary to calculate the layout again and again when
    painting the status bar item multiple times, provided that its text does not
    change.
    
    Change-Id: I6494c2d6b676e8f4fdda2cde6165ff0755fd4fa2
    Reviewed-on: https://gerrit.libreoffice.org/38578
    Reviewed-by: Tamás Bunth <btomi96 at gmail.com>
    Tested-by: Tamás Bunth <btomi96 at gmail.com>

diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index d6a7032f20dd..cf44ac9c3811 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -971,7 +971,8 @@ public:
 
     void                        DrawText( const Point& rStartPt, const OUString& rStr,
                                           sal_Int32 nIndex = 0, sal_Int32 nLen = -1,
-                                          MetricVector* pVector = nullptr, OUString* pDisplayText = nullptr );
+                                          MetricVector* pVector = nullptr, OUString* pDisplayText = nullptr,
+                                          SalLayout** pLayoutCache = nullptr );
 
     void                        DrawText( const tools::Rectangle& rRect,
                                           const OUString& rStr, DrawTextFlags nStyle = DrawTextFlags::NONE,
@@ -1132,7 +1133,8 @@ public:
         See also GetTextBoundRect() for more explanation + code examples.
     */
     long                        GetTextWidth( const OUString& rStr, sal_Int32 nIndex = 0, sal_Int32 nLen = -1,
-                                  vcl::TextLayoutCache const* = nullptr) const;
+                                  vcl::TextLayoutCache const* = nullptr,
+                                  SalLayout** pLayoutCache = nullptr) const;
 
     /** Height where any character of the current font fits; in logic coordinates.
 
@@ -1148,7 +1150,8 @@ public:
                                                SalLayoutFlags flags = SalLayoutFlags::NONE);
     long                        GetTextArray( const OUString& rStr, long* pDXAry,
                                               sal_Int32 nIndex = 0, sal_Int32 nLen = -1,
-                                              vcl::TextLayoutCache const* = nullptr) const;
+                                              vcl::TextLayoutCache const* = nullptr,
+                                              SalLayout** pLayoutCache = nullptr) const;
 
     bool                        GetCaretPositions( const OUString&, long* pCaretXArray,
                                               sal_Int32 nIndex, sal_Int32 nLen ) const;
diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx
index 15eaeb434433..3937af3eb543 100644
--- a/vcl/source/outdev/text.cxx
+++ b/vcl/source/outdev/text.cxx
@@ -802,7 +802,8 @@ void OutputDevice::SetTextAlign( TextAlign eAlign )
 
 void OutputDevice::DrawText( const Point& rStartPt, const OUString& rStr,
                              sal_Int32 nIndex, sal_Int32 nLen,
-                             MetricVector* pVector, OUString* pDisplayText
+                             MetricVector* pVector, OUString* pDisplayText,
+                             SalLayout** pLayoutCache
                              )
 {
     assert(!is_double_buffered_window());
@@ -874,11 +875,47 @@ void OutputDevice::DrawText( const Point& rStartPt, const OUString& rStr,
     if ( !IsDeviceOutputNecessary() || pVector )
         return;
 
-    SalLayout* pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt);
-    if( pSalLayout )
+    if(mpFontInstance && pLayoutCache)
+        // do not use cache with modified string
+        if( mpFontInstance->mpConversion )
+            *pLayoutCache = nullptr;
+
+    // without cache
+    if(!pLayoutCache)
     {
-        ImplDrawText( *pSalLayout );
-        delete pSalLayout;
+        SalLayout* pSalLayout = ImplLayout(rStr, nIndex, nLen, rStartPt);
+        if(pSalLayout)
+        {
+            ImplDrawText( *pSalLayout );
+            delete pSalLayout;
+        }
+
+    }
+    else
+    {
+        // with cache, but there is no cache yet
+        if(!*pLayoutCache)
+            *pLayoutCache = ImplLayout(rStr, nIndex, nLen, rStartPt);
+
+        if( *pLayoutCache )
+        {
+            // initialize font if needed
+            if( mbNewFont )
+                if( !ImplNewFont() )
+                    return;
+            if( mbInitFont )
+                InitFont();
+
+            OUString aStrModifiable = rStr;
+            ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStrModifiable, nIndex, nLen,
+                    0, nullptr);
+
+             // position, justify, etc. the layout
+             (*pLayoutCache)->AdjustLayout( aLayoutArgs );
+             (*pLayoutCache)->DrawBase() = ImplLogicToDevicePixel( rStartPt );
+
+            ImplDrawText( **pLayoutCache );
+        }
     }
 
     if( mpAlphaVDev )
@@ -886,10 +923,12 @@ void OutputDevice::DrawText( const Point& rStartPt, const OUString& rStr,
 }
 
 long OutputDevice::GetTextWidth( const OUString& rStr, sal_Int32 nIndex, sal_Int32 nLen,
-     vcl::TextLayoutCache const*const pLayoutCache) const
+     vcl::TextLayoutCache const*const pLayoutCache,
+     SalLayout** pSalLayoutCache) const
 {
 
-    long nWidth = GetTextArray( rStr, nullptr, nIndex, nLen, pLayoutCache );
+    long nWidth = GetTextArray( rStr, nullptr, nIndex,
+            nLen, pLayoutCache, pSalLayoutCache );
 
     return nWidth;
 }
@@ -952,7 +991,8 @@ void OutputDevice::DrawTextArray( const Point& rStartPt, const OUString& rStr,
 
 long OutputDevice::GetTextArray( const OUString& rStr, long* pDXAry,
                                  sal_Int32 nIndex, sal_Int32 nLen,
-                                 vcl::TextLayoutCache const*const pLayoutCache) const
+                                 vcl::TextLayoutCache const*const pLayoutCache,
+                                 SalLayout** pSalLayoutCache) const
 {
     if( nIndex >= rStr.getLength() )
         return 0; // TODO: this looks like a buggy caller?
@@ -961,23 +1001,36 @@ long OutputDevice::GetTextArray( const OUString& rStr, long* pDXAry,
     {
         nLen = rStr.getLength() - nIndex;
     }
-    // do layout
-    SalLayout *const pSalLayout = ImplLayout(rStr, nIndex, nLen,
-            Point(0,0), 0, nullptr, SalLayoutFlags::NONE, pLayoutCache);
-    if( !pSalLayout )
+
+    SalLayout* pSalLayout = pSalLayoutCache ? *pSalLayoutCache : nullptr;
+
+    if(!pSalLayout)
     {
-        // The caller expects this to init the elements of pDXAry.
-        // Adapting all the callers to check that GetTextArray succeeded seems
-        // too much work.
-        // Init here to 0 only in the (rare) error case, so that any missing
-        // element init in the happy case will still be found by tools,
-        // and hope that is sufficient.
-        if (pDXAry)
+        // do layout
+        pSalLayout = ImplLayout(rStr, nIndex, nLen,
+                Point(0,0), 0, nullptr, SalLayoutFlags::NONE, pLayoutCache);
+        if( !pSalLayout )
+        {
+            // The caller expects this to init the elements of pDXAry.
+            // Adapting all the callers to check that GetTextArray succeeded seems
+            // too much work.
+            // Init here to 0 only in the (rare) error case, so that any missing
+            // element init in the happy case will still be found by tools,
+            // and hope that is sufficient.
+            if (pDXAry)
+            {
+                memset(pDXAry, 0, nLen * sizeof(*pDXAry));
+            }
+            return 0;
+        }
+
+        // update cache if used
+        if(pSalLayoutCache)
         {
-            memset(pDXAry, 0, nLen * sizeof(*pDXAry));
+            *pSalLayoutCache = pSalLayout;
         }
-        return 0;
     }
+
 #if VCL_FLOAT_DEVICE_PIXEL
     std::unique_ptr<DeviceCoordinate[]> pDXPixelArray;
     if(pDXAry)
@@ -986,7 +1039,9 @@ long OutputDevice::GetTextArray( const OUString& rStr, long* pDXAry,
     }
     DeviceCoordinate nWidth = pSalLayout->FillDXArray( pDXPixelArray.get() );
     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
-    delete pSalLayout;
+
+    if(!pSalLayoutCache)
+        delete pSalLayout;
 
     // convert virtual char widths to virtual absolute positions
     if( pDXPixelArray )
@@ -1031,7 +1086,9 @@ long OutputDevice::GetTextArray( const OUString& rStr, long* pDXAry,
 
     long nWidth = pSalLayout->FillDXArray( pDXAry );
     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
-    delete pSalLayout;
+
+    if(!pSalLayoutCache)
+        delete pSalLayout;
 
     // convert virtual char widths to virtual absolute positions
     if( pDXAry )
diff --git a/vcl/source/window/status.cxx b/vcl/source/window/status.cxx
index aa5c1f59f6e6..c4f44d8e1a4b 100644
--- a/vcl/source/window/status.cxx
+++ b/vcl/source/window/status.cxx
@@ -32,6 +32,8 @@
 #include <svdata.hxx>
 #include <window.h>
 
+#include "sallayout.hxx"
+
 #define STATUSBAR_OFFSET_X      STATUSBAR_OFFSET
 #define STATUSBAR_OFFSET_Y      2
 #define STATUSBAR_OFFSET_TEXTY  3
@@ -59,20 +61,21 @@ StatusBar::ImplData::ImplData()
 
 struct ImplStatusItem
 {
-    sal_uInt16              mnId;
-    StatusBarItemBits   mnBits;
-    long                mnWidth;
-    long                mnOffset;
-    long                mnExtraWidth;
-    long                mnX;
-    OUString            maText;
-    OUString            maHelpText;
-    OUString            maQuickHelpText;
-    OString             maHelpId;
-    void*               mpUserData;
-    bool            mbVisible;
-    OUString            maAccessibleName;
-    OUString            maCommand;
+    sal_uInt16                          mnId;
+    StatusBarItemBits                   mnBits;
+    long                                mnWidth;
+    long                                mnOffset;
+    long                                mnExtraWidth;
+    long                                mnX;
+    OUString                            maText;
+    OUString                            maHelpText;
+    OUString                            maQuickHelpText;
+    OString                             maHelpId;
+    void*                               mpUserData;
+    bool                                mbVisible;
+    OUString                            maAccessibleName;
+    OUString                            maCommand;
+    std::unique_ptr<SalLayout>          mxLayoutCache;
 };
 
 inline long ImplCalcProgressWidth( sal_uInt16 nMax, long nSize )
@@ -369,20 +372,38 @@ void StatusBar::ImplDrawItem(vcl::RenderContext& rRenderContext, bool bOffScreen
         rRenderContext.SetClipRegion(aRegion);
     }
 
-    // print text
-    Size aTextSize(rRenderContext.GetTextWidth(pItem->maText), rRenderContext.GetTextHeight());
+    SalLayout* pLayoutCache = pItem->mxLayoutCache.get();
+    Size aTextSize(rRenderContext.GetTextWidth(pItem->maText,0,-1,nullptr,&pLayoutCache), rRenderContext.GetTextHeight());
+
+    // update cache if necessary
+    if(pLayoutCache != pItem->mxLayoutCache.get() )
+        pItem->mxLayoutCache.reset(pLayoutCache);
+
     Point aTextPos = ImplGetItemTextPos(aTextRectSize, aTextSize, pItem->mnBits);
+
     if (bOffScreen)
     {
-        mpImplData->mpVirDev->DrawText(aTextPos, pItem->maText);
+        mpImplData->mpVirDev->DrawText(
+                    aTextPos,
+                    pItem->maText,
+                    0, -1, nullptr, nullptr,
+                    &pLayoutCache );
     }
     else
     {
         aTextPos.X() += aTextRect.Left();
         aTextPos.Y() += aTextRect.Top();
-        rRenderContext.DrawText(aTextPos, pItem->maText);
+        rRenderContext.DrawText(
+                    aTextPos,
+                    pItem->maText,
+                    0, -1, nullptr, nullptr,
+                    &pLayoutCache );
     }
 
+    // update cache if necessary
+    if(pLayoutCache != pItem->mxLayoutCache.get() )
+        pItem->mxLayoutCache.reset(pLayoutCache);
+
     // call DrawItem if necessary
     if (pItem->mnBits & StatusBarItemBits::UserDraw)
     {
@@ -830,6 +851,13 @@ void StatusBar::StateChanged( StateChangedType nType )
         ImplInitSettings();
         Invalidate();
     }
+
+    //invalidate layout cache
+    for (ImplStatusItem* pItem : mpItemList)
+    {
+        pItem->mxLayoutCache.reset();
+    }
+
 }
 
 void StatusBar::DataChanged( const DataChangedEvent& rDCEvt )
@@ -852,6 +880,8 @@ void StatusBar::DataChanged( const DataChangedEvent& rDCEvt )
             long nWidth = GetTextWidth( pItem->maText ) + nFudge;
             if( nWidth > pItem->mnWidth + STATUSBAR_OFFSET )
                 pItem->mnWidth = nWidth + STATUSBAR_OFFSET;
+
+            pItem->mxLayoutCache.reset();
         }
         Size aSize = GetSizePixel();
         // do not disturb current width, since
@@ -1133,11 +1163,21 @@ void StatusBar::SetItemText( sal_uInt16 nItemId, const OUString& rText )
 
         if ( pItem->maText != rText )
         {
+            // invalidate cache
+            pItem->mxLayoutCache.reset();
+
             pItem->maText = rText;
 
             // adjust item width - see also DataChanged()
             long nFudge = GetTextHeight()/4;
-            long nWidth = GetTextWidth( pItem->maText ) + nFudge;
+
+            SalLayout* pLayoutCache = nullptr;
+
+            long nWidth = GetTextWidth( pItem->maText,0,-1,nullptr,&pLayoutCache ) + nFudge;
+
+            // update cache
+            pItem->mxLayoutCache.reset(pLayoutCache);
+
             if( (nWidth > pItem->mnWidth + STATUSBAR_OFFSET) ||
                 ((nWidth < pItem->mnWidth) && (mnDX - STATUSBAR_OFFSET) < mnItemsWidth  ))
             {
@@ -1196,6 +1236,8 @@ void StatusBar::SetItemData( sal_uInt16 nItemId, void* pNewData )
     if ( nPos != STATUSBAR_ITEM_NOTFOUND )
     {
         ImplStatusItem* pItem = mpItemList[ nPos ];
+        // invalidate cache
+        pItem->mxLayoutCache.reset();
         pItem->mpUserData = pNewData;
 
         // call Draw-Item if it's a User-Item


More information about the Libreoffice-commits mailing list