summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorMichael Stahl <mstahl@redhat.com>2015-03-03 15:26:10 +0100
committerMichael Stahl <mstahl@redhat.com>2015-03-31 20:08:35 +0200
commitb9782a2b59428e1bc398b5f3a895785a072c93b6 (patch)
tree11321664d97646020fb77cf161e89e20a11d68d6 /vcl
parentb7fa07b07195799f385ccba0243611f71ffe0525 (diff)
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@redhat.com> Tested-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/generic/glyphs/gcach_layout.cxx64
-rw-r--r--vcl/inc/generic/glyphcache.hxx3
-rw-r--r--vcl/inc/sallayout.hxx12
-rw-r--r--vcl/source/gdi/sallayout.cxx10
-rw-r--r--vcl/source/outdev/text.cxx53
5 files changed, 120 insertions, 22 deletions
diff --git a/vcl/generic/glyphs/gcach_layout.cxx b/vcl/generic/glyphs/gcach_layout.cxx
index debcbe79eb4c..94486a1a8813 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 c8d3552ba7c9..ae9e30b9c59a 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 943f8eb6bf5b..7ad886640d5c 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 e83264765bd0..82d87c322caf 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 06e0b4078ab5..c52cae5f858c 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 )
{