[Libreoffice-commits] core.git: vcl/Library_vcl.mk vcl/quartz
Norbert Thiebaud
nthiebaud at gmail.com
Wed Apr 9 09:33:29 PDT 2014
vcl/Library_vcl.mk | 1
vcl/quartz/CTRunData.cxx | 90 +++++++++++++++
vcl/quartz/CTRunData.hxx | 42 +++++++
vcl/quartz/ctlayout.cxx | 269 ++++++++++++++++++++++++-----------------------
4 files changed, 271 insertions(+), 131 deletions(-)
New commits:
commit b8aa1f23645bbe81093ff436b82a58766f3157af
Author: Norbert Thiebaud <nthiebaud at gmail.com>
Date: Mon Apr 7 02:01:39 2014 -0500
vcl quartz: cache per-run glyphs information
GetNextGlyphs could only deal with 1 glyph at the time
and was recalculing a lot of thing while iterating on the glyphs
This is not just a performance issue.. the notiong of keeping
per run glyphs information will be useful to re-establish the
proper support of glyphs display positionning by SetDXArray()
which today is completely ignored, in favor or letting
CoreText spread the extra free space itself.
Change-Id: Ib267c3e490619b650d4149f4b15b5758802942ba
Reviewed-on: https://gerrit.libreoffice.org/8879
Tested-by: Norbert Thiebaud <nthiebaud at gmail.com>
Reviewed-by: Norbert Thiebaud <nthiebaud at gmail.com>
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index d7c13f1..487a53b 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -349,6 +349,7 @@ vcl_quartz_code= \
vcl/quartz/salvd \
vcl_coretext_code= \
+ vcl/quartz/CTRunData \
vcl/quartz/ctfonts \
vcl/quartz/ctlayout \
vcl/quartz/salgdi \
diff --git a/vcl/quartz/CTRunData.cxx b/vcl/quartz/CTRunData.cxx
new file mode 100644
index 0000000..609449b
--- /dev/null
+++ b/vcl/quartz/CTRunData.cxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/types.h>
+#include <cassert>
+
+#include "premac.h"
+#include <CoreGraphics/CoreGraphics.h>
+#include <CoreText/CoreText.h>
+#include "postmac.h"
+
+#include "CTRunData.hxx"
+
+CTRunData::CTRunData( CTRunRef pRun, int start)
+ : ownership_flags(0)
+ , m_StartPos(start)
+ , m_pRun(pRun)
+{
+ assert(pRun);
+
+ CFDictionaryRef pRunAttributes = CTRunGetAttributes( m_pRun );
+ m_pFont = (CTFontRef)CFDictionaryGetValue( pRunAttributes, kCTFontAttributeName );
+
+ m_nGlyphs = CTRunGetGlyphCount(m_pRun);
+ m_EndPos = m_StartPos + m_nGlyphs;
+ const CFRange aAll = CFRangeMake( 0, m_nGlyphs );
+
+ m_pAdvances = CTRunGetAdvancesPtr( pRun );
+ if( !m_pAdvances )
+ {
+ m_pAdvances = new CGSize[m_nGlyphs];
+ ownership_flags |= CTRUNDATA_F_OWN_ADVANCES;
+ CTRunGetAdvances( pRun, aAll, (CGSize*)m_pAdvances );
+ }
+
+ m_pGlyphs = CTRunGetGlyphsPtr( m_pRun );
+ if( !m_pGlyphs )
+ {
+ m_pGlyphs = new CGGlyph[m_nGlyphs];
+ ownership_flags |= CTRUNDATA_F_OWN_GLYPHS;
+ CTRunGetGlyphs( pRun, aAll, (CGGlyph*)m_pGlyphs);
+ }
+
+ m_pStringIndices = CTRunGetStringIndicesPtr( pRun );
+ if( !m_pStringIndices )
+ {
+ m_pStringIndices = new CFIndex[m_nGlyphs];
+ ownership_flags |= CTRUNDATA_F_OWN_INDICES;
+ CTRunGetStringIndices( pRun, aAll, (CFIndex*)m_pStringIndices );
+ }
+
+ m_pPositions = CTRunGetPositionsPtr( pRun );
+ if( !m_pPositions )
+ {
+ m_pPositions = new CGPoint[m_nGlyphs];
+ ownership_flags |= CTRUNDATA_F_OWN_POSITIONS;
+ CTRunGetPositions( pRun, aAll, (CGPoint*)m_pPositions );
+ }
+}
+
+CTRunData::~CTRunData()
+{
+ if(ownership_flags & CTRUNDATA_F_OWN_ADVANCES)
+ {
+ delete [] m_pAdvances;
+ }
+
+ if(ownership_flags & CTRUNDATA_F_OWN_GLYPHS)
+ {
+ delete [] m_pGlyphs;
+ }
+
+ if(ownership_flags & CTRUNDATA_F_OWN_INDICES)
+ {
+ delete [] m_pStringIndices;
+ }
+
+ if(ownership_flags & CTRUNDATA_F_OWN_POSITIONS)
+ {
+ delete [] m_pPositions;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/quartz/CTRunData.hxx b/vcl/quartz/CTRunData.hxx
new file mode 100644
index 0000000..2fb1912c
--- /dev/null
+++ b/vcl/quartz/CTRunData.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#ifndef CTRunData_Included
+#define CTRunData_Included
+
+#include "premac.h"
+#include <CoreGraphics/CoreGraphics.h>
+#include <CoreText/CoreText.h>
+#include "postmac.h"
+
+class CTRunData
+{
+public:
+ int ownership_flags;
+#define CTRUNDATA_F_OWN_ADVANCES (1<<0)
+#define CTRUNDATA_F_OWN_GLYPHS (1<<1)
+#define CTRUNDATA_F_OWN_INDICES (1<<2)
+#define CTRUNDATA_F_OWN_POSITIONS (1<<3)
+
+ int m_nGlyphs;
+ int m_StartPos;
+ int m_EndPos;
+ CTRunRef m_pRun;
+ CTFontRef m_pFont;
+ const CGGlyph* m_pGlyphs;
+ const CGPoint* m_pPositions;
+ const CGSize* m_pAdvances;
+ const CFIndex* m_pStringIndices;
+
+ CTRunData(CTRunRef pRun, int start);
+ ~CTRunData(void);
+};
+
+#endif /* NDef CTRunData_Included */
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/quartz/ctlayout.cxx b/vcl/quartz/ctlayout.cxx
index b8b1b98..a9cac89 100644
--- a/vcl/quartz/ctlayout.cxx
+++ b/vcl/quartz/ctlayout.cxx
@@ -17,12 +17,15 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
+#include <sal/types.h>
+#include <boost/ptr_container/ptr_vector.hpp>
#include "tools/debug.hxx"
#include "ctfonts.hxx"
+#include "CTRunData.hxx"
-class CTLayout
-: public SalLayout
+
+class CTLayout : public SalLayout
{
public:
explicit CTLayout( const CoreTextStyle* );
@@ -52,6 +55,7 @@ private:
void drawCTLine(AquaSalGraphics& rAquaGraphics, CTLineRef ctline, const CoreTextStyle* const pStyle) const;
CGPoint GetTextDrawPosition(void) const;
double GetWidth(void) const;
+ bool CacheGlyphLayout(void) const;
const CoreTextStyle* const mpTextStyle;
@@ -70,6 +74,10 @@ private:
// x-offset relative to layout origin
// currently only used in RTL-layouts
mutable double mfBaseAdv;
+
+ mutable bool bLayouted; // true if the glyph layout information are cached and current;
+ mutable boost::ptr_vector<CTRunData> m_vRunData;
+
};
CTLayout::CTLayout( const CoreTextStyle* pTextStyle )
@@ -81,6 +89,7 @@ CTLayout::CTLayout( const CoreTextStyle* pTextStyle )
, mfTrailingSpaceWidth( 0.0 )
, mfCachedWidth( -1 )
, mfBaseAdv( 0 )
+ , bLayouted( false )
{
}
@@ -94,6 +103,9 @@ CTLayout::~CTLayout()
bool CTLayout::LayoutText( ImplLayoutArgs& rArgs )
{
+ m_vRunData.release();
+ bLayouted = false;
+
if( mpAttrString )
CFRelease( mpAttrString );
mpAttrString = NULL;
@@ -226,7 +238,7 @@ void CTLayout::AdjustLayout( ImplLayoutArgs& rArgs )
// any unforeseen side effects.
CGPoint CTLayout::GetTextDrawPosition(void) const
{
- float fPosX, fPosY;
+ CGFloat fPosX, fPosY;
if (mnLayoutFlags & SAL_LAYOUT_RIGHT_ALIGN)
{
@@ -335,125 +347,123 @@ void CTLayout::DrawText( SalGraphics& rGraphics ) const
drawCTLine(rAquaGraphics, mpCTLine, mpTextStyle);
}
+bool CTLayout::CacheGlyphLayout(void) const // eew!
+{
+ m_vRunData.release();
+ if(!mpCTLine)
+ {
+ return false;
+ }
+ CFArrayRef aRuns = CTLineGetGlyphRuns( mpCTLine );
+ const int nRun = CFArrayGetCount( aRuns );
+ int nPos = 0;
+
+ for( int i = 0; i < nRun; ++i )
+ {
+ CTRunRef pRun = (CTRunRef)CFArrayGetValueAtIndex( aRuns, i );
+ CTRunData* pRunData = new CTRunData(pRun, nPos);
+ m_vRunData.push_back(pRunData);
+ nPos += pRunData->m_nGlyphs;
+ }
+ bLayouted = true;
+ return true;
+}
+
int CTLayout::GetNextGlyphs( int nLen, sal_GlyphId* pOutGlyphIds, Point& rPos, int& nStart,
sal_Int32* pGlyphAdvances, int* pCharIndexes,
const PhysicalFontFace** pFallbackFonts ) const
{
if( !mpCTLine )
+ {
return 0;
+ }
+ if(!bLayouted)
+ {
+ CacheGlyphLayout();
+ }
if( nStart < 0 ) // first glyph requested?
+ {
nStart = 0;
- nLen = 1; // TODO: handle nLen>1 below
-
- // prepare to iterate over the glyph runs
- int nCount = 0;
- int nSubIndex = nStart;
-
- typedef std::vector<CGGlyph> CGGlyphVector;
- typedef std::vector<CGPoint> CGPointVector;
- typedef std::vector<CGSize> CGSizeVector;
- typedef std::vector<CFIndex> CFIndexVector;
- CGGlyphVector aCGGlyphVec;
- CGPointVector aCGPointVec;
- CGSizeVector aCGSizeVec;
- CFIndexVector aCFIndexVec;
+ }
+ const PhysicalFontFace* pFallbackFont = NULL;
+ CTFontRef pFont = NULL;
+ CTFontDescriptorRef pFontDesc = NULL;
+ ImplDevFontAttributes rDevFontAttr;
- // TODO: iterate over cached layout
- CFArrayRef aGlyphRuns = CTLineGetGlyphRuns( mpCTLine );
- const int nRunCount = CFArrayGetCount( aGlyphRuns );
+ boost::ptr_vector<CTRunData>::const_iterator iter = m_vRunData.begin();
- for( int nRunIndex = 0; nRunIndex < nRunCount; ++nRunIndex )
+ while(iter != m_vRunData.end() && iter->m_EndPos <= nStart)
{
- CTRunRef pGlyphRun = (CTRunRef)CFArrayGetValueAtIndex( aGlyphRuns, nRunIndex );
- const CFIndex nGlyphsInRun = CTRunGetGlyphCount( pGlyphRun );
- // skip to the first glyph run of interest
- if( nSubIndex >= nGlyphsInRun )
+ iter++;
+ }
+ if(iter == m_vRunData.end())
+ {
+ return 0;
+ }
+ else
+ {
+ if( pFallbackFonts )
{
- nSubIndex -= nGlyphsInRun;
- continue;
+ pFont = (CTFontRef)CFDictionaryGetValue( mpTextStyle->GetStyleDict(), kCTFontAttributeName );
+ pFontDesc = CTFontCopyFontDescriptor( iter->m_pFont );
+ rDevFontAttr = DevFontFromCTFontDescriptor( pFontDesc, NULL );
}
- const CFRange aFullRange = CFRangeMake( 0, nGlyphsInRun );
-
- // get glyph run details
- const CGGlyph* pCGGlyphIdx = CTRunGetGlyphsPtr( pGlyphRun );
- if( !pCGGlyphIdx )
+ }
+ int i = nStart;
+ int count = 0;
+ while( i < nStart + nLen )
+ {
+ // convert glyph details for VCL
+ int j = i - iter->m_StartPos;
+ *(pOutGlyphIds++) = iter->m_pGlyphs[ j ];
+ if( pGlyphAdvances )
{
- aCGGlyphVec.reserve( nGlyphsInRun );
- CTRunGetGlyphs( pGlyphRun, aFullRange, &aCGGlyphVec[0] );
- pCGGlyphIdx = &aCGGlyphVec[0];
+ *(pGlyphAdvances++) = lrint(iter->m_pAdvances[ j ].width);
}
- const CGPoint* pCGGlyphPos = CTRunGetPositionsPtr( pGlyphRun );
- if( !pCGGlyphPos )
+ if( pCharIndexes )
{
- aCGPointVec.reserve( nGlyphsInRun );
- CTRunGetPositions( pGlyphRun, aFullRange, &aCGPointVec[0] );
- pCGGlyphPos = &aCGPointVec[0];
+ *(pCharIndexes++) = iter->m_pStringIndices[ j ] + mnMinCharPos;
}
-
- const CGSize* pCGGlyphAdvs = NULL;
- if( pGlyphAdvances)
+ if( pFallbackFonts )
{
- pCGGlyphAdvs = CTRunGetAdvancesPtr( pGlyphRun );
- if( !pCGGlyphAdvs)
+ if ( !CFEqual( iter->m_pFont, pFont ) )
{
- aCGSizeVec.reserve( nGlyphsInRun );
- CTRunGetAdvances( pGlyphRun, aFullRange, &aCGSizeVec[0] );
- pCGGlyphAdvs = &aCGSizeVec[0];
+ pFallbackFont = new CoreTextFontData( rDevFontAttr, (sal_IntPtr)pFontDesc );
+ *(pFallbackFonts++) = pFallbackFont;
}
- }
-
- const CFIndex* pCGGlyphStrIdx = NULL;
- if( pCharIndexes)
- {
- pCGGlyphStrIdx = CTRunGetStringIndicesPtr( pGlyphRun );
- if( !pCGGlyphStrIdx)
+ else
{
- aCFIndexVec.reserve( nGlyphsInRun );
- CTRunGetStringIndices( pGlyphRun, aFullRange, &aCFIndexVec[0] );
- pCGGlyphStrIdx = &aCFIndexVec[0];
+ *(pFallbackFonts++) = NULL;
}
}
-
- const PhysicalFontFace* pFallbackFont = NULL;
- if( pFallbackFonts )
+ if( i == nStart )
{
- CFDictionaryRef pRunAttributes = CTRunGetAttributes( pGlyphRun );
- CTFontRef pRunFont = (CTFontRef)CFDictionaryGetValue( pRunAttributes, kCTFontAttributeName );
-
- CFDictionaryRef pAttributes = mpTextStyle->GetStyleDict();
- CTFontRef pFont = (CTFontRef)CFDictionaryGetValue( pAttributes, kCTFontAttributeName );
- if ( !CFEqual( pRunFont, pFont ) )
- {
- CTFontDescriptorRef pFontDesc = CTFontCopyFontDescriptor( pRunFont );
- ImplDevFontAttributes rDevFontAttr = DevFontFromCTFontDescriptor( pFontDesc, NULL );
- pFallbackFont = new CoreTextFontData( rDevFontAttr, (sal_IntPtr)pFontDesc );
- }
+ const CGPoint& rFirstPos = iter->m_pPositions[ j ];
+ rPos = GetDrawPosition( Point( rFirstPos.x, rFirstPos.y) );
}
-
- // get the details for each interesting glyph
- // TODO: handle nLen>1
- for(; (--nLen >= 0) && (nSubIndex < nGlyphsInRun); ++nSubIndex, ++nStart )
+ i += 1;
+ count += 1;
+ if(i == iter->m_EndPos)
{
- // convert glyph details for VCL
- *(pOutGlyphIds++) = pCGGlyphIdx[ nSubIndex ];
- if( pGlyphAdvances )
- *(pGlyphAdvances++) = lrint(pCGGlyphAdvs[ nSubIndex ].width);
- if( pCharIndexes )
- *(pCharIndexes++) = pCGGlyphStrIdx[ nSubIndex] + mnMinCharPos;
+ // note: we assume that we do not have empty runs in the middle of things
+ ++iter;
+ if( iter == m_vRunData.end())
+ {
+ break;
+ }
if( pFallbackFonts )
- *(pFallbackFonts++) = pFallbackFont;
- if( !nCount++ )
{
- const CGPoint& rCurPos = pCGGlyphPos[ nSubIndex ];
- rPos = GetDrawPosition( Point( rCurPos.x, rCurPos.y) );
+ pFont = (CTFontRef)CFDictionaryGetValue( mpTextStyle->GetStyleDict(), kCTFontAttributeName );
+ pFontDesc = CTFontCopyFontDescriptor( iter->m_pFont );
+ rDevFontAttr = DevFontFromCTFontDescriptor( pFontDesc, NULL );
}
}
- nSubIndex = 0; // prepare for the next glyph run
- break; // TODO: handle nLen>1
}
+ nStart = i;
+
+ return count;
- return nCount;
}
double CTLayout::GetWidth() const
@@ -476,60 +486,57 @@ long CTLayout::GetTextWidth() const
long CTLayout::FillDXArray( sal_Int32* pDXArray ) const
{
+ long nPixWidth = GetTextWidth();
// short circuit requests which don't need full details
if( !pDXArray )
- return GetTextWidth();
+ return nPixWidth;
- long nPixWidth = GetTextWidth();
- if( pDXArray )
+ // prepare the sub-pixel accurate logical-width array
+ ::std::vector<double> aWidthVector( mnCharCount );
+ if( mnTrailingSpaceCount && (mfTrailingSpaceWidth > 0.0) )
{
- // prepare the sub-pixel accurate logical-width array
- ::std::vector<float> aWidthVector( mnCharCount );
- if( mnTrailingSpaceCount && (mfTrailingSpaceWidth > 0.0) )
- {
- const double fOneWidth = mfTrailingSpaceWidth / mnTrailingSpaceCount;
- ::std::fill_n(aWidthVector.begin() + (mnCharCount - mnTrailingSpaceCount),
- mnTrailingSpaceCount,
- fOneWidth);
- }
-
- // handle each glyph run
- CFArrayRef aGlyphRuns = CTLineGetGlyphRuns( mpCTLine );
- const int nRunCount = CFArrayGetCount( aGlyphRuns );
- typedef std::vector<CGSize> CGSizeVector;
- CGSizeVector aSizeVec;
- typedef std::vector<CFIndex> CFIndexVector;
- CFIndexVector aIndexVec;
+ const double fOneWidth = mfTrailingSpaceWidth / mnTrailingSpaceCount;
+ ::std::fill_n(aWidthVector.begin() + (mnCharCount - mnTrailingSpaceCount),
+ mnTrailingSpaceCount,
+ fOneWidth);
+ }
- for( int nRunIndex = 0; nRunIndex < nRunCount; ++nRunIndex )
- {
- CTRunRef pGlyphRun = (CTRunRef)CFArrayGetValueAtIndex( aGlyphRuns, nRunIndex );
- const CFIndex nGlyphCount = CTRunGetGlyphCount( pGlyphRun );
- const CFRange aFullRange = CFRangeMake( 0, nGlyphCount );
+ // handle each glyph run
+ CFArrayRef aGlyphRuns = CTLineGetGlyphRuns( mpCTLine );
+ const int nRunCount = CFArrayGetCount( aGlyphRuns );
+ typedef std::vector<CGSize> CGSizeVector;
+ CGSizeVector aSizeVec;
+ typedef std::vector<CFIndex> CFIndexVector;
+ CFIndexVector aIndexVec;
- aSizeVec.resize( nGlyphCount );
- aIndexVec.resize( nGlyphCount );
- CTRunGetAdvances( pGlyphRun, aFullRange, &aSizeVec[0] );
- CTRunGetStringIndices( pGlyphRun, aFullRange, &aIndexVec[0] );
+ for( int nRunIndex = 0; nRunIndex < nRunCount; ++nRunIndex )
+ {
+ CTRunRef pGlyphRun = (CTRunRef)CFArrayGetValueAtIndex( aGlyphRuns, nRunIndex );
+ const CFIndex nGlyphCount = CTRunGetGlyphCount( pGlyphRun );
+ const CFRange aFullRange = CFRangeMake( 0, nGlyphCount );
- for( int i = 0; i != nGlyphCount; ++i )
- {
- const int nRelIdx = aIndexVec[i];
- aWidthVector[nRelIdx] += aSizeVec[i].width;
- }
- }
+ aSizeVec.resize( nGlyphCount );
+ aIndexVec.resize( nGlyphCount );
+ CTRunGetAdvances( pGlyphRun, aFullRange, &aSizeVec[0] );
+ CTRunGetStringIndices( pGlyphRun, aFullRange, &aIndexVec[0] );
- // convert the sub-pixel accurate array into classic pDXArray integers
- float fWidthSum = 0.0;
- sal_Int32 nOldDX = 0;
- for( int i = 0; i < mnCharCount; ++i)
+ for( int i = 0; i != nGlyphCount; ++i )
{
- const sal_Int32 nNewDX = rint( fWidthSum += aWidthVector[i]);
- pDXArray[i] = nNewDX - nOldDX;
- nOldDX = nNewDX;
+ const int nRelIdx = aIndexVec[i];
+ aWidthVector[nRelIdx] += aSizeVec[i].width;
}
}
+ // convert the sub-pixel accurate array into classic pDXArray integers
+ double fWidthSum = 0.0;
+ sal_Int32 nOldDX = 0;
+ for( int i = 0; i < mnCharCount; ++i)
+ {
+ const sal_Int32 nNewDX = rint( fWidthSum += aWidthVector[i]);
+ pDXArray[i] = nNewDX - nOldDX;
+ nOldDX = nNewDX;
+ }
+
return nPixWidth;
}
More information about the Libreoffice-commits
mailing list