[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