[Libreoffice-commits] core.git: 3 commits - vcl/coretext vcl/inc vcl/Library_vcl.mk vcl/source

Khaled Hosny khaledhosny at eglug.org
Mon Jun 3 06:13:53 PDT 2013


 vcl/Library_vcl.mk              |    7 
 vcl/coretext/ctfonts.cxx        |  517 ++++++++++++++++++++++
 vcl/coretext/ctfonts.hxx        |   53 ++
 vcl/coretext/ctlayout.cxx       |  497 +++++++++++++++++++++
 vcl/coretext/salgdi2.cxx        |  908 ++++++++++++++++++++++++++++++++++++++++
 vcl/inc/aqua/salgdi.h           |    2 
 vcl/inc/coretext/salgdi2.h      |  413 ++++++++++++++++++
 vcl/inc/impfont.hxx             |    3 
 vcl/inc/quartz/salgdicommon.hxx |    5 
 vcl/source/gdi/outdev3.cxx      |    8 
 10 files changed, 2408 insertions(+), 5 deletions(-)

New commits:
commit cb61e01a59081e9d67ef2c81e3f9c82ccca1d05e
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Sun Jun 2 23:23:59 2013 +0200

    Drop Core Text dynamic loading stuff
    
    Our Mac OS X baseline includes Core Text.
    
    Change-Id: Icd2f0062d172db1d4393b2dd1eac4d9f55a88495

diff --git a/vcl/coretext/ctfonts.cxx b/vcl/coretext/ctfonts.cxx
index e6cf65b..2884cb5 100644
--- a/vcl/coretext/ctfonts.cxx
+++ b/vcl/coretext/ctfonts.cxx
@@ -34,10 +34,6 @@
 #include "basegfx/polygon/b2dpolygon.hxx"
 #include "basegfx/matrix/b2dhommatrix.hxx"
 
-#ifndef DISABLE_CORETEXT_DYNLOAD
-#include <dlfcn.h>
-#endif
-
 // =======================================================================
 
 // CoreText specific physically available font face
@@ -176,12 +172,11 @@ void CTTextStyle::GetFontMetric( float fDPIY, ImplFontMetricData& rMetric ) cons
 
 bool CTTextStyle::GetGlyphBoundRect( sal_GlyphId nGlyphId, Rectangle& rRect ) const
 {
-    const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
     CGGlyph nCGGlyph = nGlyphId & GF_IDXMASK; // NOTE: CoreText handles glyph fallback itself
     CTFontRef aCTFontRef = (CTFontRef)CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName );
 
     const CTFontOrientation aFontOrientation = kCTFontDefaultOrientation; // TODO: horz/vert
-    const CGRect aCGRect = rCT.FontGetBoundingRectsForGlyphs( aCTFontRef, aFontOrientation, &nCGGlyph, NULL, 1 );
+    const CGRect aCGRect = CTFontGetBoundingRectsForGlyphs( aCTFontRef, aFontOrientation, &nCGGlyph, NULL, 1 );
 
     rRect.Left()   = lrint( mfFontScale * aCGRect.origin.x );
     rRect.Top()    = lrint( mfFontScale * aCGRect.origin.y );
