Author: hdu
Date: Fri Jan  3 12:38:31 2014
New Revision: 1555075

URL: http://svn.apache.org/r1555075
Log:
#i123951# add an OSX CoreText based text system

Added:
    openoffice/trunk/main/vcl/aqua/source/gdi/ctfonts.cxx
    openoffice/trunk/main/vcl/aqua/source/gdi/ctfonts.hxx
    openoffice/trunk/main/vcl/aqua/source/gdi/ctlayout.cxx

Added: openoffice/trunk/main/vcl/aqua/source/gdi/ctfonts.cxx
URL: 
http://svn.apache.org/viewvc/openoffice/trunk/main/vcl/aqua/source/gdi/ctfonts.cxx?rev=1555075&view=auto
==============================================================================
--- openoffice/trunk/main/vcl/aqua/source/gdi/ctfonts.cxx (added)
+++ openoffice/trunk/main/vcl/aqua/source/gdi/ctfonts.cxx Fri Jan  3 12:38:31 
2014
@@ -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 "aqua/salgdi.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 aGlyphId, Rectangle& rRect ) 
const
+{
+       const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
+       CGGlyph nCGGlyph = aGlyphId & 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 aGlyphId, 
basegfx::B2DPolyPolygon& rResult ) const
+{
+       rResult.clear();
+
+       const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
+       // TODO: GF_FONTMASK if using non-native glyph fallback
+       CGGlyph nCGGlyph = aGlyphId & 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( pTagName[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;
+}
+
+// =======================================================================
+

Added: openoffice/trunk/main/vcl/aqua/source/gdi/ctfonts.hxx
URL: 
http://svn.apache.org/viewvc/openoffice/trunk/main/vcl/aqua/source/gdi/ctfonts.hxx?rev=1555075&view=auto
==============================================================================
--- openoffice/trunk/main/vcl/aqua/source/gdi/ctfonts.hxx (added)
+++ openoffice/trunk/main/vcl/aqua/source/gdi/ctfonts.hxx Fri Jan  3 12:38:31 
2014
@@ -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 "aqua/salgdi.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
+
+// =======================================================================
+

Added: openoffice/trunk/main/vcl/aqua/source/gdi/ctlayout.cxx
URL: 
http://svn.apache.org/viewvc/openoffice/trunk/main/vcl/aqua/source/gdi/ctlayout.cxx?rev=1555075&view=auto
==============================================================================
--- openoffice/trunk/main/vcl/aqua/source/gdi/ctlayout.cxx (added)
+++ openoffice/trunk/main/vcl/aqua/source/gdi/ctlayout.cxx Fri Jan  3 12:38:31 
2014
@@ -0,0 +1,517 @@
+/**************************************************************
+ * 
+ * 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* pOutGlyphIds, 
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();
+       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;
+
+       // if the text to be justified has whitespace in it then
+       // - Writer goes crazy with its HalfSpace magic
+       // - LayoutEngine handles spaces specially (in particular at the text 
start or end)
+       if( mnTrailingSpaces ) {
+               // adjust for Writer's SwFntObj::DrawText() Halfspace magic at 
the text end
+               std::vector<sal_Int32> aOrigDXAry;
+               aOrigDXAry.resize( mnCharCount);
+               FillDXArray( &aOrigDXAry[0] );
+               int nLastCharSpace = rArgs.mpDXArray[ 
mnCharCount-1-mnTrailingSpaces ]
+                       - aOrigDXAry[ mnCharCount-1-mnTrailingSpaces ];
+               nPixelWidth -= nLastCharSpace;
+               if( nPixelWidth < 0 )
+                       return;
+               // recreate the CoreText line layout without trailing spaces
+               CFRelease( mpCTLine );
+               CFStringRef aCFText = CFStringCreateWithCharactersNoCopy( NULL, 
rArgs.mpStr + mnMinCharPos,
+                       mnCharCount - mnTrailingSpaces, kCFAllocatorNull );
+               CFAttributedStringRef pAttrStr = CFAttributedStringCreate( 
NULL, aCFText, mpTextStyle->GetStyleDict() );
+               mpCTLine = CTLineCreateWithAttributedString( pAttrStr );
+               CFRelease( aCFText);
+               CFRelease( pAttrStr );
+       }
+
+       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* pOutGlyphIds, 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
+                       *(pOutGlyphIds++) = 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 );
+
+       const long nScaledWidth = lrint( mfFontScale * mfCachedWidth );
+       return nScaledWidth;
+}
+
+// -----------------------------------------------------------------------
+
+long CTLayout::FillDXArray( sal_Int32* pDXArray ) const
+{
+       // short circuit requests which don't need full details
+       if( !pDXArray )
+               return GetTextWidth();
+
+       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 /*aGlyphId*/ ) 
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 = (aGlyphId & 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);
+}
+
+// =======================================================================
+


Reply via email to