[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