@@ -236,11 +231,10 @@ bool CTTextStyle::GetGlyphOutline( sal_GlyphId nGlyphId, basegfx::B2DPolyPolygon
 {
     rResult.clear();
 
-    const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
     // TODO: GF_FONTMASK if using non-native glyph fallback
     CGGlyph nCGGlyph = nGlyphId & GF_IDXMASK;
     CTFontRef pCTFont = (CTFontRef)CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName );
-    CGPathRef xPath = rCT.FontCreatePathForGlyph( pCTFont, nCGGlyph, NULL );
+    CGPathRef xPath = CTFontCreatePathForGlyph( pCTFont, nCGGlyph, NULL );
 
     GgoData aGgoData;
     aGgoData.mpPolyPoly = &rResult;
@@ -490,22 +484,15 @@ ImplMacFontData* CTFontList::GetFontDataFromId( sal_IntPtr nFontId ) const
 
 bool CTFontList::Init( void )
 {
-#ifndef DISABLE_CORETEXT_DYNLOAD
-    // check availability of the CoreText API
-    const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
-    if( !rCT.IsActive() )
-        return false;
-#endif // DISABLE_CORETEXT_DYNLOAD
-
     // enumerate available system fonts
     static const int nMaxDictEntries = 8;
     CFMutableDictionaryRef pCFDict = CFDictionaryCreateMutable( NULL,
         nMaxDictEntries, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
     CFDictionaryAddValue( pCFDict, kCTFontCollectionRemoveDuplicatesOption, kCFBooleanTrue );
-    mpCTFontCollection = rCT.FontCollectionCreateFromAvailableFonts( pCFDict );
+    mpCTFontCollection = CTFontCollectionCreateFromAvailableFonts( pCFDict );
     CFRelease( pCFDict );
 
-    mpCTFontArray = rCT.FontCollectionCreateMatchingFontDescriptors( mpCTFontCollection );
+    mpCTFontArray = CTFontCollectionCreateMatchingFontDescriptors( mpCTFontCollection );
     const int nFontCount = CFArrayGetCount( mpCTFontArray );
     const CFRange aFullRange = CFRangeMake( 0, nFontCount );
     CFArrayApplyFunction( mpCTFontArray, aFullRange, CTFontEnumCallBack, this );
@@ -515,81 +502,6 @@ bool CTFontList::Init( void )
 
 // =======================================================================
 
-#ifndef DISABLE_CORETEXT_DYNLOAD
-
-DynCoreTextSyms::DynCoreTextSyms( void )
-{
-    mbIsActive = false;
-
-    // check if CoreText has been explicitely disabled
-    const char* pEnvStr = getenv( "SAL_DISABLE_CORETEXT");
-    if( pEnvStr && (pEnvStr[0] != '0') )
-        return;
-
-    // check CoreText version
-    GetCoreTextVersion = (uint32_t(*)(void))dlsym( RTLD_DEFAULT, "CTGetCoreTextVersion");
-    if( !GetCoreTextVersion) return;
-
-    const uint32_t nCTVersion = GetCoreTextVersion();
-    static const uint32_t mykCTVersionNumber10_5 = 0x00020000;
-    if( nCTVersion < mykCTVersionNumber10_5)
-        return;
-
-    // load CoreText symbols dynamically
-    LineGetTrailingWhitespaceWidth = (double(*)(CTLineRef))dlsym( RTLD_DEFAULT, "CTLineGetTrailingWhitespaceWidth");
-    if( !LineGetTrailingWhitespaceWidth) return;
-
-    LineCreateJustifiedLine = (CTLineRef(*)(CTLineRef,CGFloat,double))dlsym( RTLD_DEFAULT, "CTLineCreateJustifiedLine");
-    if( !LineCreateJustifiedLine) return;
-
-    LineGetOffsetForStringIndex = (CGFloat(*)(CTLineRef,CFIndex,CGFloat*))dlsym( RTLD_DEFAULT, "CTLineGetOffsetForStringIndex");
-    if( !LineGetOffsetForStringIndex) return;
-
-    LineGetGlyphRuns = (CFArrayRef(*)(CTLineRef))dlsym( RTLD_DEFAULT, "CTLineGetGlyphRuns");
-    if( !LineGetGlyphRuns) return;
-
-    RunGetGlyphCount = (CFIndex(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetGlyphCount");
-    if( !RunGetGlyphCount) return;
-
-    RunGetGlyphsPtr = (const CGGlyph*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetGlyphsPtr");
-    if( !RunGetGlyphsPtr) return;
-
-    RunGetPositionsPtr = (const CGPoint*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetPositionsPtr");
-    if( !RunGetPositionsPtr) return;
-
-    RunGetAdvancesPtr = (const CGSize*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetAdvancesPtr");
-    if( !RunGetAdvancesPtr) return;
-
-    RunGetStringIndicesPtr = (const CFIndex*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetStringIndicesPtr");
-    if( !RunGetStringIndicesPtr) return;
-
-    FontCollectionCreateFromAvailableFonts = (CTFontCollectionRef(*)(CFDictionaryRef))dlsym( RTLD_DEFAULT, "CTFontCollectionCreateFromAvailableFonts");
-    if( !FontCollectionCreateFromAvailableFonts) return;
-
-    FontCollectionCreateMatchingFontDescriptors = (CFArrayRef(*)(CTFontCollectionRef))dlsym( RTLD_DEFAULT, "CTFontCollectionCreateMatchingFontDescriptors");
-    if( !FontCollectionCreateMatchingFontDescriptors) return;
-
-    FontCreatePathForGlyph = (CGPathRef(*)(CTFontRef,CGGlyph,const CGAffineTransform*))dlsym( RTLD_DEFAULT, "CTFontCreatePathForGlyph");
-    if( !FontCreatePathForGlyph) return;
-
-    FontGetBoundingRectsForGlyphs = (CGRect(*)(CTFontRef,CTFontOrientation,CGGlyph*,CGRect*,CFIndex))dlsym( RTLD_DEFAULT, "CTFontGetBoundingRectsForGlyphs");
-    if( !FontGetBoundingRectsForGlyphs) return;
-
-    mbIsActive = true;
-}
-
-// -----------------------------------------------------------------------
-
-const DynCoreTextSyms& DynCoreTextSyms::get( void )
-{
-    static DynCoreTextSyms aCT;
-    return aCT;
-}
-
-#endif // DISABLE_CORETEXT_DYNLOAD
-
-// =======================================================================
-
 SystemFontList* GetCoretextFontList( void )
 {
     CTFontList* pList = new CTFontList();
diff --git a/vcl/coretext/ctfonts.hxx b/vcl/coretext/ctfonts.hxx
index ec2e6e7..e903b63 100644
--- a/vcl/coretext/ctfonts.hxx
+++ b/vcl/coretext/ctfonts.hxx
@@ -51,40 +51,3 @@ private:
 
 // =======================================================================
 
-#ifndef DISABLE_CORETEXT_DYNLOAD
-// the CoreText symbols may need to be loaded dynamically
-// since platform targets like OSX 10.4 do not provide all required symbols
-// TODO: avoid the dlsym stuff if the target platform is >= OSX10.5
-
-class DynCoreTextSyms
-{
-public:
-    // dynamic symbols to access the CoreText API
-    uint32_t    (*GetCoreTextVersion)(void);
-    CTFontCollectionRef (*FontCollectionCreateFromAvailableFonts)(CFDictionaryRef);
-    CFArrayRef  (*FontCollectionCreateMatchingFontDescriptors)(CTFontCollectionRef);
-    CGPathRef   (*FontCreatePathForGlyph)(CTFontRef,CGGlyph,const CGAffineTransform*);
-    CGRect          (*FontGetBoundingRectsForGlyphs)(CTFontRef,CTFontOrientation,CGGlyph*,CGRect*,CFIndex);
-    CTLineRef   (*LineCreateJustifiedLine)(CTLineRef,CGFloat,double);
-    double      (*LineGetTrailingWhitespaceWidth)(CTLineRef);
-    CGFloat     (*LineGetOffsetForStringIndex)(CTLineRef,CFIndex,CGFloat*);
-    CFArrayRef  (*LineGetGlyphRuns)(CTLineRef);
-    CFIndex     (*RunGetGlyphCount)(CTRunRef);
-    const CGGlyph*  (*RunGetGlyphsPtr)(CTRunRef);
-    const CGPoint*  (*RunGetPositionsPtr)(CTRunRef);
-    const CGSize*   (*RunGetAdvancesPtr)(CTRunRef);
-    const CFIndex * (*RunGetStringIndicesPtr)(CTRunRef);
-
-    // singleton helpers
-    static const DynCoreTextSyms& get( void );
-    bool        IsActive( void ) const { return mbIsActive; }
-
-private:
-    explicit    DynCoreTextSyms( void );
-    bool        mbIsActive;
-};
-
-#endif // DISABLE_CORETEXT_DYNLOAD
-
-// =======================================================================
-
diff --git a/vcl/coretext/ctlayout.cxx b/vcl/coretext/ctlayout.cxx
index 30da812..0d71047 100644
--- a/vcl/coretext/ctlayout.cxx
+++ b/vcl/coretext/ctlayout.cxx
@@ -145,10 +145,9 @@ void CTLayout::AdjustLayout( ImplLayoutArgs& rArgs )
     if( !mpCTLine)
         return;
 
-    const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
     // CoreText fills trailing space during justification so we have to
     // take that into account when requesting CT to justify something
-    mfTrailingSpaceWidth = rCT.LineGetTrailingWhitespaceWidth( mpCTLine );
+    mfTrailingSpaceWidth = CTLineGetTrailingWhitespaceWidth( mpCTLine );
     const int nTrailingSpaceWidth = rint( mfFontScale * mfTrailingSpaceWidth );
 
     int nOrigWidth = GetTextWidth();
@@ -181,7 +180,7 @@ void CTLayout::AdjustLayout( ImplLayoutArgs& rArgs )
     if( (nOrigWidth >= nPixelWidth-1) && (nOrigWidth <= nPixelWidth+1) )
         return;
 
-    CTLineRef pNewCTLine = rCT.LineCreateJustifiedLine( mpCTLine, 1.0, nPixelWidth / mfFontScale );
+    CTLineRef pNewCTLine = CTLineCreateJustifiedLine( mpCTLine, 1.0, nPixelWidth / mfFontScale );
     if( !pNewCTLine ) { // CTLineCreateJustifiedLine can and does fail
         // handle failure by keeping the unjustified layout
         // TODO: a better solution such as
@@ -258,7 +257,6 @@ int CTLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIDs, Point& rPos, int&
     int nCount = 0;
     int nSubIndex = nStart;
 
-    const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
     typedef std::vector<CGGlyph> CGGlyphVector;
     typedef std::vector<CGPoint> CGPointVector;
     typedef std::vector<CGSize>  CGSizeVector;
@@ -269,11 +267,11 @@ int CTLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIDs, Point& rPos, int&
     CFIndexVector aCFIndexVec;
 
     // TODO: iterate over cached layout
-    CFArrayRef aGlyphRuns = rCT.LineGetGlyphRuns( mpCTLine );
+    CFArrayRef aGlyphRuns = CTLineGetGlyphRuns( mpCTLine );
     const int nRunCount = CFArrayGetCount( aGlyphRuns );
     for( int nRunIndex = 0; nRunIndex < nRunCount; ++nRunIndex ) {
         CTRunRef pGlyphRun = (CTRunRef)CFArrayGetValueAtIndex( aGlyphRuns, nRunIndex );
-        const CFIndex nGlyphsInRun = rCT.RunGetGlyphCount( pGlyphRun );
+        const CFIndex nGlyphsInRun = CTRunGetGlyphCount( pGlyphRun );
         // skip to the first glyph run of interest
         if( nSubIndex >= nGlyphsInRun ) {
             nSubIndex -= nGlyphsInRun;
@@ -282,13 +280,13 @@ int CTLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIDs, Point& rPos, int&
         const CFRange aFullRange = CFRangeMake( 0, nGlyphsInRun );
 
         // get glyph run details
-        const CGGlyph* pCGGlyphIdx = rCT.RunGetGlyphsPtr( pGlyphRun );
+        const CGGlyph* pCGGlyphIdx = CTRunGetGlyphsPtr( pGlyphRun );
         if( !pCGGlyphIdx ) {
             aCGGlyphVec.reserve( nGlyphsInRun );
             CTRunGetGlyphs( pGlyphRun, aFullRange, &aCGGlyphVec[0] );
             pCGGlyphIdx = &aCGGlyphVec[0];
         }
-        const CGPoint* pCGGlyphPos = rCT.RunGetPositionsPtr( pGlyphRun );
+        const CGPoint* pCGGlyphPos = CTRunGetPositionsPtr( pGlyphRun );
         if( !pCGGlyphPos ) {
             aCGPointVec.reserve( nGlyphsInRun );
             CTRunGetPositions( pGlyphRun, aFullRange, &aCGPointVec[0] );
@@ -297,7 +295,7 @@ int CTLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIDs, Point& rPos, int&
 
         const CGSize* pCGGlyphAdvs = NULL;
         if( pGlyphAdvances) {
-            pCGGlyphAdvs = rCT.RunGetAdvancesPtr( pGlyphRun );
+            pCGGlyphAdvs = CTRunGetAdvancesPtr( pGlyphRun );
             if( !pCGGlyphAdvs) {
                 aCGSizeVec.reserve( nGlyphsInRun );
                 CTRunGetAdvances( pGlyphRun, aFullRange, &aCGSizeVec[0] );
@@ -307,7 +305,7 @@ int CTLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIDs, Point& rPos, int&
 
         const CFIndex* pCGGlyphStrIdx = NULL;
         if( pCharIndexes) {
-            pCGGlyphStrIdx = rCT.RunGetStringIndicesPtr( pGlyphRun );
+            pCGGlyphStrIdx = CTRunGetStringIndicesPtr( pGlyphRun );
             if( !pCGGlyphStrIdx) {
                 aCFIndexVec.reserve( nGlyphsInRun );
                 CTRunGetStringIndices( pGlyphRun, aFullRange, &aCFIndexVec[0] );
@@ -422,12 +420,11 @@ void CTLayout::GetCaretPositions( int nMaxIndex, sal_Int32* pCaretXArray ) const
     for( int i = 0; i < nMaxIndex; ++i )
         pCaretXArray[ i ] = -1;
 
-    const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
     for( int n = 0; n <= mnCharCount; ++n )
     {
         // measure the characters cursor position
         CGFloat fPos2 = -1;
-        const CGFloat fPos1 = rCT.LineGetOffsetForStringIndex( mpCTLine, n, &fPos2 );
+        const CGFloat fPos1 = CTLineGetOffsetForStringIndex( mpCTLine, n, &fPos2 );
         (void)fPos2; // TODO: split cursor at line direction change
         // update previous trailing position
         if( n > 0 )
commit ee9fd88741202a95b47886116815b04f643459d4
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Sun Jun 2 12:43:36 2013 +0200

    Get the new Core Text code to compile
    
    Change-Id: I592158bd60afcbe756c6f0e11aa69a44768a0985

diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index d5496e3..b1f3f49 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -344,10 +344,9 @@ vcl_quartz_code= \
     vcl/quartz/utils \
 
 vcl_coretext_code= \
-    vcl/coretext/salcoretextfontutils \
-    vcl/coretext/salcoretextlayout \
-    vcl/coretext/salcoretextstyle \
-    vcl/coretext/salgdi \
+    vcl/coretext/ctfonts \
+    vcl/coretext/ctlayout \
+    vcl/coretext/salgdi2 \
 
 # GUIBASE specific stuff
 
diff --git a/vcl/coretext/ctfonts.cxx b/vcl/coretext/ctfonts.cxx
index 5eb2d34..e6cf65b 100644
--- a/vcl/coretext/ctfonts.cxx
+++ b/vcl/coretext/ctfonts.cxx
@@ -19,8 +19,7 @@
  *
  *************************************************************/
 
-// MARKER(update_precomp.py): autogen include statement, do not remove
-#include "precompiled_vcl.hxx"
+#include <boost/unordered_map.hpp>
 
 #include "impfont.hxx"
 #include "outfont.hxx"
@@ -29,6 +28,7 @@
 #include "aqua/salinst.h"
 #include "aqua/saldata.hxx"
 #include "coretext/salgdi2.h"
+#include "quartz/utils.h"
 #include "ctfonts.hxx"
 
 #include "basegfx/polygon/b2dpolygon.hxx"
@@ -47,10 +47,10 @@ class CTFontData
 public:
     explicit                CTFontData( const ImplDevFontAttributes&, sal_IntPtr nFontId );
     virtual                 ~CTFontData( void );
-    virtual ImplFontData*   Clone( void ) const;
+    virtual PhysicalFontFace*   Clone( void ) const;
 
-    virtual ImplMacTextStyle*   CreateMacTextStyle( const ImplFontSelectData& ) const;
-    virtual ImplFontEntry*      CreateFontInstance( /*const*/ ImplFontSelectData& ) const;
+    virtual ImplMacTextStyle*   CreateMacTextStyle( const FontSelectPattern& ) const;
+    virtual ImplFontEntry*      CreateFontInstance( /*const*/ FontSelectPattern& ) const;
     virtual int                 GetFontTable( const char pTagName[5], unsigned char* ) const;
 };
 
@@ -73,18 +73,18 @@ private:
     CTFontCollectionRef mpCTFontCollection;
     CFArrayRef mpCTFontArray;
 
-    typedef std::hash_map<sal_IntPtr,CTFontData*> CTFontContainer;
+    typedef boost::unordered_map<sal_IntPtr,CTFontData*> CTFontContainer;
     CTFontContainer maFontContainer;
 };
 
 // =======================================================================
 
-CTTextStyle::CTTextStyle( const ImplFontSelectData& rFSD )
+CTTextStyle::CTTextStyle( const FontSelectPattern& rFSD )
 :   ImplMacTextStyle( rFSD )
 ,   mpStyleDict( NULL )
 {
     mpFontData = (CTFontData*)rFSD.mpFontData;
-    const ImplFontSelectData* const pReqFont = &rFSD;
+    const FontSelectPattern* const pReqFont = &rFSD;
 
     double fScaledFontHeight = pReqFont->mfExactHeight;
 #if 0 // TODO: does CoreText need font size limiting???
@@ -264,13 +264,8 @@ bool CTTextStyle::GetGlyphOutline( sal_GlyphId nGlyphId, basegfx::B2DPolyPolygon
 
 void CTTextStyle::SetTextColor( const RGBAColor& rColor )
 {
-#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
     CGColorRef pCGColor = CGColorCreateGenericRGB( rColor.GetRed(),
         rColor.GetGreen(), rColor.GetBlue(), rColor.GetAlpha() );
-#else // for builds on OSX 10.4 SDK
-    const CGColorSpaceRef pCGColorSpace = GetSalData()->mxRGBSpace;
-    CGColorRef pCGColor = CGColorCreate( pCGColorSpace, rColor.AsArray() );
-#endif
     CFDictionarySetValue( mpStyleDict, kCTForegroundColorAttributeName, pCGColor );
     CFRelease( pCGColor);
 }
@@ -290,21 +285,21 @@ CTFontData::~CTFontData( void )
 
 // -----------------------------------------------------------------------
 
-ImplFontData* CTFontData::Clone( void ) const
+PhysicalFontFace* CTFontData::Clone( void ) const
 {
     return new CTFontData( *this);
 }
 
 // -----------------------------------------------------------------------
 
-ImplMacTextStyle* CTFontData::CreateMacTextStyle( const ImplFontSelectData& rFSD ) const
+ImplMacTextStyle* CTFontData::CreateMacTextStyle( const FontSelectPattern& rFSD ) const
 {
     return new CTTextStyle( rFSD);
 }
 
 // -----------------------------------------------------------------------
 
-ImplFontEntry* CTFontData::CreateFontInstance( /*const*/ ImplFontSelectData& rFSD ) const
+ImplFontEntry* CTFontData::CreateFontInstance( /*const*/ FontSelectPattern& rFSD ) const
 {
     return new ImplFontEntry( rFSD);
 }
@@ -352,12 +347,12 @@ static void CTFontEnumCallBack( const void* pValue, void* pContext )
     rDFA.mnQuality     = 0;
 
     // reset the font attributes
-    rDFA.meFamily     = FAMILY_DONTKNOW;
-    rDFA.mePitch      = PITCH_VARIABLE;
-    rDFA.meWidthType  = WIDTH_NORMAL;
-    rDFA.meWeight     = WEIGHT_NORMAL;
-    rDFA.meItalic     = ITALIC_NONE;
-    rDFA.mbSymbolFlag = false;
+    rDFA.SetFamilyType( FAMILY_DONTKNOW );
+    rDFA.SetPitch( PITCH_VARIABLE );
+    rDFA.SetWidthType( WIDTH_NORMAL );
+    rDFA.SetWeight( WEIGHT_NORMAL );
+    rDFA.SetItalic( ITALIC_NONE );
+    rDFA.SetSymbolFlag( false );
 
     // all scalable fonts on this platform are subsettable
     rDFA.mbEmbeddable = false;
@@ -366,10 +361,10 @@ static void CTFontEnumCallBack( const void* pValue, void* pContext )
     // get font name
     // TODO: use kCTFontDisplayNameAttribute instead???
     CFStringRef pFamilyName = (CFStringRef)CTFontDescriptorCopyAttribute( pFD, kCTFontFamilyNameAttribute );
-    rDFA.maName = GetOUString( pFamilyName );
+    rDFA.SetFamilyName( GetOUString( pFamilyName ) );
     // get font style
     CFStringRef pStyleName = (CFStringRef)CTFontDescriptorCopyAttribute( pFD, kCTFontStyleNameAttribute );
-    rDFA.maStyleName = GetOUString( pStyleName );
+    rDFA.SetStyleName( GetOUString( pStyleName ) );
 
     // get font-enabled status
     int bFontEnabled = FALSE;
@@ -385,7 +380,7 @@ static void CTFontEnumCallBack( const void* pValue, void* pContext )
     CFNumberRef pSymbolNum = NULL;
     if( CFDictionaryGetValueIfPresent( pAttrDict, kCTFontSymbolicTrait, (const void**)&pSymbolNum ) ) {
         CFNumberGetValue( pSymbolNum, kCFNumberSInt64Type, &nSymbolTrait );
-        rDFA.mbSymbolFlag = ((nSymbolTrait & kCTFontClassMaskTrait) == kCTFontSymbolicClass);
+        rDFA.SetSymbolFlag( ((nSymbolTrait & kCTFontClassMaskTrait) == kCTFontSymbolicClass) );
     }
 
     // get the font weight
@@ -402,14 +397,14 @@ static void CTFontEnumCallBack( const void* pValue, void* pContext )
         if( nInt < WEIGHT_THIN )
             nInt = WEIGHT_THIN;
     }
-    rDFA.meWeight = (FontWeight)nInt;
+    rDFA.SetWeight( (FontWeight)nInt );
 
     // get the font slant
     double fSlant = 0;
     CFNumberRef pSlantNum = (CFNumberRef)CFDictionaryGetValue( pAttrDict, kCTFontSlantTrait );
     CFNumberGetValue( pSlantNum, kCFNumberDoubleType, &fSlant );
     if( fSlant >= 0.035 )
-        rDFA.meItalic = ITALIC_NORMAL;
+        rDFA.SetItalic( ITALIC_NORMAL );
 
     // get width trait
     double fWidth = 0;
@@ -425,7 +420,7 @@ static void CTFontEnumCallBack( const void* pValue, void* pContext )
         if( nInt < WIDTH_ULTRA_CONDENSED )
             nInt = WIDTH_ULTRA_CONDENSED;
     }
-    rDFA.meWidthType = (FontWidth)nInt;
+    rDFA.SetWidthType( (FontWidth)nInt );
 
     // release the attribute dict that we had copied
     CFRelease( pAttrDict );
@@ -433,44 +428,6 @@ static void CTFontEnumCallBack( const void* pValue, void* pContext )
     // TODO? also use the HEAD table if available to get more attributes
 //  CFDataRef CTFontCopyTable( CTFontRef, kCTFontTableHead, /*kCTFontTableOptionNoOptions*/kCTFontTableOptionExcludeSynthetic );
 
-#if (OSL_DEBUG_LEVEL >= 1)
-    // update font attributes using the font's postscript name
-    ImplDevFontAttributes rDFA2;
-    CTFontRef pFont = CTFontCreateWithFontDescriptor( pFD, 0.0, NULL );
-    CFStringRef pPSName = CTFontCopyPostScriptName( pFont );
-    const String aPSName = GetOUString( pPSName );
-
-    rDFA2.mbSymbolFlag = false;
-    rDFA2.mePitch      = PITCH_VARIABLE;
-    rDFA2.meWidthType  = WIDTH_NORMAL;
-    rDFA2.meWeight     = WEIGHT_NORMAL;
-    rDFA2.meItalic     = ITALIC_NONE;
-
-    UpdateAttributesFromPSName( aPSName, rDFA2 );
-    CFRelease( pPSName );
-    CFRelease( pFont );
-
-    // show the font details and compare the CTFontDescriptor vs. PSName traits
-    char cMatch = (rDFA.mbSymbolFlag==rDFA2.mbSymbolFlag);
-    cMatch &= (rDFA.meWeight==rDFA2.meWeight);
-    cMatch &= ((rDFA.meItalic==ITALIC_NONE) == (rDFA2.meItalic==ITALIC_NONE));
-    cMatch &= (rDFA.meWidthType==rDFA2.meWidthType);
-    cMatch = cMatch ? '.' : '#';
-
-    char aFN[256], aSN[256];
-    CFStringGetCString( pFamilyName, aFN, sizeof(aFN), kCFStringEncodingUTF8 );
-    CFStringGetCString( pStyleName, aSN, sizeof(aSN), kCFStringEncodingUTF8 );
-
-    const ByteString aPSCName( aPSName, RTL_TEXTENCODING_UTF8 );
-    const char* aPN = aPSCName.GetBuffer();
-    printf("\tCTFont_%d%x%d%d_%c_%d%x%d%d ena=%d s=%02d b=%+.2f i=%+.2f w=%+.2f (\"%s\", \"%s\", \"%s\")\n",
-        (int)rDFA.mbSymbolFlag,(int)rDFA.meWeight,(int)rDFA.meItalic,(int)rDFA.meWidthType,
-        cMatch,
-        (int)rDFA2.mbSymbolFlag,(int)rDFA2.meWeight,(int)rDFA2.meItalic,(int)rDFA2.meWidthType,
-        bFontEnabled,
-        (int)(nSymbolTrait>>kCTFontClassMaskShift),fWeight,fSlant,fWidth,aFN,aSN,aPN);
-#endif // (OSL_DEBUG_LEVEL >= 1)
-
     if( bFontEnabled)
     {
         const sal_IntPtr nFontId = (sal_IntPtr)pValue;
diff --git a/vcl/coretext/ctfonts.hxx b/vcl/coretext/ctfonts.hxx
index c62c1f9..ec2e6e7 100644
--- a/vcl/coretext/ctfonts.hxx
+++ b/vcl/coretext/ctfonts.hxx
@@ -30,7 +30,7 @@ class CTTextStyle
 :   public ImplMacTextStyle
 {
 public:
-    explicit    CTTextStyle( const ImplFontSelectData& );
+    explicit    CTTextStyle( const FontSelectPattern& );
     virtual     ~CTTextStyle( void );
 
     virtual SalLayout* GetTextLayout( void ) const;
diff --git a/vcl/coretext/ctlayout.cxx b/vcl/coretext/ctlayout.cxx
index d232910..30da812 100644
--- a/vcl/coretext/ctlayout.cxx
+++ b/vcl/coretext/ctlayout.cxx
@@ -47,7 +47,7 @@ public:
     virtual bool    GetGlyphOutlines( SalGraphics&, PolyPolyVector& ) const;
     virtual bool    GetBoundRect( SalGraphics&, Rectangle& ) const;
 
-    const ImplFontData* GetFallbackFontData( sal_GlyphId ) const;
+    const PhysicalFontFace* GetFallbackFontData( sal_GlyphId ) const;
 
     virtual void    InitFont( void) const;
     virtual void    MoveGlyph( int nStart, long nNewXPos );
@@ -396,7 +396,7 @@ long CTLayout::FillDXArray( sal_Int32* pDXArray ) const
 
 // -----------------------------------------------------------------------
 
-int CTLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
+int CTLayout::GetTextBreak( long nMaxWidth, long /*nCharExtra*/, int nFactor ) const
 {
     if( !mpCTLine )
         return STRING_LEN;
@@ -469,9 +469,9 @@ void CTLayout::MoveGlyph( int /*nStart*/, long /*nNewXPos*/ ) {}
 void CTLayout::DropGlyph( int /*nStart*/ ) {}
 void CTLayout::Simplify( bool /*bIsBase*/ ) {}
 
-// get the ImplFontData for a glyph fallback font
+// get the PhysicalFontFace for a glyph fallback font
 // for a glyphid that was returned by CTLayout::GetNextGlyphs()
-const ImplFontData* CTLayout::GetFallbackFontData( sal_GlyphId /*nGlyphId*/ ) const
+const PhysicalFontFace* CTLayout::GetFallbackFontData( sal_GlyphId /*nGlyphId*/ ) const
 {
 #if 0
     // check if any fallback fonts were needed
@@ -484,7 +484,7 @@ const ImplFontData* CTLayout::GetFallbackFontData( sal_GlyphId /*nGlyphId*/ ) co
     pFallbackFont = mpFallbackInfo->GetFallbackFontData( nFallbackLevel );
 #else
     // let CoreText's font cascading handle glyph fallback
-    const ImplFontData* pFallbackFont = NULL;
+    const PhysicalFontFace* pFallbackFont = NULL;
 #endif
     return pFallbackFont;
 }
diff --git a/vcl/coretext/salgdi2.cxx b/vcl/coretext/salgdi2.cxx
index c118440..74c906f 100644
--- a/vcl/coretext/salgdi2.cxx
+++ b/vcl/coretext/salgdi2.cxx
@@ -36,7 +36,7 @@
 #include "vcl/sysdata.hxx"
 #include "vcl/svapp.hxx"
 
-#include "aqua/atsui/salgdi.h"
+#include "coretext/salgdi2.h"
 #include "aqua/salframe.h"
 #ifdef ENABLE_CORETEXT
 #include "ctfonts.hxx"
@@ -65,7 +65,7 @@ SystemFontList::~SystemFontList( void )
 
 // =======================================================================
 
-ImplMacTextStyle::ImplMacTextStyle( const ImplFontSelectData& rReqFont )
+ImplMacTextStyle::ImplMacTextStyle( const FontSelectPattern& rReqFont )
 :   mpFontData( (ImplMacFontData*)rReqFont.mpFontData )
 ,   mfFontScale( 1.0 )
 ,   mfFontStretch( 1.0 )
@@ -80,7 +80,7 @@ ImplMacTextStyle::~ImplMacTextStyle( void )
 // =======================================================================
 
 ImplMacFontData::ImplMacFontData( const ImplMacFontData& rSrc )
-:   ImplFontData( rSrc )
+:   PhysicalFontFace( rSrc )
 ,   mnFontId( rSrc.mnFontId )
 ,   mpCharMap( rSrc.mpCharMap )
 ,   mbOs2Read( rSrc.mbOs2Read )
@@ -95,7 +95,7 @@ ImplMacFontData::ImplMacFontData( const ImplMacFontData& rSrc )
 // -----------------------------------------------------------------------
 
 ImplMacFontData::ImplMacFontData( const ImplDevFontAttributes& rDFA, sal_IntPtr nFontId )
-:   ImplFontData( rDFA, 0 )
+:   PhysicalFontFace( rDFA, 0 )
 ,   mnFontId( nFontId )
 ,   mpCharMap( NULL )
 ,   mbOs2Read( false )
@@ -132,12 +132,6 @@ ImplFontEntry* ImplMacFontData::CreateFontInstance(FontSelectPattern& rFSD) cons
 static unsigned GetUShort( const unsigned char* p ){return((p[0]<<8)+p[1]);}
 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
 
-#if MACOSX_SDK_VERSION >= 1070
-extern "C" {
-extern ATSFontRef FMGetATSFontRefFromFont(FMFont iFont);
-}
-#endif
-
 const ImplFontCharMap* ImplMacFontData::GetImplFontCharMap() const
 {
     // return the cached charmap
@@ -186,33 +180,29 @@ bool ImplMacFontData::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabi
     }
     mbFontCapabilitiesRead = true;
 
+    int nBufSize = 0;
     // prepare to get the GSUB table raw data
-    ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
-    ByteCount nBufSize = 0;
-    OSStatus eStatus;
-    eStatus = ATSFontGetTable( rFont, GetTag("GSUB"), 0, 0, NULL, &nBufSize );
-    if( eStatus == noErr )
+    nBufSize = GetFontTable( "GSUB", NULL );
+    if( nBufSize > 0 )
     {
         // allocate a buffer for the GSUB raw data
         ByteVector aBuffer( nBufSize );
         // get the GSUB raw data
-        ByteCount nRawLength = 0;
-        eStatus = ATSFontGetTable( rFont, GetTag("GSUB"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
-        if( eStatus == noErr )
+        const int nRawLength = GetFontTable( "GSUB", &aBuffer[0] );
+        if( nRawLength > 0 )
         {
             const unsigned char* pGSUBTable = &aBuffer[0];
             vcl::getTTScripts(maFontCapabilities.maGSUBScriptTags, pGSUBTable, nRawLength);
         }
     }
-    eStatus = ATSFontGetTable( rFont, GetTag("OS/2"), 0, 0, NULL, &nBufSize );
-    if( eStatus == noErr )
+    nBufSize = GetFontTable( "OS/2", NULL );
+    if( nBufSize > 0 )
     {
-        // allocate a buffer for the GSUB raw data
+        // allocate a buffer for the OS/2 raw data
         ByteVector aBuffer( nBufSize );
         // get the OS/2 raw data
-        ByteCount nRawLength = 0;
-        eStatus = ATSFontGetTable( rFont, GetTag("OS/2"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
-        if( eStatus == noErr )
+        const int nRawLength = GetFontTable( "OS/2", &aBuffer[0] );
+        if( nRawLength > 0 )
         {
             const unsigned char* pOS2Table = &aBuffer[0];
             vcl::getTTCoverage(
diff --git a/vcl/inc/coretext/salgdi2.h b/vcl/inc/coretext/salgdi2.h
index 86d5fc9f..90fb594 100644
--- a/vcl/inc/coretext/salgdi2.h
+++ b/vcl/inc/coretext/salgdi2.h
@@ -62,7 +62,7 @@ public:
     virtual ImplFontEntry*  CreateFontInstance( FontSelectPattern& ) const;
     virtual sal_IntPtr      GetFontId() const;
 
-    virtual ImplMacTextStyle* CreateMacTextStyle( const ImplFontSelectData& ) const = 0;
+    virtual ImplMacTextStyle* CreateMacTextStyle( const FontSelectPattern& ) const = 0;
     virtual int             GetFontTable( const char pTagName[5], unsigned char* ) const = 0;
 
     const ImplFontCharMap*  GetImplFontCharMap() const;
@@ -92,7 +92,7 @@ private:
 class ImplMacTextStyle
 {
 public:
-    explicit        ImplMacTextStyle( const ImplFontSelectData& );
+    explicit        ImplMacTextStyle( const FontSelectPattern& );
     virtual         ~ImplMacTextStyle( void );
 
     virtual SalLayout* GetTextLayout( void ) const = 0;
commit ea8422d42e838e7ddfeb8d9f77f3ecedecb29ce8
Author: Khaled Hosny <khaledhosny at eglug.org>
Date:   Sat Jun 1 17:12:29 2013 +0200

    Cherry-pick Core Text port from AOO
    
    Manually picked from:
    
    http://svn.apache.org/viewvc?view=revision&sortby=log&revision=1480384
    
    Author:         hdu
    Date:           Wed May 8 18:14:34 2013 UTC (3 weeks, 2 days ago)
    Changed paths:  55
    Log Message:    #i122195# add VCL support for 64bit OSX>=10.7
    
    Change-Id: Ia799d7fdeb257e9bfd311338dcfdf97caf9d191f

diff --git a/vcl/coretext/ctfonts.cxx b/vcl/coretext/ctfonts.cxx
new file mode 100644
index 0000000..5eb2d34
--- /dev/null
+++ b/vcl/coretext/ctfonts.cxx
@@ -0,0 +1,648 @@
+/**************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+
+#include "impfont.hxx"
+#include "outfont.hxx"
+#include "sallayout.hxx"
+
+#include "aqua/salinst.h"
+#include "aqua/saldata.hxx"
+#include "coretext/salgdi2.h"
+#include "ctfonts.hxx"
+
+#include "basegfx/polygon/b2dpolygon.hxx"
+#include "basegfx/matrix/b2dhommatrix.hxx"
+
+#ifndef DISABLE_CORETEXT_DYNLOAD
+#include <dlfcn.h>
+#endif
+
+// =======================================================================
+
+// CoreText specific physically available font face
+class CTFontData
+:   public ImplMacFontData
+{
+public:
+    explicit                CTFontData( const ImplDevFontAttributes&, sal_IntPtr nFontId );
+    virtual                 ~CTFontData( void );
+    virtual ImplFontData*   Clone( void ) const;
+
+    virtual ImplMacTextStyle*   CreateMacTextStyle( const ImplFontSelectData& ) const;
+    virtual ImplFontEntry*      CreateFontInstance( /*const*/ ImplFontSelectData& ) const;
+    virtual int                 GetFontTable( const char pTagName[5], unsigned char* ) const;
+};
+
+// =======================================================================
+
+class CTFontList
+:   public SystemFontList
+{
+public:
+    explicit    CTFontList( void );
+    virtual     ~CTFontList( void );
+
+    bool        Init( void );
+    void        AddFont( CTFontData* );
+
+    virtual void    AnnounceFonts( ImplDevFontList& ) const;
+    virtual ImplMacFontData* GetFontDataFromId( sal_IntPtr ) const;
+
+private:
+    CTFontCollectionRef mpCTFontCollection;
+    CFArrayRef mpCTFontArray;
+
+    typedef std::hash_map<sal_IntPtr,CTFontData*> CTFontContainer;
+    CTFontContainer maFontContainer;
+};
+
+// =======================================================================
+
+CTTextStyle::CTTextStyle( const ImplFontSelectData& rFSD )
+:   ImplMacTextStyle( rFSD )
+,   mpStyleDict( NULL )
+{
+    mpFontData = (CTFontData*)rFSD.mpFontData;
+    const ImplFontSelectData* const pReqFont = &rFSD;
+
+    double fScaledFontHeight = pReqFont->mfExactHeight;
+#if 0 // TODO: does CoreText need font size limiting???
+    static const float fMaxFontHeight = 144.0; // TODO: is there a limit for CoreText?
+    if( fScaledFontHeight > fMaxFontHeight )
+    {
+        mfFontScale = fScaledFontHeight / fMaxFontHeight;
+        fScaledFontHeight = fMaxFontHeight;
+    }
+#endif
+
+    // convert font rotation to radian
+    mfFontRotation = pReqFont->mnOrientation * (M_PI / 1800.0);
+
+    // handle font stretching if any
+    const CGAffineTransform* pMatrix = NULL;
+    CGAffineTransform aMatrix;
+    if( (pReqFont->mnWidth != 0) && (pReqFont->mnWidth != pReqFont->mnHeight) )
+    {
+        mfFontStretch = (float)pReqFont->mnWidth / pReqFont->mnHeight;
+        aMatrix = CGAffineTransformMakeScale( mfFontStretch, 1.0F );
+        pMatrix = &aMatrix;
+    }
+
+    // create the style object for CoreText font attributes
+    static const CFIndex nMaxDictSize = 16; // TODO: does this really suffice?
+    mpStyleDict = CFDictionaryCreateMutable( NULL, nMaxDictSize,
+        &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
+
+    // set some default styles: no kerning, regular ligatures
+    static const CGFloat fValZero = 0.0;
+    CFNumberRef pCFFloatNumZero = CFNumberCreate( NULL, kCFNumberFloatType, &fValZero );
+    CFDictionarySetValue( mpStyleDict, kCTKernAttributeName, pCFFloatNumZero );
+    CFRelease( pCFFloatNumZero);
+    static const int nValOne = 1;
+    CFNumberRef pCFIntNumOne = CFNumberCreate( NULL, kCFNumberIntType, &nValOne );
+    CFDictionarySetValue( mpStyleDict, kCTLigatureAttributeName, pCFIntNumOne );
+    CFRelease( pCFIntNumOne);
+    CFBooleanRef pCFVertBool = pReqFont->mbVertical ? kCFBooleanTrue : kCFBooleanFalse;
+    CFDictionarySetValue( mpStyleDict, kCTVerticalFormsAttributeName, pCFVertBool );
+
+    CTFontDescriptorRef pFontDesc = (CTFontDescriptorRef)mpFontData->GetFontId();
+    CTFontRef pNewCTFont = CTFontCreateWithFontDescriptor( pFontDesc, fScaledFontHeight, pMatrix );
+    CFDictionarySetValue( mpStyleDict, kCTFontAttributeName, pNewCTFont );
+    CFRelease( pNewCTFont);
+
+#if 0 // LastResort is implicit in CoreText's font cascading
+    const void* aGFBDescriptors[] = { CTFontDescriptorCreateWithNameAndSize( CFSTR("LastResort"), 0) }; // TODO: use the full GFB list
+    const int nGfbCount = sizeof(aGFBDescriptors) / sizeof(*aGFBDescriptors);
+    CFArrayRef pGfbList = CFArrayCreate( NULL, aGFBDescriptors, nGfbCount, &kCFTypeArrayCallBacks);
+    CFDictionaryAddValue( mpStyleDict, kCTFontCascadeListAttribute, pGfbList);
+    CFRelease( pGfbList);
+#endif
+}
+
+// -----------------------------------------------------------------------
+
+CTTextStyle::~CTTextStyle( void )
+{
+    if( mpStyleDict )
+        CFRelease( mpStyleDict );
+}
+
+// -----------------------------------------------------------------------
+
+void CTTextStyle::GetFontMetric( float fDPIY, ImplFontMetricData& rMetric ) const
+{
+    // get the matching CoreText font handle
+    // TODO: is it worth it to cache the CTFontRef in SetFont() and reuse it here?
+    CTFontRef aCTFontRef = (CTFontRef)CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName );
+
+    const double fPixelSize = (mfFontScale * fDPIY);
+    rMetric.mnAscent       = lrint( CTFontGetAscent( aCTFontRef ) * fPixelSize);
+    rMetric.mnDescent      = lrint( CTFontGetDescent( aCTFontRef ) * fPixelSize);
+    rMetric.mnIntLeading   = lrint( CTFontGetLeading( aCTFontRef ) * fPixelSize);
+    rMetric.mnExtLeading   = 0;
+    // since ImplFontMetricData::mnWidth is only used for stretching/squeezing fonts
+    // setting this width to the pixel height of the fontsize is good enough
+    // it also makes the calculation of the stretch factor simple
+    rMetric.mnWidth        = lrint( CTFontGetSize( aCTFontRef ) * fPixelSize * mfFontStretch);
+
+    // all CoreText fonts are scalable
+    rMetric.mbScalableFont = true;
+    // TODO: check if any kerning is supported
+    rMetric.mbKernableFont = true;
+}
+
+// -----------------------------------------------------------------------
+
+bool CTTextStyle::GetGlyphBoundRect( sal_GlyphId nGlyphId, Rectangle& rRect ) const
+{
+    const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
+    CGGlyph nCGGlyph = nGlyphId & GF_IDXMASK; // NOTE: CoreText handles glyph fallback itself
+    CTFontRef aCTFontRef = (CTFontRef)CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName );
+
+    const CTFontOrientation aFontOrientation = kCTFontDefaultOrientation; // TODO: horz/vert
+    const CGRect aCGRect = rCT.FontGetBoundingRectsForGlyphs( aCTFontRef, aFontOrientation, &nCGGlyph, NULL, 1 );
+
+    rRect.Left()   = lrint( mfFontScale * aCGRect.origin.x );
+    rRect.Top()    = lrint( mfFontScale * aCGRect.origin.y );
+    rRect.Right()  = lrint( mfFontScale * (aCGRect.origin.x + aCGRect.size.width) );
+    rRect.Bottom() = lrint( mfFontScale * (aCGRect.origin.y + aCGRect.size.height) );
+    return true;
+}
+
+// -----------------------------------------------------------------------
+
+// callbacks from CTFontCreatePathForGlyph+CGPathApply for GetGlyphOutline()
+struct GgoData { basegfx::B2DPolygon maPolygon; basegfx::B2DPolyPolygon* mpPolyPoly; };
+
+static void MyCGPathApplierFunc( void* pData, const CGPathElement* pElement )
+{
+    basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
+    const int nPointCount = rPolygon.count();
+
+    switch( pElement->type )
+    {
+    case kCGPathElementCloseSubpath:
+    case kCGPathElementMoveToPoint:
+        if( nPointCount > 0 ) {
+            static_cast<GgoData*>(pData)->mpPolyPoly->append( rPolygon );
+            rPolygon.clear();
+        }
+        // fall through for kCGPathElementMoveToPoint:
+        if( pElement->type != kCGPathElementMoveToPoint )
+            break;
+    case kCGPathElementAddLineToPoint:
+        rPolygon.append( basegfx::B2DPoint( +pElement->points[0].x, -pElement->points[0].y ) );
+        break;
+    case kCGPathElementAddCurveToPoint:
+        rPolygon.append( basegfx::B2DPoint( +pElement->points[2].x, -pElement->points[2].y ) );
+        rPolygon.setNextControlPoint( nPointCount-1, basegfx::B2DPoint( pElement->points[0].x, -pElement->points[0].y ) );
+        rPolygon.setPrevControlPoint( nPointCount+0, basegfx::B2DPoint( pElement->points[1].x, -pElement->points[1].y ) );
+        break;
+    case kCGPathElementAddQuadCurveToPoint: {
+        const basegfx::B2DPoint aStartPt = rPolygon.getB2DPoint( nPointCount-1 );
+        const basegfx::B2DPoint aCtrPt1( (aStartPt.getX() + 2* pElement->points[0].x) / 3.0,
+                    (aStartPt.getY() - 2 * pElement->points[0].y) / 3.0 );
+        const basegfx::B2DPoint aCtrPt2( (+2 * +pElement->points[0].x + pElement->points[1].x) / 3.0,
+                (-2 * pElement->points[0].y - pElement->points[1].y) / 3.0 );
+        rPolygon.append( basegfx::B2DPoint( +pElement->points[1].x, -pElement->points[1].y ) );
+        rPolygon.setNextControlPoint( nPointCount-1, aCtrPt1 );
+        rPolygon.setPrevControlPoint( nPointCount+0, aCtrPt2 );
+        } break;
+    }
+}
+
+bool CTTextStyle::GetGlyphOutline( sal_GlyphId nGlyphId, basegfx::B2DPolyPolygon& rResult ) const
+{
+    rResult.clear();
+
+    const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
+    // TODO: GF_FONTMASK if using non-native glyph fallback
+    CGGlyph nCGGlyph = nGlyphId & GF_IDXMASK;
+    CTFontRef pCTFont = (CTFontRef)CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName );
+    CGPathRef xPath = rCT.FontCreatePathForGlyph( pCTFont, nCGGlyph, NULL );
+
+    GgoData aGgoData;
+    aGgoData.mpPolyPoly = &rResult;
+    CGPathApply( xPath, (void*)&aGgoData, MyCGPathApplierFunc );
+#if 0 // TODO: does OSX ensure that the last polygon is always closed?
+    const CGPathElement aClosingElement = { kCGPathElementCloseSubpath, NULL };
+    MyCGPathApplierFunc( (void*)&aGgoData, &aClosingElement );
+#endif
+
+    // apply the font scale
+    if( mfFontScale != 1.0 ) {
+        basegfx::B2DHomMatrix aScale;
+        aScale.scale( +mfFontScale, +mfFontScale );
+        rResult.transform( aScale );
+    }
+
+    return true;
+}
+
+// -----------------------------------------------------------------------
+
+void CTTextStyle::SetTextColor( const RGBAColor& rColor )
+{
+#if (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
+    CGColorRef pCGColor = CGColorCreateGenericRGB( rColor.GetRed(),
+        rColor.GetGreen(), rColor.GetBlue(), rColor.GetAlpha() );
+#else // for builds on OSX 10.4 SDK
+    const CGColorSpaceRef pCGColorSpace = GetSalData()->mxRGBSpace;
+    CGColorRef pCGColor = CGColorCreate( pCGColorSpace, rColor.AsArray() );
+#endif
+    CFDictionarySetValue( mpStyleDict, kCTForegroundColorAttributeName, pCGColor );
+    CFRelease( pCGColor);
+}
+
+// =======================================================================
+
+CTFontData::CTFontData( const ImplDevFontAttributes& rDFA, sal_IntPtr nFontId )
+:   ImplMacFontData( rDFA, nFontId )
+{}
+
+// -----------------------------------------------------------------------
+
+CTFontData::~CTFontData( void )
+{
+    // TODO: any resources to release?
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontData* CTFontData::Clone( void ) const
+{
+    return new CTFontData( *this);
+}
+
+// -----------------------------------------------------------------------
+
+ImplMacTextStyle* CTFontData::CreateMacTextStyle( const ImplFontSelectData& rFSD ) const
+{
+    return new CTTextStyle( rFSD);
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontEntry* CTFontData::CreateFontInstance( /*const*/ ImplFontSelectData& rFSD ) const
+{
+    return new ImplFontEntry( rFSD);
+}
+
+// -----------------------------------------------------------------------
+
+int CTFontData::GetFontTable( const char pTagName[5], unsigned char* pResultBuf ) const
+{
+    DBG_ASSERT( aTagName[4]=='\0', "CTFontData::GetFontTable with invalid tagname!\n" );
+
+    const CTFontTableTag nTagCode = (pTagName[0]<<24) + (pTagName[1]<<16) + (pTagName[2]<<8) + (pTagName[3]<<0);
+
+    // get the raw table length
+    CTFontDescriptorRef pFontDesc = reinterpret_cast<CTFontDescriptorRef>( GetFontId());
+    CTFontRef rCTFont = CTFontCreateWithFontDescriptor( pFontDesc, 0.0, NULL);
+    CFDataRef pDataRef = CTFontCopyTable( rCTFont, nTagCode, kCTFontTableOptionExcludeSynthetic);
+    CFRelease( rCTFont);
+    if( !pDataRef)
+        return 0;
+
+    const CFIndex nByteLength = CFDataGetLength( pDataRef);
+
+    // get the raw table data if requested
+    if( pResultBuf && (nByteLength > 0))
+    {
+        const CFRange aFullRange = CFRangeMake( 0, nByteLength);
+        CFDataGetBytes( pDataRef, aFullRange, (UInt8*)pResultBuf);
+    }
+
+    CFRelease( pDataRef);
+
+    return (int)nByteLength;
+}
+
+// =======================================================================
+
+static void CTFontEnumCallBack( const void* pValue, void* pContext )
+{
+    CTFontDescriptorRef pFD = static_cast<CTFontDescriptorRef>(pValue);
+
+    // all CoreText fonts are device fonts that can rotate just fine
+    ImplDevFontAttributes rDFA;
+    rDFA.mbOrientation = true;
+    rDFA.mbDevice      = true;
+    rDFA.mnQuality     = 0;
+
+    // reset the font attributes
+    rDFA.meFamily     = FAMILY_DONTKNOW;
+    rDFA.mePitch      = PITCH_VARIABLE;
+    rDFA.meWidthType  = WIDTH_NORMAL;
+    rDFA.meWeight     = WEIGHT_NORMAL;
+    rDFA.meItalic     = ITALIC_NONE;
+    rDFA.mbSymbolFlag = false;
+
+    // all scalable fonts on this platform are subsettable
+    rDFA.mbEmbeddable = false;
+    rDFA.mbSubsettable = true;
+
+    // get font name
+    // TODO: use kCTFontDisplayNameAttribute instead???
+    CFStringRef pFamilyName = (CFStringRef)CTFontDescriptorCopyAttribute( pFD, kCTFontFamilyNameAttribute );
+    rDFA.maName = GetOUString( pFamilyName );
+    // get font style
+    CFStringRef pStyleName = (CFStringRef)CTFontDescriptorCopyAttribute( pFD, kCTFontStyleNameAttribute );
+    rDFA.maStyleName = GetOUString( pStyleName );
+
+    // get font-enabled status
+    int bFontEnabled = FALSE;
+    CFNumberRef pFontEnabled = (CFNumberRef)CTFontDescriptorCopyAttribute( pFD, kCTFontEnabledAttribute );
+    CFNumberGetValue( pFontEnabled, kCFNumberIntType, &bFontEnabled );
+
+    // get font attributes
+    CFDictionaryRef pAttrDict = (CFDictionaryRef)CTFontDescriptorCopyAttribute( pFD, kCTFontTraitsAttribute );
+
+    // get symbolic trait
+    // TODO: use other traits such as MonoSpace/Condensed/Expanded or Vertical too
+    SInt64 nSymbolTrait = 0;
+    CFNumberRef pSymbolNum = NULL;
+    if( CFDictionaryGetValueIfPresent( pAttrDict, kCTFontSymbolicTrait, (const void**)&pSymbolNum ) ) {
+        CFNumberGetValue( pSymbolNum, kCFNumberSInt64Type, &nSymbolTrait );
+        rDFA.mbSymbolFlag = ((nSymbolTrait & kCTFontClassMaskTrait) == kCTFontSymbolicClass);
+    }
+
+    // get the font weight
+    double fWeight = 0;
+    CFNumberRef pWeightNum = (CFNumberRef)CFDictionaryGetValue( pAttrDict, kCTFontWeightTrait );
+    CFNumberGetValue( pWeightNum, kCFNumberDoubleType, &fWeight );
+    int nInt = WEIGHT_NORMAL;
+    if( fWeight > 0 ) {
+        nInt = rint(WEIGHT_NORMAL + fWeight * ((WEIGHT_BLACK - WEIGHT_NORMAL)/0.68));
+        if( nInt > WEIGHT_BLACK )
+            nInt = WEIGHT_BLACK;
+    } else if( fWeight < 0 ) {
+        nInt = rint(WEIGHT_NORMAL + fWeight * ((WEIGHT_NORMAL - WEIGHT_THIN)/0.9));
+        if( nInt < WEIGHT_THIN )
+            nInt = WEIGHT_THIN;
+    }
+    rDFA.meWeight = (FontWeight)nInt;
+
+    // get the font slant
+    double fSlant = 0;
+    CFNumberRef pSlantNum = (CFNumberRef)CFDictionaryGetValue( pAttrDict, kCTFontSlantTrait );
+    CFNumberGetValue( pSlantNum, kCFNumberDoubleType, &fSlant );
+    if( fSlant >= 0.035 )
+        rDFA.meItalic = ITALIC_NORMAL;
+
+    // get width trait
+    double fWidth = 0;
+    CFNumberRef pWidthNum = (CFNumberRef)CFDictionaryGetValue( pAttrDict, kCTFontWidthTrait );
+    CFNumberGetValue( pWidthNum, kCFNumberDoubleType, &fWidth );
+    nInt = WIDTH_NORMAL;
+    if( fWidth > 0 ) {
+        nInt = rint( WIDTH_NORMAL + fWidth * ((WIDTH_ULTRA_EXPANDED - WIDTH_NORMAL)/0.4));
+        if( nInt > WIDTH_ULTRA_EXPANDED )
+            nInt = WIDTH_ULTRA_EXPANDED;
+    } else if( fWidth < 0 ) {
+        nInt = rint( WIDTH_NORMAL + fWidth * ((WIDTH_NORMAL - WIDTH_ULTRA_CONDENSED)/0.5));
+        if( nInt < WIDTH_ULTRA_CONDENSED )
+            nInt = WIDTH_ULTRA_CONDENSED;
+    }
+    rDFA.meWidthType = (FontWidth)nInt;
+
+    // release the attribute dict that we had copied
+    CFRelease( pAttrDict );
+
+    // TODO? also use the HEAD table if available to get more attributes
+//  CFDataRef CTFontCopyTable( CTFontRef, kCTFontTableHead, /*kCTFontTableOptionNoOptions*/kCTFontTableOptionExcludeSynthetic );
+
+#if (OSL_DEBUG_LEVEL >= 1)
+    // update font attributes using the font's postscript name
+    ImplDevFontAttributes rDFA2;
+    CTFontRef pFont = CTFontCreateWithFontDescriptor( pFD, 0.0, NULL );
+    CFStringRef pPSName = CTFontCopyPostScriptName( pFont );
+    const String aPSName = GetOUString( pPSName );
+
+    rDFA2.mbSymbolFlag = false;
+    rDFA2.mePitch      = PITCH_VARIABLE;
+    rDFA2.meWidthType  = WIDTH_NORMAL;
+    rDFA2.meWeight     = WEIGHT_NORMAL;
+    rDFA2.meItalic     = ITALIC_NONE;
+
+    UpdateAttributesFromPSName( aPSName, rDFA2 );
+    CFRelease( pPSName );
+    CFRelease( pFont );
+
+    // show the font details and compare the CTFontDescriptor vs. PSName traits
+    char cMatch = (rDFA.mbSymbolFlag==rDFA2.mbSymbolFlag);
+    cMatch &= (rDFA.meWeight==rDFA2.meWeight);
+    cMatch &= ((rDFA.meItalic==ITALIC_NONE) == (rDFA2.meItalic==ITALIC_NONE));
+    cMatch &= (rDFA.meWidthType==rDFA2.meWidthType);
+    cMatch = cMatch ? '.' : '#';
+
+    char aFN[256], aSN[256];
+    CFStringGetCString( pFamilyName, aFN, sizeof(aFN), kCFStringEncodingUTF8 );
+    CFStringGetCString( pStyleName, aSN, sizeof(aSN), kCFStringEncodingUTF8 );
+
+    const ByteString aPSCName( aPSName, RTL_TEXTENCODING_UTF8 );
+    const char* aPN = aPSCName.GetBuffer();
+    printf("\tCTFont_%d%x%d%d_%c_%d%x%d%d ena=%d s=%02d b=%+.2f i=%+.2f w=%+.2f (\"%s\", \"%s\", \"%s\")\n",
+        (int)rDFA.mbSymbolFlag,(int)rDFA.meWeight,(int)rDFA.meItalic,(int)rDFA.meWidthType,
+        cMatch,
+        (int)rDFA2.mbSymbolFlag,(int)rDFA2.meWeight,(int)rDFA2.meItalic,(int)rDFA2.meWidthType,
+        bFontEnabled,
+        (int)(nSymbolTrait>>kCTFontClassMaskShift),fWeight,fSlant,fWidth,aFN,aSN,aPN);
+#endif // (OSL_DEBUG_LEVEL >= 1)
+
+    if( bFontEnabled)
+    {
+        const sal_IntPtr nFontId = (sal_IntPtr)pValue;
+        CTFontData* pFontData = new CTFontData( rDFA, nFontId );
+        CTFontList* pFontList = (CTFontList*)pContext;
+        pFontList->AddFont( pFontData );
+    }
+}
+
+// =======================================================================
+
+CTFontList::CTFontList()
+:   mpCTFontCollection( NULL )
+,   mpCTFontArray( NULL )
+{}
+
+// -----------------------------------------------------------------------
+
+CTFontList::~CTFontList()
+{
+    CTFontContainer::const_iterator it = maFontContainer.begin();
+    for(; it != maFontContainer.end(); ++it )
+        delete (*it).second;
+    maFontContainer.clear();
+
+    if( mpCTFontArray )
+        CFRelease( mpCTFontArray );
+    if( mpCTFontCollection )
+        CFRelease( mpCTFontCollection );
+}
+
+// -----------------------------------------------------------------------
+
+void CTFontList::AddFont( CTFontData* pFontData )
+{
+    sal_IntPtr nFontId = pFontData->GetFontId();
+    maFontContainer[ nFontId ] = pFontData;
+}
+
+// -----------------------------------------------------------------------
+
+void CTFontList::AnnounceFonts( ImplDevFontList& rFontList ) const
+{
+    CTFontContainer::const_iterator it = maFontContainer.begin();
+    for(; it != maFontContainer.end(); ++it )
+        rFontList.Add( (*it).second->Clone() );
+}
+
+// -----------------------------------------------------------------------
+
+ImplMacFontData* CTFontList::GetFontDataFromId( sal_IntPtr nFontId ) const
+{
+    CTFontContainer::const_iterator it = maFontContainer.find( nFontId );
+    if( it == maFontContainer.end() )
+        return NULL;
+    return (*it).second;
+}
+
+// -----------------------------------------------------------------------
+
+bool CTFontList::Init( void )
+{
+#ifndef DISABLE_CORETEXT_DYNLOAD
+    // check availability of the CoreText API
+    const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
+    if( !rCT.IsActive() )
+        return false;
+#endif // DISABLE_CORETEXT_DYNLOAD
+
+    // enumerate available system fonts
+    static const int nMaxDictEntries = 8;
+    CFMutableDictionaryRef pCFDict = CFDictionaryCreateMutable( NULL,
+        nMaxDictEntries, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
+    CFDictionaryAddValue( pCFDict, kCTFontCollectionRemoveDuplicatesOption, kCFBooleanTrue );
+    mpCTFontCollection = rCT.FontCollectionCreateFromAvailableFonts( pCFDict );
+    CFRelease( pCFDict );
+
+    mpCTFontArray = rCT.FontCollectionCreateMatchingFontDescriptors( mpCTFontCollection );
+    const int nFontCount = CFArrayGetCount( mpCTFontArray );
+    const CFRange aFullRange = CFRangeMake( 0, nFontCount );
+    CFArrayApplyFunction( mpCTFontArray, aFullRange, CTFontEnumCallBack, this );
+
+    return true;
+}
+
+// =======================================================================
+
+#ifndef DISABLE_CORETEXT_DYNLOAD
+
+DynCoreTextSyms::DynCoreTextSyms( void )
+{
+    mbIsActive = false;
+
+    // check if CoreText has been explicitely disabled
+    const char* pEnvStr = getenv( "SAL_DISABLE_CORETEXT");
+    if( pEnvStr && (pEnvStr[0] != '0') )
+        return;
+
+    // check CoreText version
+    GetCoreTextVersion = (uint32_t(*)(void))dlsym( RTLD_DEFAULT, "CTGetCoreTextVersion");
+    if( !GetCoreTextVersion) return;
+
+    const uint32_t nCTVersion = GetCoreTextVersion();
+    static const uint32_t mykCTVersionNumber10_5 = 0x00020000;
+    if( nCTVersion < mykCTVersionNumber10_5)
+        return;
+
+    // load CoreText symbols dynamically
+    LineGetTrailingWhitespaceWidth = (double(*)(CTLineRef))dlsym( RTLD_DEFAULT, "CTLineGetTrailingWhitespaceWidth");
+    if( !LineGetTrailingWhitespaceWidth) return;
+
+    LineCreateJustifiedLine = (CTLineRef(*)(CTLineRef,CGFloat,double))dlsym( RTLD_DEFAULT, "CTLineCreateJustifiedLine");
+    if( !LineCreateJustifiedLine) return;
+
+    LineGetOffsetForStringIndex = (CGFloat(*)(CTLineRef,CFIndex,CGFloat*))dlsym( RTLD_DEFAULT, "CTLineGetOffsetForStringIndex");
+    if( !LineGetOffsetForStringIndex) return;
+
+    LineGetGlyphRuns = (CFArrayRef(*)(CTLineRef))dlsym( RTLD_DEFAULT, "CTLineGetGlyphRuns");
+    if( !LineGetGlyphRuns) return;
+
+    RunGetGlyphCount = (CFIndex(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetGlyphCount");
+    if( !RunGetGlyphCount) return;
+
+    RunGetGlyphsPtr = (const CGGlyph*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetGlyphsPtr");
+    if( !RunGetGlyphsPtr) return;
+
+    RunGetPositionsPtr = (const CGPoint*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetPositionsPtr");
+    if( !RunGetPositionsPtr) return;
+
+    RunGetAdvancesPtr = (const CGSize*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetAdvancesPtr");
+    if( !RunGetAdvancesPtr) return;
+
+    RunGetStringIndicesPtr = (const CFIndex*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetStringIndicesPtr");
+    if( !RunGetStringIndicesPtr) return;
+
+    FontCollectionCreateFromAvailableFonts = (CTFontCollectionRef(*)(CFDictionaryRef))dlsym( RTLD_DEFAULT, "CTFontCollectionCreateFromAvailableFonts");
+    if( !FontCollectionCreateFromAvailableFonts) return;
+
+    FontCollectionCreateMatchingFontDescriptors = (CFArrayRef(*)(CTFontCollectionRef))dlsym( RTLD_DEFAULT, "CTFontCollectionCreateMatchingFontDescriptors");
+    if( !FontCollectionCreateMatchingFontDescriptors) return;
+
+    FontCreatePathForGlyph = (CGPathRef(*)(CTFontRef,CGGlyph,const CGAffineTransform*))dlsym( RTLD_DEFAULT, "CTFontCreatePathForGlyph");
+    if( !FontCreatePathForGlyph) return;
+
+    FontGetBoundingRectsForGlyphs = (CGRect(*)(CTFontRef,CTFontOrientation,CGGlyph*,CGRect*,CFIndex))dlsym( RTLD_DEFAULT, "CTFontGetBoundingRectsForGlyphs");
+    if( !FontGetBoundingRectsForGlyphs) return;
+
+    mbIsActive = true;
+}
+
+// -----------------------------------------------------------------------
+
+const DynCoreTextSyms& DynCoreTextSyms::get( void )
+{
+    static DynCoreTextSyms aCT;
+    return aCT;
+}
+
+#endif // DISABLE_CORETEXT_DYNLOAD
+
+// =======================================================================
+
+SystemFontList* GetCoretextFontList( void )
+{
+    CTFontList* pList = new CTFontList();
+    if( !pList->Init() ) {
+        delete pList;
+        return NULL;
+    }
+
+    return pList;
+}
+
+// =======================================================================
+
diff --git a/vcl/coretext/ctfonts.hxx b/vcl/coretext/ctfonts.hxx
new file mode 100644
index 0000000..c62c1f9
--- /dev/null
+++ b/vcl/coretext/ctfonts.hxx
@@ -0,0 +1,90 @@
+/**************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+#include "coretext/salgdi2.h"
+#include "sallayout.hxx"
+
+#include <ApplicationServices/ApplicationServices.h>
+
+// =======================================================================
+
+class CTTextStyle
+:   public ImplMacTextStyle
+{
+public:
+    explicit    CTTextStyle( const ImplFontSelectData& );
+    virtual     ~CTTextStyle( void );
+
+    virtual SalLayout* GetTextLayout( void ) const;
+
+    virtual void    GetFontMetric( float fDPIY, ImplFontMetricData& ) const;
+    virtual bool    GetGlyphBoundRect( sal_GlyphId, Rectangle& ) const;
+    virtual bool    GetGlyphOutline( sal_GlyphId, basegfx::B2DPolyPolygon& ) const;
+
+    virtual void    SetTextColor( const RGBAColor& );
+
+private:
+    /// CoreText text style object
+    CFMutableDictionaryRef  mpStyleDict;
+
+    friend class CTLayout;
+    CFMutableDictionaryRef  GetStyleDict( void ) const { return mpStyleDict; }
+};
+
+// =======================================================================
+
+#ifndef DISABLE_CORETEXT_DYNLOAD
+// the CoreText symbols may need to be loaded dynamically
+// since platform targets like OSX 10.4 do not provide all required symbols
+// TODO: avoid the dlsym stuff if the target platform is >= OSX10.5
+
+class DynCoreTextSyms
+{
+public:
+    // dynamic symbols to access the CoreText API
+    uint32_t    (*GetCoreTextVersion)(void);
+    CTFontCollectionRef (*FontCollectionCreateFromAvailableFonts)(CFDictionaryRef);
+    CFArrayRef  (*FontCollectionCreateMatchingFontDescriptors)(CTFontCollectionRef);
+    CGPathRef   (*FontCreatePathForGlyph)(CTFontRef,CGGlyph,const CGAffineTransform*);
+    CGRect          (*FontGetBoundingRectsForGlyphs)(CTFontRef,CTFontOrientation,CGGlyph*,CGRect*,CFIndex);
+    CTLineRef   (*LineCreateJustifiedLine)(CTLineRef,CGFloat,double);
+    double      (*LineGetTrailingWhitespaceWidth)(CTLineRef);
+    CGFloat     (*LineGetOffsetForStringIndex)(CTLineRef,CFIndex,CGFloat*);
+    CFArrayRef  (*LineGetGlyphRuns)(CTLineRef);
+    CFIndex     (*RunGetGlyphCount)(CTRunRef);
+    const CGGlyph*  (*RunGetGlyphsPtr)(CTRunRef);
+    const CGPoint*  (*RunGetPositionsPtr)(CTRunRef);
+    const CGSize*   (*RunGetAdvancesPtr)(CTRunRef);
+    const CFIndex * (*RunGetStringIndicesPtr)(CTRunRef);
+
+    // singleton helpers
+    static const DynCoreTextSyms& get( void );
+    bool        IsActive( void ) const { return mbIsActive; }
+
+private:
+    explicit    DynCoreTextSyms( void );
+    bool        mbIsActive;
+};
+
+#endif // DISABLE_CORETEXT_DYNLOAD
+
+// =======================================================================
+
diff --git a/vcl/coretext/ctlayout.cxx b/vcl/coretext/ctlayout.cxx
new file mode 100644
index 0000000..d232910
--- /dev/null
+++ b/vcl/coretext/ctlayout.cxx
@@ -0,0 +1,500 @@
+/**************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+//#include "salgdi.hxx"
+#include "tools/debug.hxx"
+
+#include "ctfonts.hxx"
+
+// =======================================================================
+
+class CTLayout
+:   public SalLayout
+{
+public:
+    explicit        CTLayout( const CTTextStyle* );
+    virtual         ~CTLayout( void );
+
+    virtual bool    LayoutText( ImplLayoutArgs& );
+    virtual void    AdjustLayout( ImplLayoutArgs& );
+    virtual void    DrawText( SalGraphics& ) const;
+
+    virtual int     GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
+                        sal_Int32* pGlyphAdvances, int* pCharIndexes ) const;
+
+    virtual long    GetTextWidth() const;
+    virtual long    FillDXArray( sal_Int32* pDXArray ) const;
+    virtual int     GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const;
+    virtual void    GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray ) const;
+    virtual bool    GetGlyphOutlines( SalGraphics&, PolyPolyVector& ) const;
+    virtual bool    GetBoundRect( SalGraphics&, Rectangle& ) const;
+
+    const ImplFontData* GetFallbackFontData( sal_GlyphId ) const;
+
+    virtual void    InitFont( void) const;
+    virtual void    MoveGlyph( int nStart, long nNewXPos );
+    virtual void    DropGlyph( int nStart );
+    virtual void    Simplify( bool bIsBase );
+
+private:
+    const CTTextStyle* const    mpTextStyle;
+
+    // CoreText specific objects
+    CFAttributedStringRef mpAttrString;
+    CTLineRef mpCTLine;
+
+    int mnCharCount;        // ==mnEndCharPos-mnMinCharPos
+    int mnTrailingSpaces;
+
+    // to prevent overflows
+    // font requests get size limited by downscaling huge fonts
+    // in these cases the font scale becomes something bigger than 1.0
+    float mfFontScale; // TODO: does CoreText have a font size limit?
+
+    // cached details about the resulting layout
+    // mutable members since these details are all lazy initialized
+    mutable double  mfCachedWidth;          // cached value of resulting typographical width
+    mutable double  mfTrailingSpaceWidth;   // in Pixels
+
+    // x-offset relative to layout origin
+    // currently only used in RTL-layouts
+    mutable long    mnBaseAdv;
+};
+
+// =======================================================================
+
+CTLayout::CTLayout( const CTTextStyle* pTextStyle )
+:   mpTextStyle( pTextStyle )
+,   mpAttrString( NULL )
+,   mpCTLine( NULL )
+,   mnCharCount( 0 )
+,   mnTrailingSpaces( 0 )
+,   mfFontScale( pTextStyle->mfFontScale )
+,   mfCachedWidth( -1 )
+,   mfTrailingSpaceWidth( 0 )
+,   mnBaseAdv( 0 )
+{
+    CFRetain( mpTextStyle->GetStyleDict() );
+}
+
+// -----------------------------------------------------------------------
+
+CTLayout::~CTLayout()
+{
+    if( mpCTLine )
+        CFRelease( mpCTLine );
+    if( mpAttrString )
+        CFRelease( mpAttrString );
+    CFRelease( mpTextStyle->GetStyleDict() );
+}
+
+// -----------------------------------------------------------------------
+
+bool CTLayout::LayoutText( ImplLayoutArgs& rArgs )
+{
+    if( mpAttrString )
+        CFRelease( mpAttrString );
+    mpAttrString = NULL;
+    if( mpCTLine )
+        CFRelease( mpCTLine );
+    mpCTLine = NULL;
+
+    SalLayout::AdjustLayout( rArgs );
+    mnCharCount = mnEndCharPos - mnMinCharPos;
+
+    // short circuit if there is nothing to do
+    if( mnCharCount <= 0 )
+        return false;
+
+    // create the CoreText line layout
+    CFStringRef aCFText = CFStringCreateWithCharactersNoCopy( NULL, rArgs.mpStr + mnMinCharPos, mnCharCount, kCFAllocatorNull );
+    mpAttrString = CFAttributedStringCreate( NULL, aCFText, mpTextStyle->GetStyleDict() );
+    mpCTLine = CTLineCreateWithAttributedString( mpAttrString );
+    CFRelease( aCFText);
+
+    // get info about trailing whitespace to prepare for text justification in AdjustLayout()
+    mnTrailingSpaces = 0;
+    for( int i = mnEndCharPos; --i >= mnMinCharPos; ++mnTrailingSpaces )
+        if( !IsSpacingGlyph( rArgs.mpStr[i] | GF_ISCHAR ))
+            break;
+    return true;
+}
+
+// -----------------------------------------------------------------------
+
+void CTLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+{
+    if( !mpCTLine)
+        return;
+
+    const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
+    // CoreText fills trailing space during justification so we have to
+    // take that into account when requesting CT to justify something
+    mfTrailingSpaceWidth = rCT.LineGetTrailingWhitespaceWidth( mpCTLine );
+    const int nTrailingSpaceWidth = rint( mfFontScale * mfTrailingSpaceWidth );
+
+    int nOrigWidth = GetTextWidth();
+    nOrigWidth -= nTrailingSpaceWidth;
+    int nPixelWidth = rArgs.mnLayoutWidth;
+    if( nPixelWidth )
+    {
+        nPixelWidth -= nTrailingSpaceWidth;
+        if( nPixelWidth <= 0)
+            return;
+    }
+    else if( rArgs.mpDXArray )
+    {
+        // for now we are only interested in the layout width
+        // TODO: use all mpDXArray elements for layouting
+        nPixelWidth = rArgs.mpDXArray[ mnCharCount - 1 - mnTrailingSpaces ];
+    }
+
+    // in RTL-layouts trailing spaces are leftmost
+    // TODO: use BiDi-algorithm to thoroughly check this assumption
+    if( rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL)
+        mnBaseAdv = nTrailingSpaceWidth;
+
+    // return early if there is nothing to do
+    if( nPixelWidth <= 0 )
+        return;
+
+    // HACK: justification requests which change the width by just one pixel are probably
+    // #i86038# introduced by lossy conversions between integer based coordinate system
+    if( (nOrigWidth >= nPixelWidth-1) && (nOrigWidth <= nPixelWidth+1) )
+        return;
+
+    CTLineRef pNewCTLine = rCT.LineCreateJustifiedLine( mpCTLine, 1.0, nPixelWidth / mfFontScale );
+    if( !pNewCTLine ) { // CTLineCreateJustifiedLine can and does fail
+        // handle failure by keeping the unjustified layout
+        // TODO: a better solution such as
+        // - forcing glyph overlap
+        // - changing the font size
+        // - changing the CTM matrix
+        return;
+    }
+    CFRelease( mpCTLine );
+    mpCTLine = pNewCTLine;
+    mfCachedWidth = -1; // TODO: can we set it directly to target width we requested? For now we re-measure
+    mfTrailingSpaceWidth = 0;
+}
+
+// -----------------------------------------------------------------------
+
+void CTLayout::DrawText( SalGraphics& rGraphics ) const
+{
+    AquaSalGraphics& rAquaGraphics = static_cast<AquaSalGraphics&>(rGraphics);
+
+    // short circuit if there is nothing to do
+    if( (mnCharCount <= 0)
+    ||  !rAquaGraphics.CheckContext() )
+        return;
+
+    // the view is vertically flipped => flipped glyphs
+    // so apply a temporary transformation that it flips back
+    // also compensate if the font was size limited
+    CGContextSaveGState( rAquaGraphics.mrContext );
+    CGContextScaleCTM( rAquaGraphics.mrContext, +mfFontScale, -mfFontScale );
+    CGContextSetShouldAntialias( rAquaGraphics.mrContext, !rAquaGraphics.mbNonAntialiasedText );
+
+    // Draw the text
+    const Point aVclPos = GetDrawPosition( Point(mnBaseAdv,0) );
+    CGPoint aTextPos = { +aVclPos.X()/mfFontScale, -aVclPos.Y()/mfFontScale };
+
+    if( mpTextStyle->mfFontRotation != 0.0 )
+    {
+        const CGFloat fRadians = mpTextStyle->mfFontRotation;
+        CGContextRotateCTM( rAquaGraphics.mrContext, +fRadians );
+
+        const CGAffineTransform aInvMatrix = CGAffineTransformMakeRotation( -fRadians );
+        aTextPos = CGPointApplyAffineTransform( aTextPos, aInvMatrix );
+    }
+
+    CGContextSetTextPosition( rAquaGraphics.mrContext, aTextPos.x, aTextPos.y );
+    CTLineDraw( mpCTLine, rAquaGraphics.mrContext );
+
+    // request an update of the changed window area
+    if( rAquaGraphics.IsWindowGraphics() )
+    {
+        const CGRect aInkRect = CTLineGetImageBounds( mpCTLine, rAquaGraphics.mrContext );
+        const CGRect aRefreshRect = CGContextConvertRectToDeviceSpace( rAquaGraphics.mrContext, aInkRect );
+        rAquaGraphics.RefreshRect( aRefreshRect );
+    }
+
+    // restore the original graphic context transformations
+    CGContextRestoreGState( rAquaGraphics.mrContext );
+}
+
+// -----------------------------------------------------------------------
+
+int CTLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIDs, Point& rPos, int& nStart,
+    sal_Int32* pGlyphAdvances, int* pCharIndexes ) const
+{
+    if( !mpCTLine )
+        return 0;
+
+    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;
+
+    const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
+    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;
+
+    // TODO: iterate over cached layout
+    CFArrayRef aGlyphRuns = rCT.LineGetGlyphRuns( mpCTLine );
+    const int nRunCount = CFArrayGetCount( aGlyphRuns );
+    for( int nRunIndex = 0; nRunIndex < nRunCount; ++nRunIndex ) {
+        CTRunRef pGlyphRun = (CTRunRef)CFArrayGetValueAtIndex( aGlyphRuns, nRunIndex );
+        const CFIndex nGlyphsInRun = rCT.RunGetGlyphCount( pGlyphRun );
+        // skip to the first glyph run of interest
+        if( nSubIndex >= nGlyphsInRun ) {
+            nSubIndex -= nGlyphsInRun;
+            continue;
+        }
+        const CFRange aFullRange = CFRangeMake( 0, nGlyphsInRun );
+
+        // get glyph run details
+        const CGGlyph* pCGGlyphIdx = rCT.RunGetGlyphsPtr( pGlyphRun );
+        if( !pCGGlyphIdx ) {
+            aCGGlyphVec.reserve( nGlyphsInRun );
+            CTRunGetGlyphs( pGlyphRun, aFullRange, &aCGGlyphVec[0] );
+            pCGGlyphIdx = &aCGGlyphVec[0];
+        }
+        const CGPoint* pCGGlyphPos = rCT.RunGetPositionsPtr( pGlyphRun );
+        if( !pCGGlyphPos ) {
+            aCGPointVec.reserve( nGlyphsInRun );
+            CTRunGetPositions( pGlyphRun, aFullRange, &aCGPointVec[0] );
+            pCGGlyphPos = &aCGPointVec[0];
+        }
+
+        const CGSize* pCGGlyphAdvs = NULL;
+        if( pGlyphAdvances) {
+            pCGGlyphAdvs = rCT.RunGetAdvancesPtr( pGlyphRun );
+            if( !pCGGlyphAdvs) {
+                aCGSizeVec.reserve( nGlyphsInRun );
+                CTRunGetAdvances( pGlyphRun, aFullRange, &aCGSizeVec[0] );
+                pCGGlyphAdvs = &aCGSizeVec[0];
+            }
+        }
+
+        const CFIndex* pCGGlyphStrIdx = NULL;
+        if( pCharIndexes) {
+            pCGGlyphStrIdx = rCT.RunGetStringIndicesPtr( pGlyphRun );
+            if( !pCGGlyphStrIdx) {
+                aCFIndexVec.reserve( nGlyphsInRun );
+                CTRunGetStringIndices( pGlyphRun, aFullRange, &aCFIndexVec[0] );
+                pCGGlyphStrIdx = &aCFIndexVec[0];
+            }
+        }
+
+        // get the details for each interesting glyph
+        // TODO: handle nLen>1
+        for(; (--nLen >= 0) && (nSubIndex < nGlyphsInRun); ++nSubIndex, ++nStart )
+        {
+            // convert glyph details for VCL
+            *(pGlyphIDs++) = pCGGlyphIdx[ nSubIndex ];
+            if( pGlyphAdvances )
+                *(pGlyphAdvances++) = pCGGlyphAdvs[ nSubIndex ].width;
+            if( pCharIndexes )
+                *(pCharIndexes++) = pCGGlyphStrIdx[ nSubIndex] + mnMinCharPos;
+            if( !nCount++ ) {
+                const CGPoint& rCurPos = pCGGlyphPos[ nSubIndex ];
+                rPos = GetDrawPosition( Point( mfFontScale * rCurPos.x, mfFontScale * rCurPos.y) );
+            }
+        }
+        nSubIndex = 0; // prepare for the next glyph run
+        break; // TODO: handle nLen>1
+    }
+
+    return nCount;
+}
+
+// -----------------------------------------------------------------------
+
+long CTLayout::GetTextWidth() const
+{
+    if( (mnCharCount <= 0) || !mpCTLine )
+        return 0;
+
+    if( mfCachedWidth < 0.0 ) {
+        mfCachedWidth = CTLineGetTypographicBounds( mpCTLine, NULL, NULL, NULL);
+        mfTrailingSpaceWidth = CTLineGetTrailingWhitespaceWidth( mpCTLine);
+    }
+
+    const long nScaledWidth = lrint( mfFontScale * (mfCachedWidth + mfTrailingSpaceWidth));
+    return nScaledWidth;
+}
+
+// -----------------------------------------------------------------------
+
+long CTLayout::FillDXArray( sal_Int32* pDXArray ) const
+{
+    // short circuit requests which don't need full details
+    if( !pDXArray )
+        return GetTextWidth();
+
+    // check assumptions
+    DBG_ASSERT( mfTrailingSpaceWidth==0.0, "CTLayout::FillDXArray() with fTSW!=0" );
+
+    long nPixWidth = GetTextWidth();
+    if( pDXArray ) {
+        // initialize the result array
+        for( int i = 0; i < mnCharCount; ++i)
+            pDXArray[i] = 0;
+        // 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;
+        for( int nRunIndex = 0; nRunIndex < nRunCount; ++nRunIndex ) {
+            CTRunRef pGlyphRun = (CTRunRef)CFArrayGetValueAtIndex( aGlyphRuns, nRunIndex );
+            const CFIndex nGlyphCount = CTRunGetGlyphCount( pGlyphRun );
+            const CFRange aFullRange = CFRangeMake( 0, nGlyphCount );
+            aSizeVec.reserve( nGlyphCount );
+            aIndexVec.reserve( nGlyphCount );
+            CTRunGetAdvances( pGlyphRun, aFullRange, &aSizeVec[0] );
+            CTRunGetStringIndices( pGlyphRun, aFullRange, &aIndexVec[0] );
+            for( int i = 0; i != nGlyphCount; ++i ) {
+                const int nRelIdx = aIndexVec[i];
+                pDXArray[ nRelIdx ] += aSizeVec[i].width;
+            }
+        }
+    }
+
+    return nPixWidth;
+}
+
+// -----------------------------------------------------------------------
+
+int CTLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const
+{
+    if( !mpCTLine )
+        return STRING_LEN;
+
+    CTTypesetterRef aCTTypeSetter = CTTypesetterCreateWithAttributedString( mpAttrString );
+    const double fCTMaxWidth = (double)nMaxWidth / (nFactor * mfFontScale);
+    CFIndex nIndex = CTTypesetterSuggestClusterBreak( aCTTypeSetter, 0, fCTMaxWidth );
+    if( nIndex >= mnCharCount )
+        return STRING_LEN;
+
+    nIndex += mnMinCharPos;
+    return (int)nIndex;
+}
+
+// -----------------------------------------------------------------------
+
+void CTLayout::GetCaretPositions( int nMaxIndex, sal_Int32* pCaretXArray ) const
+{
+    DBG_ASSERT( ((nMaxIndex>0)&&!(nMaxIndex&1)),
+        "CTLayout::GetCaretPositions() : invalid number of caret pairs requested");
+
+    // initialize the caret positions
+    for( int i = 0; i < nMaxIndex; ++i )
+        pCaretXArray[ i ] = -1;
+
+    const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
+    for( int n = 0; n <= mnCharCount; ++n )
+    {
+        // measure the characters cursor position
+        CGFloat fPos2 = -1;
+        const CGFloat fPos1 = rCT.LineGetOffsetForStringIndex( mpCTLine, n, &fPos2 );
+        (void)fPos2; // TODO: split cursor at line direction change
+        // update previous trailing position
+        if( n > 0 )
+            pCaretXArray[ 2*n-1 ] = lrint( fPos1 * mfFontScale );
+        // update current leading position
+        if( 2*n >= nMaxIndex )
+            break;
+        pCaretXArray[ 2*n+0 ] = lrint( fPos1 * mfFontScale );
+    }
+}
+
+// -----------------------------------------------------------------------
+
+bool CTLayout::GetBoundRect( SalGraphics& rGraphics, Rectangle& rVCLRect ) const
+{
+    AquaSalGraphics& rAquaGraphics = static_cast<AquaSalGraphics&>(rGraphics);
+    CGRect aMacRect = CTLineGetImageBounds( mpCTLine, rAquaGraphics.mrContext );
+    CGPoint aMacPos = CGContextGetTextPosition( rAquaGraphics.mrContext );
+    aMacRect.origin.x -= aMacPos.x;
+    aMacRect.origin.y -= aMacPos.y;
+
+    const Point aPos = GetDrawPosition( Point(mnBaseAdv, 0) );
+
+    // CoreText top-bottom are vertically flipped from a VCL aspect
+    rVCLRect.Left()   = aPos.X() + mfFontScale * aMacRect.origin.x;
+    rVCLRect.Right()  = aPos.X() + mfFontScale * (aMacRect.origin.x + aMacRect.size.width);
+    rVCLRect.Bottom() = aPos.Y() - mfFontScale * aMacRect.origin.y;
+    rVCLRect.Top()    = aPos.Y() - mfFontScale * (aMacRect.origin.y + aMacRect.size.height);
+    return true;
+}
+
+// =======================================================================
+
+// glyph fallback is supported directly by Aqua
+// so methods used only by MultiSalLayout can be dummy implementated
+bool CTLayout::GetGlyphOutlines( SalGraphics&, PolyPolyVector& ) const { return false; }
+void CTLayout::InitFont() const {}
+void CTLayout::MoveGlyph( int /*nStart*/, long /*nNewXPos*/ ) {}
+void CTLayout::DropGlyph( int /*nStart*/ ) {}
+void CTLayout::Simplify( bool /*bIsBase*/ ) {}
+
+// get the ImplFontData for a glyph fallback font
+// for a glyphid that was returned by CTLayout::GetNextGlyphs()
+const ImplFontData* CTLayout::GetFallbackFontData( sal_GlyphId /*nGlyphId*/ ) const
+{
+#if 0
+    // check if any fallback fonts were needed
+    if( !mpFallbackInfo )
+        return NULL;
+    // check if the current glyph needs a fallback font
+    int nFallbackLevel = (nGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
+    if( !nFallbackLevel )
+        return NULL;
+    pFallbackFont = mpFallbackInfo->GetFallbackFontData( nFallbackLevel );
+#else
+    // let CoreText's font cascading handle glyph fallback
+    const ImplFontData* pFallbackFont = NULL;
+#endif
+    return pFallbackFont;
+}
+
+// =======================================================================
+
+SalLayout* CTTextStyle::GetTextLayout( void ) const
+{
+    return new CTLayout( this);
+}
+
+// =======================================================================
+
diff --git a/vcl/coretext/salgdi2.cxx b/vcl/coretext/salgdi2.cxx
new file mode 100644
index 0000000..c118440
--- /dev/null
+++ b/vcl/coretext/salgdi2.cxx
@@ -0,0 +1,918 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "sal/config.h"
+
+#include "osl/file.hxx"
+#include "osl/process.h"
+
+#include "osl/mutex.hxx"
+
+#include "rtl/bootstrap.h"
+#include "rtl/strbuf.hxx"
+
+#include "basegfx/range/b2drectangle.hxx"
+#include "basegfx/polygon/b2dpolygon.hxx"
+#include "basegfx/polygon/b2dpolygontools.hxx"
+#include "basegfx/matrix/b2dhommatrix.hxx"
+#include "basegfx/matrix/b2dhommatrixtools.hxx"
+
+#include "vcl/sysdata.hxx"
+#include "vcl/svapp.hxx"
+
+#include "aqua/atsui/salgdi.h"
+#include "aqua/salframe.h"
+#ifdef ENABLE_CORETEXT
+#include "ctfonts.hxx"
+#else
+#include "atsfonts.hxx"
+#endif
+
+#include "fontsubset.hxx"
+#include "impfont.hxx"
+#include "sallayout.hxx"
+#include "sft.hxx"
+
+
+using namespace vcl;
+
+// =======================================================================
+
+SystemFontList::~SystemFontList( void )
+{}
+
+
+// ATSUI is deprecated in 10.6 (or already 10.5?)
+#if HAVE_GCC_PRAGMA_DIAGNOSTIC_MODIFY
+#pragma GCC diagnostic warning "-Wdeprecated-declarations"
+#endif
+
+// =======================================================================
+
+ImplMacTextStyle::ImplMacTextStyle( const ImplFontSelectData& rReqFont )
+:   mpFontData( (ImplMacFontData*)rReqFont.mpFontData )
+,   mfFontScale( 1.0 )
+,   mfFontStretch( 1.0 )
+,   mfFontRotation( 0.0 )
+{}
+
+// -----------------------------------------------------------------------
+
+ImplMacTextStyle::~ImplMacTextStyle( void )
+{}
+
+// =======================================================================
+
+ImplMacFontData::ImplMacFontData( const ImplMacFontData& rSrc )
+:   ImplFontData( rSrc )
+,   mnFontId( rSrc.mnFontId )
+,   mpCharMap( rSrc.mpCharMap )
+,   mbOs2Read( rSrc.mbOs2Read )
+,   mbHasOs2Table( rSrc.mbHasOs2Table )
+,   mbCmapEncodingRead( rSrc.mbCmapEncodingRead )
+,   mbHasCJKSupport( rSrc.mbHasCJKSupport )
+{
+    if( mpCharMap )
+        mpCharMap->AddReference();
+}
+
+// -----------------------------------------------------------------------
+
+ImplMacFontData::ImplMacFontData( const ImplDevFontAttributes& rDFA, sal_IntPtr nFontId )
+:   ImplFontData( rDFA, 0 )
+,   mnFontId( nFontId )
+,   mpCharMap( NULL )
+,   mbOs2Read( false )
+,   mbHasOs2Table( false )
+,   mbCmapEncodingRead( false )
+,   mbHasCJKSupport( false )
+,   mbFontCapabilitiesRead( false )
+{}
+
+// -----------------------------------------------------------------------
+
+ImplMacFontData::~ImplMacFontData()
+{
+    if( mpCharMap )
+        mpCharMap->DeReference();
+}
+
+// -----------------------------------------------------------------------
+
+sal_IntPtr ImplMacFontData::GetFontId() const
+{
+    return (sal_IntPtr)mnFontId;
+}
+
+// -----------------------------------------------------------------------
+
+ImplFontEntry* ImplMacFontData::CreateFontInstance(FontSelectPattern& rFSD) const
+{
+    return new ImplFontEntry(rFSD);
+}
+
+// -----------------------------------------------------------------------
+
+static unsigned GetUShort( const unsigned char* p ){return((p[0]<<8)+p[1]);}
+static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
+
+#if MACOSX_SDK_VERSION >= 1070
+extern "C" {
+extern ATSFontRef FMGetATSFontRefFromFont(FMFont iFont);
+}
+#endif
+
+const ImplFontCharMap* ImplMacFontData::GetImplFontCharMap() const
+{
+    // return the cached charmap
+    if( mpCharMap )
+        return mpCharMap;
+
+    // set the default charmap
+    mpCharMap = ImplFontCharMap::GetDefaultMap();
+    mpCharMap->AddReference();
+
+    // get the CMAP byte size
+    // allocate a buffer for the CMAP raw data
+    const int nBufSize = GetFontTable( "cmap", NULL );
+    DBG_ASSERT( (nBufSize > 0), "ImplMacFontData::GetImplFontCharMap : GetFontTable1 failed!\n");
+    if( nBufSize <= 0 )
+        return mpCharMap;
+
+    // get the CMAP raw data
+    ByteVector aBuffer( nBufSize );
+    const int nRawLength = GetFontTable( "cmap", &aBuffer[0] );
+    DBG_ASSERT( (nRawLength > 0), "ImplMacFontData::GetImplFontCharMap : GetFontTable2 failed!\n");
+    if( nRawLength <= 0 )
+        return mpCharMap;
+    DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::GetImplFontCharMap : ByteCount mismatch!\n");
+
+    // parse the CMAP
+    CmapResult aCmapResult;
+    if( ParseCMAP( &aBuffer[0], nRawLength, aCmapResult ) )
+    {
+        // create the matching charmap
+        mpCharMap->DeReference();
+        mpCharMap = new ImplFontCharMap( aCmapResult );
+        mpCharMap->AddReference();
+    }
+
+    return mpCharMap;
+}
+
+bool ImplMacFontData::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
+{
+    // read this only once per font
+    if( mbFontCapabilitiesRead )
+    {
+        rFontCapabilities = maFontCapabilities;
+        return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty();
+    }
+    mbFontCapabilitiesRead = true;
+
+    // prepare to get the GSUB table raw data
+    ATSFontRef rFont = FMGetATSFontRefFromFont( mnFontId );
+    ByteCount nBufSize = 0;
+    OSStatus eStatus;
+    eStatus = ATSFontGetTable( rFont, GetTag("GSUB"), 0, 0, NULL, &nBufSize );
+    if( eStatus == noErr )
+    {
+        // allocate a buffer for the GSUB raw data
+        ByteVector aBuffer( nBufSize );
+        // get the GSUB raw data
+        ByteCount nRawLength = 0;
+        eStatus = ATSFontGetTable( rFont, GetTag("GSUB"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
+        if( eStatus == noErr )
+        {
+            const unsigned char* pGSUBTable = &aBuffer[0];
+            vcl::getTTScripts(maFontCapabilities.maGSUBScriptTags, pGSUBTable, nRawLength);
+        }
+    }
+    eStatus = ATSFontGetTable( rFont, GetTag("OS/2"), 0, 0, NULL, &nBufSize );
+    if( eStatus == noErr )
+    {
+        // allocate a buffer for the GSUB raw data
+        ByteVector aBuffer( nBufSize );
+        // get the OS/2 raw data
+        ByteCount nRawLength = 0;
+        eStatus = ATSFontGetTable( rFont, GetTag("OS/2"), 0, nBufSize, (void*)&aBuffer[0], &nRawLength );
+        if( eStatus == noErr )
+        {
+            const unsigned char* pOS2Table = &aBuffer[0];
+            vcl::getTTCoverage(
+                maFontCapabilities.maUnicodeRange,
+                maFontCapabilities.maCodePageRange,
+                pOS2Table, nRawLength);
+        }
+    }
+    rFontCapabilities = maFontCapabilities;
+    return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplMacFontData::ReadOs2Table( void ) const
+{
+    // read this only once per font
+    if( mbOs2Read )
+        return;
+    mbOs2Read = true;
+    mbHasOs2Table = false;
+
+    // prepare to get the OS/2 table raw data
+    const int nBufSize = GetFontTable( "OS/2", NULL );
+    DBG_ASSERT( (nBufSize > 0), "ImplMacFontData::ReadOs2Table : GetFontTable1 failed!\n");
+    if( nBufSize <= 0 )
+        return;
+
+    // get the OS/2 raw data
+    ByteVector aBuffer( nBufSize );
+    const int nRawLength = GetFontTable( "cmap", &aBuffer[0] );
+    DBG_ASSERT( (nRawLength > 0), "ImplMacFontData::ReadOs2Table : GetFontTable2 failed!\n");
+    if( nRawLength <= 0 )
+        return;
+    DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::ReadOs2Table : ByteCount mismatch!\n");
+    mbHasOs2Table = true;
+
+    // parse the OS/2 raw data
+    // TODO: also analyze panose info, etc.
+
+    // check if the fonts needs the "CJK extra leading" heuristic
+    const unsigned char* pOS2map = &aBuffer[0];
+    const sal_uInt32 nVersion = GetUShort( pOS2map );
+    if( nVersion >= 0x0001 )
+    {
+        sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
+        if( ulUnicodeRange2 & 0x2DF00000 )
+            mbHasCJKSupport = true;
+    }
+}
+
+void ImplMacFontData::ReadMacCmapEncoding( void ) const
+{
+    // read this only once per font
+    if( mbCmapEncodingRead )
+        return;
+    mbCmapEncodingRead = true;
+
+    const int nBufSize = GetFontTable( "cmap", NULL );
+    if( nBufSize <= 0 )
+        return;
+
+    // get the CMAP raw data
+    ByteVector aBuffer( nBufSize );
+    const int nRawLength = GetFontTable( "cmap", &aBuffer[0] );
+    if( nRawLength < 24 )
+        return;
+    DBG_ASSERT( (nBufSize==nRawLength), "ImplMacFontData::ReadMacCmapEncoding : ByteCount mismatch!\n");
+
+    const unsigned char* pCmap = &aBuffer[0];
+    if( GetUShort( pCmap ) != 0x0000 )
+        return;
+
+    // check if the fonts needs the "CJK extra leading" heuristic
+    int nSubTables = GetUShort( pCmap + 2 );
+
+    for( const unsigned char* p = pCmap + 4; --nSubTables >= 0; p += 8 )
+    {
+        int nPlatform = GetUShort( p );
+        if( nPlatform == kFontMacintoshPlatform ) {
+            int nEncoding = GetUShort (p + 2 );
+            if( nEncoding == kFontJapaneseScript ||
+                nEncoding == kFontTraditionalChineseScript ||
+                nEncoding == kFontKoreanScript ||
+                nEncoding == kFontSimpleChineseScript )
+            {
+                mbHasCJKSupport = true;
+                break;
+            }
+        }
+    }
+}
+
+// -----------------------------------------------------------------------
+
+bool ImplMacFontData::HasCJKSupport( void ) const
+{
+    ReadOs2Table();
+    if( !mbHasOs2Table )
+        ReadMacCmapEncoding();
+
+    return mbHasCJKSupport;
+}
+
+// =======================================================================
+
+AquaSalGraphics::AquaSalGraphics()
+    : mpFrame( NULL )
+    , mxLayer( NULL )
+    , mrContext( NULL )
+    , mpXorEmulation( NULL )
+    , mnXorMode( 0 )
+    , mnWidth( 0 )
+    , mnHeight( 0 )
+    , mnBitmapDepth( 0 )
+    , mnRealDPIX( 0 )
+    , mnRealDPIY( 0 )
+    , mfFakeDPIScale( 1.0 )
+    , mxClipPath( NULL )
+    , maLineColor( COL_WHITE )
+    , maFillColor( COL_BLACK )
+    , mpMacFontData( NULL )
+    , mpMacTextStyle( NULL )
+    , maTextColor( COL_BLACK )
+    , mbNonAntialiasedText( false )
+    , mbPrinter( false )
+    , mbVirDev( false )
+    , mbWindow( false )
+{}
+
+// -----------------------------------------------------------------------
+
+AquaSalGraphics::~AquaSalGraphics()
+{
+    CGPathRelease( mxClipPath );
+    delete mpMacTextStyle;
+
+    if( mpXorEmulation )
+        delete mpXorEmulation;
+
+    if( mxLayer )
+        CGLayerRelease( mxLayer );
+    else if( mrContext && mbWindow )
+    {
+        // destroy backbuffer bitmap context that we created ourself
+        CGContextRelease( mrContext );
+        mrContext = NULL;
+        // memory is freed automatically by maOwnContextMemory
+    }
+}
+
+// =======================================================================
+
+void AquaSalGraphics::SetTextColor( SalColor nSalColor )
+{
+    maTextColor = RGBAColor( nSalColor );
+    if( mpMacTextStyle)
+        mpMacTextStyle->SetTextColor( maTextColor );
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int /*nFallbackLevel*/ )
+{
+    mpMacTextStyle->GetFontMetric( mfFakeDPIScale, *pMetric );
+}
+
+// -----------------------------------------------------------------------
+
+sal_uLong AquaSalGraphics::GetKernPairs( sal_uLong, ImplKernPairData* )
+{
+    return 0;
+}
+
+// -----------------------------------------------------------------------
+
+static bool AddTempFontDir( const char* pDir )
+{
+    FSRef aPathFSRef;
+    Boolean bIsDirectory = true;
+    OSStatus eStatus = FSPathMakeRef( reinterpret_cast<const UInt8*>(pDir), &aPathFSRef, &bIsDirectory );
+    DBG_ASSERTWARNING( (eStatus==noErr) && bIsDirectory, "vcl AddTempFontDir() with invalid directory name!" );
+    if( eStatus != noErr )
+        return false;
+
+    // TODO: deactivate ATSFontContainerRef when closing app
+    ATSFontContainerRef aATSFontContainer;
+
+    const ATSFontContext eContext = kATSFontContextLocal; // TODO: *Global???
+    eStatus = ::ATSFontActivateFromFileReference( &aPathFSRef,
+        eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
+        &aATSFontContainer );
+    if( eStatus != noErr )
+        return false;
+
+    return true;
+}
+
+static bool AddLocalTempFontDirs( void )
+{
+    static bool bFirst = true;
+    if( !bFirst )
+        return false;
+    bFirst = false;
+
+    // add private font files
+
+    OUString aBrandStr( "$BRAND_BASE_DIR" );
+    rtl_bootstrap_expandMacros( &aBrandStr.pData );
+    OUString aBrandSysPath;
+    OSL_VERIFY( osl_getSystemPathFromFileURL( aBrandStr.pData, &aBrandSysPath.pData ) == osl_File_E_None );
+
+    OStringBuffer aBrandFontDir( aBrandSysPath.getLength()*2 );
+    aBrandFontDir.append( OUStringToOString( aBrandSysPath, RTL_TEXTENCODING_UTF8 ) );
+    aBrandFontDir.append( "/share/fonts/truetype/" );
+    return AddTempFontDir( aBrandFontDir.getStr() );
+}
+
+void AquaSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
+{
+    DBG_ASSERT( pFontList, "AquaSalGraphics::GetDevFontList(NULL) !");
+
+    AddLocalTempFontDirs();
+
+    // The idea is to cache the list of system fonts once it has been generated.
+    // SalData seems to be a good place for this caching. However we have to
+    // carefully make the access to the font list thread-safe. If we register
+    // a font-change event handler to update the font list in case fonts have
+    // changed on the system we have to lock access to the list. The right
+    // way to do that is the solar mutex since GetDevFontList is protected
+    // through it as should be all event handlers
+
+    SalData* pSalData = GetSalData();
+#ifdef ENABLE_CORETEXT
+    SystemFontList* GetCoretextFontList(void); // forward declaration
+    if( !pSalData->mpFontList )
+        pSalData->mpFontList = GetCoretextFontList();
+#else
+    SystemFontList* GetAtsFontList(void);      // forward declaration
+    if( !pSalData->mpFontList )
+        pSalData->mpFontList = GetAtsFontList();
+#endif
+
+    // Copy all PhysicalFontFace objects contained in the SystemFontList
+    pSalData->mpFontList->AnnounceFonts( *pFontList );
+}
+
+void AquaSalGraphics::ClearDevFontCache()
+{
+    SalData* pSalData = GetSalData();
+    delete pSalData->mpFontList;
+    pSalData->mpFontList = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+bool AquaSalGraphics::AddTempDevFont( ImplDevFontList*,
+    const OUString& rFontFileURL, const OUString& /*rFontName*/ )
+{
+    OUString aUSytemPath;
+    OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
+
+    FSRef aNewRef;
+    Boolean bIsDirectory = true;
+    OString aCFileName = OUStringToOString( aUSytemPath, RTL_TEXTENCODING_UTF8 );
+    OSStatus eStatus = FSPathMakeRef( (UInt8*)aCFileName.getStr(), &aNewRef, &bIsDirectory );
+    DBG_ASSERT( (eStatus==noErr) && !bIsDirectory, "vcl AddTempDevFont() with invalid fontfile name!" );
+    if( eStatus != noErr )
+        return false;
+
+    ATSFontContainerRef oContainer;
+
+    const ATSFontContext eContext = kATSFontContextLocal; // TODO: *Global???
+    eStatus = ::ATSFontActivateFromFileReference( &aNewRef,
+        eContext, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault,
+        &oContainer );
+    if( eStatus != noErr )
+        return false;
+
+    // TODO: ATSFontDeactivate( oContainer ) when fonts are no longer needed
+    // TODO: register new ImplMacFontdata in pFontList
+    return true;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool AquaSalGraphics::GetGlyphOutline( sal_GlyphId nGlyphId, basegfx::B2DPolyPolygon& rPolyPoly )
+{
+    const bool bRC = mpMacTextStyle->GetGlyphOutline( nGlyphId, rPolyPoly );
+    return bRC;
+}
+
+// -----------------------------------------------------------------------
+
+sal_Bool AquaSalGraphics::GetGlyphBoundRect( sal_GlyphId nGlyphId, Rectangle& rRect )
+{
+    const bool bRC = mpMacTextStyle->GetGlyphBoundRect( nGlyphId, rRect );
+    return bRC;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::GetDevFontSubstList( OutputDevice* )
+{
+    // nothing to do since there are no device-specific fonts on Aqua
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
+{
+}
+
+// -----------------------------------------------------------------------
+
+sal_uInt16 AquaSalGraphics::SetFont( FontSelectPattern* pReqFont, int /*nFallbackLevel*/ )
+{
+    // release the text style
+    delete mpMacTextStyle;
+    mpMacTextStyle = NULL;
+
+    // handle NULL request meaning: release-font-resources request
+    if( !pReqFont )
+    {
+        mpMacFontData = NULL;
+        return 0;
+    }
+
+    // update the text style
+    mpMacFontData = static_cast<const ImplMacFontData*>( pReqFont->mpFontData );
+    mpMacTextStyle = mpMacFontData->CreateMacTextStyle( *pReqFont );
+    mpMacTextStyle->SetTextColor( maTextColor );
+
+#if OSL_DEBUG_LEVEL > 3
+    fprintf( stderr, "SetFont to (\"%s\", \"%s\", fontid=%d) for (\"%s\" \"%s\" weight=%d, slant=%d size=%dx%d orientation=%d)\n",
+             OUStringToOString( mpMacFontData->GetFamilyName(), RTL_TEXTENCODING_UTF8 ).getStr(),
+             OUStringToOString( mpMacFontData->GetStyleName(), RTL_TEXTENCODING_UTF8 ).getStr(),
+             (int)nFontID,
+             OUStringToOString( pReqFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ).getStr(),
+             OUStringToOString( pReqFont->GetStyleName(), RTL_TEXTENCODING_UTF8 ).getStr(),
+             pReqFont->GetWeight(),
+             pReqFont->GetSlant(),
+             pReqFont->mnHeight,
+             pReqFont->mnWidth,
+             pReqFont->mnOrientation);
+#endif
+
+    return 0;
+}
+
+// -----------------------------------------------------------------------
+
+SalLayout* AquaSalGraphics::GetTextLayout( ImplLayoutArgs& /*rArgs*/, int /*nFallbackLevel*/ )
+{
+    SalLayout* pSalLayout = mpMacTextStyle->GetTextLayout();
+    return pSalLayout;
+}
+
+// -----------------------------------------------------------------------
+
+const ImplFontCharMap* AquaSalGraphics::GetImplFontCharMap() const
+{
+    if( !mpMacFontData )
+        return ImplFontCharMap::GetDefaultMap();
+
+    return mpMacFontData->GetImplFontCharMap();
+}
+
+bool AquaSalGraphics::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
+{
+    if( !mpMacFontData )
+        return false;
+
+    return mpMacFontData->GetImplFontCapabilities(rFontCapabilities);
+}
+
+// -----------------------------------------------------------------------
+

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list