summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorKhaled Hosny <khaledhosny@eglug.org>2013-06-01 17:12:29 +0200
committerKhaled Hosny <khaledhosny@eglug.org>2013-06-03 15:11:53 +0200
commitea8422d42e838e7ddfeb8d9f77f3ecedecb29ce8 (patch)
tree8f389c873fe7297fdf5f4dd59d631f95e583bcc6 /vcl
parentcacc516693b879c08bd3b1963eeed9c38928615f (diff)
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
Diffstat (limited to 'vcl')
-rw-r--r--vcl/coretext/ctfonts.cxx648
-rw-r--r--vcl/coretext/ctfonts.hxx90
-rw-r--r--vcl/coretext/ctlayout.cxx500
-rw-r--r--vcl/coretext/salgdi2.cxx918
-rw-r--r--vcl/inc/aqua/salgdi.h2
-rw-r--r--vcl/inc/coretext/salgdi2.h413
-rw-r--r--vcl/inc/impfont.hxx3
-rw-r--r--vcl/inc/quartz/salgdicommon.hxx5
-rw-r--r--vcl/source/gdi/outdev3.cxx8
9 files changed, 2586 insertions, 1 deletions
diff --git a/vcl/coretext/ctfonts.cxx b/vcl/coretext/ctfonts.cxx
new file mode 100644
index 000000000000..5eb2d3465ea5
--- /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 000000000000..c62c1f963fca
--- /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 000000000000..d232910a41c3
--- /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 000000000000..c118440d4779
--- /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);
+}
+
+// -----------------------------------------------------------------------
+
+// fake a SFNT font directory entry for a font table
+// see http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6.html#Directory
+static void FakeDirEntry( const char aTag[5], ByteCount nOfs, ByteCount nLen,
+ const unsigned char* /*pData*/, unsigned char*& rpDest )
+{
+ // write entry tag
+ rpDest[ 0] = aTag[0];
+ rpDest[ 1] = aTag[1];
+ rpDest[ 2] = aTag[2];
+ rpDest[ 3] = aTag[3];
+ // TODO: get entry checksum and write it
+ // not too important since the subsetter doesn't care currently
+ // for( pData+nOfs ... pData+nOfs+nLen )
+ // write entry offset
+ rpDest[ 8] = (char)(nOfs >> 24);
+ rpDest[ 9] = (char)(nOfs >> 16);
+ rpDest[10] = (char)(nOfs >> 8);
+ rpDest[11] = (char)(nOfs >> 0);
+ // write entry length
+ rpDest[12] = (char)(nLen >> 24);
+ rpDest[13] = (char)(nLen >> 16);
+ rpDest[14] = (char)(nLen >> 8);
+ rpDest[15] = (char)(nLen >> 0);
+ // advance to next entry
+ rpDest += 16;
+}
+
+// fake a TTF or CFF font as directly accessing font file is not possible
+// when only the fontid is known. This approach also handles *.dfont fonts.
+bool AquaSalGraphics::GetRawFontData( const PhysicalFontFace* pFontData,
+ ByteVector& rBuffer, bool* pJustCFF )
+{
+ const ImplMacFontData* pMacFont = static_cast<const ImplMacFontData*>(pFontData);
+
+ // short circuit for CFF-only fonts
+ const int nCffSize = pMacFont->GetFontTable( "CFF ", NULL);
+ if( pJustCFF != NULL )
+ {
+ *pJustCFF = (nCffSize > 0);
+ if( *pJustCFF)
+ {
+ rBuffer.resize( nCffSize);
+ const int nCffRead = pMacFont->GetFontTable( "CFF ", &rBuffer[0]);
+ if( nCffRead != nCffSize)
+ return false;
+ return true;
+ }
+ }
+
+ // get font table availability and size in bytes
+ const int nHeadSize = pMacFont->GetFontTable( "head", NULL);
+ if( nHeadSize <= 0)
+ return false;
+ const int nMaxpSize = pMacFont->GetFontTable( "maxp", NULL);
+ if( nMaxpSize <= 0)
+ return false;
+ const int nCmapSize = pMacFont->GetFontTable( "cmap", NULL);
+ if( nCmapSize <= 0)
+ return false;
+ const int nNameSize = pMacFont->GetFontTable( "name", NULL);
+ if( nNameSize <= 0)
+ return false;
+ const int nHheaSize = pMacFont->GetFontTable( "hhea", NULL);
+ if( nHheaSize <= 0)
+ return false;
+ const int nHmtxSize = pMacFont->GetFontTable( "hmtx", NULL);
+ if( nHmtxSize <= 0)
+ return false;
+
+ // get the ttf-glyf outline tables
+ int nLocaSize = 0;
+ int nGlyfSize = 0;
+ if( nCffSize <= 0)
+ {
+ nLocaSize = pMacFont->GetFontTable( "loca", NULL);
+ if( nLocaSize <= 0)
+ return false;
+ nGlyfSize = pMacFont->GetFontTable( "glyf", NULL);
+ if( nGlyfSize <= 0)
+ return false;
+ }
+
+ int nPrepSize = 0, nCvtSize = 0, nFpgmSize = 0;
+ if( nGlyfSize) // TODO: reduce PDF size by making hint subsetting optional
+ {
+ nPrepSize = pMacFont->GetFontTable( "prep", NULL);
+ nCvtSize = pMacFont->GetFontTable( "cvt ", NULL);
+ nFpgmSize = pMacFont->GetFontTable( "fpgm", NULL);
+ }
+
+ // prepare a byte buffer for a fake font
+ int nTableCount = 7;
+ nTableCount += (nPrepSize>0) + (nCvtSize>0) + (nFpgmSize>0) + (nGlyfSize>0);
+ const ByteCount nFdirSize = 12 + 16*nTableCount;
+ ByteCount nTotalSize = nFdirSize;
+ nTotalSize += nHeadSize + nMaxpSize + nNameSize + nCmapSize;
+ if( nGlyfSize )
+ nTotalSize += nLocaSize + nGlyfSize;
+ else
+ nTotalSize += nCffSize;
+ nTotalSize += nHheaSize + nHmtxSize;
+ nTotalSize += nPrepSize + nCvtSize + nFpgmSize;
+ rBuffer.resize( nTotalSize );
+
+ // fake a SFNT font directory header
+ if( nTableCount < 16 )
+ {
+ int nLog2 = 0;
+ while( (nTableCount >> nLog2) > 1 ) ++nLog2;
+ rBuffer[ 1] = 1; // Win-TTF style scaler
+ rBuffer[ 5] = nTableCount; // table count
+ rBuffer[ 7] = nLog2*16; // searchRange
+ rBuffer[ 9] = nLog2; // entrySelector
+ rBuffer[11] = (nTableCount-nLog2)*16; // rangeShift
+ }
+
+ // get font table raw data and update the fake directory entries
+ ByteCount nOfs = nFdirSize;
+ unsigned char* pFakeEntry = &rBuffer[12];
+ if( nCmapSize != pMacFont->GetFontTable( "cmap", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "cmap", nOfs, nCmapSize, &rBuffer[0], pFakeEntry );
+ nOfs += nCmapSize;
+ if( nCvtSize ) {
+ if( nCvtSize != pMacFont->GetFontTable( "cvt ", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "cvt ", nOfs, nCvtSize, &rBuffer[0], pFakeEntry );
+ nOfs += nCvtSize;
+ }
+ if( nFpgmSize ) {
+ if( nFpgmSize != pMacFont->GetFontTable( "fpgm", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "fpgm", nOfs, nFpgmSize, &rBuffer[0], pFakeEntry );
+ nOfs += nFpgmSize;
+ }
+ if( nCffSize ) {
+ if( nCffSize != pMacFont->GetFontTable( "CFF ", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "CFF ", nOfs, nCffSize, &rBuffer[0], pFakeEntry );
+ nOfs += nGlyfSize;
+ } else {
+ if( nGlyfSize != pMacFont->GetFontTable( "glyf", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "glyf", nOfs, nGlyfSize, &rBuffer[0], pFakeEntry );
+ nOfs += nGlyfSize;
+ if( nLocaSize != pMacFont->GetFontTable( "loca", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "loca", nOfs, nLocaSize, &rBuffer[0], pFakeEntry );
+ nOfs += nLocaSize;
+ }
+ if( nHeadSize != pMacFont->GetFontTable( "head", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "head", nOfs, nHeadSize, &rBuffer[0], pFakeEntry );
+ nOfs += nHeadSize;
+ if( nHheaSize != pMacFont->GetFontTable( "hhea", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "hhea", nOfs, nHheaSize, &rBuffer[0], pFakeEntry );
+ nOfs += nHheaSize;
+ if( nHmtxSize != pMacFont->GetFontTable( "hmtx", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "hmtx", nOfs, nHmtxSize, &rBuffer[0], pFakeEntry );
+ nOfs += nHmtxSize;
+ if( nMaxpSize != pMacFont->GetFontTable( "maxp", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "maxp", nOfs, nMaxpSize, &rBuffer[0], pFakeEntry );
+ nOfs += nMaxpSize;
+ if( nNameSize != pMacFont->GetFontTable( "name", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "name", nOfs, nNameSize, &rBuffer[0], pFakeEntry );
+ nOfs += nNameSize;
+ if( nPrepSize ) {
+ if( nPrepSize != pMacFont->GetFontTable( "prep", &rBuffer[nOfs]))
+ return false;
+ FakeDirEntry( "prep", nOfs, nPrepSize, &rBuffer[0], pFakeEntry );
+ nOfs += nPrepSize;
+ }
+
+ DBG_ASSERT( (nOfs==nTotalSize), "AquaSalGraphics::CreateFontSubset (nOfs!=nTotalSize)");
+
+ return true;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFontData, bool bVertical,
+ Int32Vector& rGlyphWidths, Ucs2UIntMap& rUnicodeEnc )
+{
+ rGlyphWidths.clear();
+ rUnicodeEnc.clear();
+
+ if( pFontData->IsSubsettable() )
+ {
+ ByteVector aBuffer;
+ if( !GetRawFontData( pFontData, aBuffer, NULL ) )
+ return;
+
+ // TODO: modernize psprint's horrible fontsubset C-API
+ // this probably only makes sense after the switch to another SCM
+ // that can preserve change history after file renames
+
+ // use the font subsetter to get the widths
+ TrueTypeFont* pSftFont = NULL;
+ int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont);
+ if( nRC != SF_OK )
+ return;
+
+ const int nGlyphCount = ::GetTTGlyphCount( pSftFont );
+ if( nGlyphCount > 0 )
+ {
+ // get glyph metrics
+ rGlyphWidths.resize(nGlyphCount);
+ std::vector<sal_uInt16> aGlyphIds(nGlyphCount);
+ for( int i = 0; i < nGlyphCount; i++ )
+ aGlyphIds[i] = static_cast<sal_uInt16>(i);
+ const TTSimpleGlyphMetrics* pGlyphMetrics = ::GetTTSimpleGlyphMetrics(
+ pSftFont, &aGlyphIds[0], nGlyphCount, bVertical );
+ if( pGlyphMetrics )
+ {
+ for( int i = 0; i < nGlyphCount; ++i )
+ rGlyphWidths[i] = pGlyphMetrics[i].adv;
+ free( (void*)pGlyphMetrics );
+ }
+
+ const ImplFontCharMap* pMap = mpMacFontData->GetImplFontCharMap();
+ DBG_ASSERT( pMap && pMap->GetCharCount(), "no charmap" );
+ pMap->AddReference(); // TODO: add and use RAII object instead
+
+ // get unicode<->glyph encoding
+ // TODO? avoid sft mapping by using the pMap itself
+ int nCharCount = pMap->GetCharCount();
+ sal_uInt32 nChar = pMap->GetFirstChar();
+ for(; --nCharCount >= 0; nChar = pMap->GetNextChar( nChar ) )
+ {
+ if( nChar > 0xFFFF ) // TODO: allow UTF-32 chars
+ break;
+ sal_Ucs nUcsChar = static_cast<sal_Ucs>(nChar);
+ sal_uInt32 nGlyph = ::MapChar( pSftFont, nUcsChar, bVertical );
+ if( nGlyph > 0 )
+ rUnicodeEnc[ nUcsChar ] = nGlyph;
+ }
+
+ pMap->DeReference(); // TODO: add and use RAII object instead
+ }
+
+ ::CloseTTFont( pSftFont );
+ }
+ else if( pFontData->IsEmbeddable() )
+ {
+ // get individual character widths
+ OSL_FAIL("not implemented for non-subsettable fonts!\n");
+ }
+}
+
+// -----------------------------------------------------------------------
+
+const Ucs2SIntMap* AquaSalGraphics::GetFontEncodingVector(
+ const PhysicalFontFace*, const Ucs2OStrMap** /*ppNonEncoded*/ )
+{
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+const void* AquaSalGraphics::GetEmbedFontData( const PhysicalFontFace*,
+ const sal_Ucs* /*pUnicodes*/,
+ sal_Int32* /*pWidths*/,
+ FontSubsetInfo&,
+ long* /*pDataLen*/ )
+{
+ return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void AquaSalGraphics::FreeEmbedFontData( const void* pData, long /*nDataLen*/ )
+{
+ // TODO: implementing this only makes sense when the implementation of
+ // AquaSalGraphics::GetEmbedFontData() returns non-NULL
+ (void)pData;
+ DBG_ASSERT( (pData!=NULL), "AquaSalGraphics::FreeEmbedFontData() is not implemented\n");
+}
+
+// -----------------------------------------------------------------------
+
+SystemFontData AquaSalGraphics::GetSysFontData( int /* nFallbacklevel */ ) const
+{
+ SystemFontData aSysFontData;
+ aSysFontData.nSize = sizeof( SystemFontData );
+
+#ifndef ENABLE_CORETEXT
+ // NOTE: Native ATSU font fallbacks are used, not the VCL fallbacks.
+ ATSUFontID fontId;
+ OSStatus err;
+ err = ATSUGetAttribute( maATSUStyle, kATSUFontTag, sizeof(fontId), &fontId, 0 );
+ if (err) fontId = 0;
+ aSysFontData.aATSUFontID = (void *) fontId;
+
+ Boolean bFbold;
+ err = ATSUGetAttribute( maATSUStyle, kATSUQDBoldfaceTag, sizeof(bFbold), &bFbold, 0 );
+ if (err) bFbold = FALSE;
+ aSysFontData.bFakeBold = (bool) bFbold;
+
+ Boolean bFItalic;
+ err = ATSUGetAttribute( maATSUStyle, kATSUQDItalicTag, sizeof(bFItalic), &bFItalic, 0 );
+ if (err) bFItalic = FALSE;
+ aSysFontData.bFakeItalic = (bool) bFItalic;
+
+ ATSUVerticalCharacterType aVerticalCharacterType;
+ err = ATSUGetAttribute( maATSUStyle, kATSUVerticalCharacterTag, sizeof(aVerticalCharacterType), &aVerticalCharacterType, 0 );
+ if (!err && aVerticalCharacterType == kATSUStronglyVertical) {
+ aSysFontData.bVerticalCharacterType = true;
+ } else {
+ aSysFontData.bVerticalCharacterType = false;
+ }
+#endif
+
+ aSysFontData.bAntialias = !mbNonAntialiasedText;
+
+ return aSysFontData;
+}
+
+// -----------------------------------------------------------------------
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/aqua/salgdi.h b/vcl/inc/aqua/salgdi.h
index 20d4588925de..d7ffe53dd206 100644
--- a/vcl/inc/aqua/salgdi.h
+++ b/vcl/inc/aqua/salgdi.h
@@ -8,7 +8,7 @@
*/
#ifdef ENABLE_CORETEXT
-# include "coretext/salgdi.h"
+# include "coretext/salgdi2.h"
#else
# include "aqua/atsui/salgdi.h"
#endif
diff --git a/vcl/inc/coretext/salgdi2.h b/vcl/inc/coretext/salgdi2.h
new file mode 100644
index 000000000000..86d5fc9f516f
--- /dev/null
+++ b/vcl/inc/coretext/salgdi2.h
@@ -0,0 +1,413 @@
+/* -*- 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 .
+ */
+
+#ifndef _SV_SALGDI_H
+#define _SV_SALGDI_H
+
+#include <vector>
+
+#include "basegfx/polygon/b2dpolypolygon.hxx"
+
+#include "premac.h"
+#include <ApplicationServices/ApplicationServices.h>
+#include "postmac.h"
+
+#include "aqua/aquavcltypes.h"
+#include <vcl/fontcapabilities.hxx>
+
+#include "outfont.hxx"
+#include "aqua/salframe.h"
+#include "salgdi.hxx"
+
+#include "quartz/salgdicommon.hxx"
+
+class AquaSalFrame;
+class ImplDevFontAttributes;
+class ImplMacTextStyle;
+
+struct CGRect;
+
+typedef sal_uInt32 sal_GlyphId;
+typedef std::vector<unsigned char> ByteVector;
+
+#ifndef CGFLOAT_TYPE
+typedef float CGFloat;
+#endif
+
+// mac specific physically available font face
+class ImplMacFontData : public PhysicalFontFace
+{
+public:
+ ImplMacFontData( const ImplDevFontAttributes&, sal_IntPtr nFontID );
+
+ virtual ~ImplMacFontData();
+
+ virtual PhysicalFontFace* Clone() const = 0;
+ virtual ImplFontEntry* CreateFontInstance( FontSelectPattern& ) const;
+ virtual sal_IntPtr GetFontId() const;
+
+ virtual ImplMacTextStyle* CreateMacTextStyle( const ImplFontSelectData& ) const = 0;
+ virtual int GetFontTable( const char pTagName[5], unsigned char* ) const = 0;
+
+ const ImplFontCharMap* GetImplFontCharMap() const;
+ bool GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const;
+ bool HasChar( sal_uInt32 cChar ) const;
+
+ void ReadOs2Table() const;
+ void ReadMacCmapEncoding() const;
+ bool HasCJKSupport() const;
+
+protected:
+ ImplMacFontData( const ImplMacFontData&);
+private:
+ const sal_IntPtr mnFontId;
+ mutable const ImplFontCharMap* mpCharMap;
+ mutable vcl::FontCapabilities maFontCapabilities;
+ mutable bool mbOs2Read; // true if OS2-table related info is valid
+ mutable bool mbHasOs2Table;
+ mutable bool mbCmapEncodingRead; // true if cmap encoding of Mac font is read
+ mutable bool mbHasCJKSupport; // #i78970# CJK fonts need extra leading
+ mutable bool mbFontCapabilitiesRead;
+};
+
+// --------------------
+// - ImplMacTextStyle -
+// --------------------
+class ImplMacTextStyle
+{
+public:
+ explicit ImplMacTextStyle( const ImplFontSelectData& );
+ virtual ~ImplMacTextStyle( void );
+
+ virtual SalLayout* GetTextLayout( void ) const = 0;
+
+ virtual void GetFontMetric( float fPDIY, ImplFontMetricData& ) const = 0;
+ virtual bool GetGlyphBoundRect( sal_GlyphId, Rectangle& ) const = 0;
+ virtual bool GetGlyphOutline( sal_GlyphId, basegfx::B2DPolyPolygon& ) const = 0;
+
+ virtual void SetTextColor( const RGBAColor& ) = 0;
+
+//###protected:
+ const ImplMacFontData* mpFontData;
+ /// workaround to prevent overflows for huge font sizes
+ float mfFontScale;
+ /// <1.0: font is squeezed, >1.0 font is stretched, else 1.0
+ float mfFontStretch;
+ /// text rotation in radian
+ float mfFontRotation;
+};
+
+// ------------------
+// - SystemFontList -
+// TODO: move into cross-platform headers
+// ------------------
+class SystemFontList
+{
+public:
+ virtual ~SystemFontList( void );
+
+ virtual void AnnounceFonts( ImplDevFontList& ) const = 0;
+ virtual ImplMacFontData* GetFontDataFromId( sal_IntPtr nFontId ) const = 0;
+};
+
+// -------------------
+// - AquaSalGraphics -
+// -------------------
+class AquaSalGraphics : public SalGraphics
+{
+ friend class ATSLayout;
+ friend class CTLayout;
+protected:
+ AquaSalFrame* mpFrame;
+ CGLayerRef mxLayer; // Quartz graphics layer
+ CGContextRef mrContext; // Quartz drawing context
+ class XorEmulation* mpXorEmulation;
+ int mnXorMode; // 0: off 1: on 2: invert only
+ int mnWidth;
+ int mnHeight;
+ int mnBitmapDepth; // zero unless bitmap
+ /// device resolution of this graphics
+ long mnRealDPIX;
+ long mnRealDPIY;
+ /// some graphics implementations (e.g. AquaSalInfoPrinter) scale
+ /// everything down by a factor (see SetupPrinterGraphics for details)
+ /// so we have to compensate for it with the inverse factor
+ double mfFakeDPIScale;
+
+ /// path representing current clip region
+ CGMutablePathRef mxClipPath;
+
+ /// Drawing colors
+ /// pen color RGBA
+ RGBAColor maLineColor;
+ /// brush color RGBA
+ RGBAColor maFillColor;
+
+ // Device Font settings
+ const ImplMacFontData* mpMacFontData;
+ ImplMacTextStyle* mpMacTextStyle;
+ RGBAColor maTextColor;
+ /// allows text to be rendered without antialiasing
+ bool mbNonAntialiasedText;
+
+ // Graphics types
+
+ /// is this a printer graphics
+ bool mbPrinter;
+ /// is this a virtual device graphics
+ bool mbVirDev;
+ /// is this a window graphics
+ bool mbWindow;
+
+public:
+ AquaSalGraphics();
+ virtual ~AquaSalGraphics();
+
+ bool IsPenVisible() const { return maLineColor.IsVisible(); }
+ bool IsBrushVisible() const { return maFillColor.IsVisible(); }
+
+ void SetWindowGraphics( AquaSalFrame* pFrame );
+ void SetPrinterGraphics( CGContextRef, long nRealDPIX, long nRealDPIY, double fFakeScale );
+ void SetVirDevGraphics( CGLayerRef, CGContextRef, int nBitDepth = 0 );
+
+ void initResolution( NSWindow* );
+ void copyResolution( AquaSalGraphics& );
+ void updateResolution();
+
+ bool IsWindowGraphics() const { return mbWindow; }
+ AquaSalFrame* getGraphicsFrame() const { return mpFrame; }
+ void setGraphicsFrame( AquaSalFrame* pFrame ) { mpFrame = pFrame; }
+
+ void ImplDrawPixel( long nX, long nY, const RGBAColor& ); // helper to draw single pixels
+
+ bool CheckContext();
+ CGContextRef GetContext();
+ void UpdateWindow( NSRect& ); // delivered in NSView coordinates
+ void RefreshRect( const CGRect& );
+ void RefreshRect( const NSRect& );
+ void RefreshRect(float lX, float lY, float lWidth, float lHeight);
+
+ void SetState();
+ void UnsetState();
+ // InvalidateContext does an UnsetState and sets mrContext to 0
+ void InvalidateContext();
+
+ virtual bool setClipRegion( const Region& );
+
+ // draw --> LineColor and FillColor and RasterOp and ClipRegion
+ virtual void drawPixel( long nX, long nY );
+ virtual void drawPixel( long nX, long nY, SalColor nSalColor );
+ virtual void drawLine( long nX1, long nY1, long nX2, long nY2 );
+ virtual void drawRect( long nX, long nY, long nWidth, long nHeight );
+ virtual void drawPolyLine( sal_uLong nPoints, const SalPoint* pPtAry );
+ virtual void drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry );
+ virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uLong* pPoints, PCONSTSALPOINT* pPtAry );
+ virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency );
+ virtual sal_Bool drawPolyLineBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry );
+ virtual sal_Bool drawPolygonBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry );
+ virtual sal_Bool drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const sal_uInt8* const* pFlgAry );
+ virtual bool drawPolyLine(
+ const ::basegfx::B2DPolygon&,
+ double fTransparency,
+ const ::basegfx::B2DVector& rLineWidths,
+ basegfx::B2DLineJoin,
+ com::sun::star::drawing::LineCap eLineCap);
+
+ // CopyArea --> No RasterOp, but ClipRegion
+ virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth,
+ long nSrcHeight, sal_uInt16 nFlags );
+
+ // CopyBits and DrawBitmap --> RasterOp and ClipRegion
+ // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics
+ virtual void copyBits( const SalTwoRect* pPosAry, SalGraphics* pSrcGraphics );
+ virtual void drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nTransparentColor );
+ virtual void drawBitmap( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ const SalBitmap& rTransparentBitmap );
+ virtual void drawMask( const SalTwoRect* pPosAry,
+ const SalBitmap& rSalBitmap,
+ SalColor nMaskColor );
+
+ virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight );
+ virtual SalColor getPixel( long nX, long nY );
+
+ // invert --> ClipRegion (only Windows or VirDevs)
+ virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags);
+ virtual void invert( sal_uLong nPoints, const SalPoint* pPtAry, SalInvert nFlags );
+
+ virtual sal_Bool drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize );
+
+ virtual bool drawAlphaBitmap( const SalTwoRect&,
+ const SalBitmap& rSourceBitmap,
+ const SalBitmap& rAlphaBitmap );
+
+ virtual bool drawAlphaRect( long nX, long nY, long nWidth,
+ long nHeight, sal_uInt8 nTransparency );
+
+ CGPoint* makeCGptArray(sal_uLong nPoints, const SalPoint* pPtAry);
+ // native widget rendering methods that require mirroring
+ virtual sal_Bool hitTestNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion,
+ const Point& aPos, sal_Bool& rIsInside );
+ virtual sal_Bool drawNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion,
+ ControlState nState, const ImplControlValue& aValue,
+ const OUString& aCaption );
+ virtual sal_Bool getNativeControlRegion( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, ControlState nState,
+ const ImplControlValue& aValue, const OUString& aCaption,
+ Rectangle &rNativeBoundingRegion, Rectangle &rNativeContentRegion );
+
+ // get device resolution
+ virtual void GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY );
+ // get the depth of the device
+ virtual sal_uInt16 GetBitCount() const;
+ // get the width of the device
+ virtual long GetGraphicsWidth() const;
+
+ // set the clip region to empty
+ virtual void ResetClipRegion();
+
+ // set the line color to transparent (= don't draw lines)
+ virtual void SetLineColor();
+ // set the line color to a specific color
+ virtual void SetLineColor( SalColor nSalColor );
+ // set the fill color to transparent (= don't fill)
+ virtual void SetFillColor();
+ // set the fill color to a specific color, shapes will be
+ // filled accordingly
+ virtual void SetFillColor( SalColor nSalColor );
+ // enable/disable XOR drawing
+ virtual void SetXORMode( bool bSet, bool bInvertOnly );
+ // set line color for raster operations
+ virtual void SetROPLineColor( SalROPColor nROPColor );
+ // set fill color for raster operations
+ virtual void SetROPFillColor( SalROPColor nROPColor );
+ // set the text color to a specific color
+ virtual void SetTextColor( SalColor nSalColor );
+ // set the font
+ virtual sal_uInt16 SetFont( FontSelectPattern*, int nFallbackLevel );
+ // get the current font's etrics
+ virtual void GetFontMetric( ImplFontMetricData*, int nFallbackLevel );
+ // get kernign pairs of the current font
+ // return only PairCount if (pKernPairs == NULL)
+ virtual sal_uLong GetKernPairs( sal_uLong nPairs, ImplKernPairData* pKernPairs );
+ // get the repertoire of the current font
+ virtual const ImplFontCharMap* GetImplFontCharMap() const;
+ virtual bool GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const;
+ // graphics must fill supplied font list
+ virtual void GetDevFontList( ImplDevFontList* );
+ // graphics must drop any cached font info
+ virtual void ClearDevFontCache();
+ // graphics should call ImplAddDevFontSubstitute on supplied
+ // OutputDevice for all its device specific preferred font substitutions
+ virtual void GetDevFontSubstList( OutputDevice* );
+ virtual bool AddTempDevFont( ImplDevFontList*, const OUString& rFileURL, const OUString& rFontName );
+ // CreateFontSubset: a method to get a subset of glyhps of a font
+ // inside a new valid font file
+ // returns TRUE if creation of subset was successful
+ // parameters: rToFile: contains a osl file URL to write the subset to
+ // pFont: describes from which font to create a subset
+ // pGlyphIDs: the glyph ids to be extracted
+ // pEncoding: the character code corresponding to each glyph
+ // pWidths: the advance widths of the correspoding glyphs (in PS font units)
+ // nGlyphs: the number of glyphs
+ // rInfo: additional outgoing information
+ // implementation note: encoding 0 with glyph id 0 should be added implicitly
+ // as "undefined character"
+ virtual sal_Bool CreateFontSubset( const OUString& rToFile,
+ const PhysicalFontFace* pFont,
+ sal_Int32* pGlyphIDs,
+ sal_uInt8* pEncoding,
+ sal_Int32* pWidths,
+ int nGlyphs,
+ FontSubsetInfo& rInfo // out parameter
+ );
+
+ // GetFontEncodingVector: a method to get the encoding map Unicode
+ // to font encoded character; this is only used for type1 fonts and
+ // may return NULL in case of unknown encoding vector
+ // if ppNonEncoded is set and non encoded characters (that is type1
+ // glyphs with only a name) exist it is set to the corresponding
+ // map for non encoded glyphs; the encoding vector contains -1
+ // as encoding for these cases
+ virtual const Ucs2SIntMap* GetFontEncodingVector( const PhysicalFontFace*, const Ucs2OStrMap** ppNonEncoded );
+
+ // GetEmbedFontData: gets the font data for a font marked
+ // embeddable by GetDevFontList or NULL in case of error
+ // parameters: pFont: describes the font in question
+ // pWidths: the widths of all glyphs from char code 0 to 255
+ // pWidths MUST support at least 256 members;
+ // rInfo: additional outgoing information
+ // pDataLen: out parameter, contains the byte length of the returned buffer
+ virtual const void* GetEmbedFontData( const PhysicalFontFace*,
+ const sal_Ucs* pUnicodes,
+ sal_Int32* pWidths,
+ FontSubsetInfo& rInfo,
+ long* pDataLen );
+ // frees the font data again
+ virtual void FreeEmbedFontData( const void* pData, long nDataLen );
+
+ virtual void GetGlyphWidths( const PhysicalFontFace*,
+ bool bVertical,
+ Int32Vector& rWidths,
+ Ucs2UIntMap& rUnicodeEnc );
+
+ virtual sal_Bool GetGlyphBoundRect( sal_GlyphId nIndex, Rectangle& );
+ virtual sal_Bool GetGlyphOutline( sal_GlyphId nIndex, basegfx::B2DPolyPolygon& );
+
+ virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel );
+ virtual void DrawServerFontLayout( const ServerFontLayout& );
+ virtual bool supportsOperation( OutDevSupportType ) const;
+
+ // Query the platform layer for control support
+ virtual sal_Bool IsNativeControlSupported( ControlType nType, ControlPart nPart );
+
+ virtual SystemGraphicsData GetGraphicsData() const;
+ virtual SystemFontData GetSysFontData( int /* nFallbacklevel */ ) const;
+
+private:
+ // differences between VCL, Quartz and kHiThemeOrientation coordinate systems
+ // make some graphics seem to be vertically-mirrored from a VCL perspective
+ bool IsFlipped() const { return mbWindow; }
+
+ void ApplyXorContext();
+ void Pattern50Fill();
+ UInt32 getState( ControlState nState );
+ UInt32 getTrackState( ControlState nState );
+ bool GetRawFontData( const PhysicalFontFace* pFontData,
+ std::vector<unsigned char>& rBuffer,
+ bool* pJustCFF );
+};
+
+// --- some trivial inlines
+
+inline void AquaSalGraphics::RefreshRect( const CGRect& rRect )
+{
+ RefreshRect( rRect.origin.x, rRect.origin.y, rRect.size.width, rRect.size.height );
+}
+
+inline void AquaSalGraphics::RefreshRect( const NSRect& rRect )
+{
+ RefreshRect( rRect.origin.x, rRect.origin.y, rRect.size.width, rRect.size.height );
+}
+
+#endif // _SV_SALGDI_H
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/impfont.hxx b/vcl/inc/impfont.hxx
index 1ac8bd65f020..26a9dd41aed9 100644
--- a/vcl/inc/impfont.hxx
+++ b/vcl/inc/impfont.hxx
@@ -27,6 +27,7 @@
#include <vcl/dllapi.h>
#include <vcl/vclenum.hxx>
#include <vcl/fntstyle.hxx>
+#include <outfont.hxx>
// ------------
// - Impl_Font -
@@ -229,6 +230,8 @@ public:
bool ParseCMAP( const unsigned char* pRawData, int nRawLength, CmapResult& );
+void UpdateAttributesFromPSName( const String& rPSName, ImplDevFontAttributes& );
+
#endif // _SV_IMPFONT_HXX
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/quartz/salgdicommon.hxx b/vcl/inc/quartz/salgdicommon.hxx
index bbc6f8f9a550..c8a18198ffe9 100644
--- a/vcl/inc/quartz/salgdicommon.hxx
+++ b/vcl/inc/quartz/salgdicommon.hxx
@@ -39,6 +39,11 @@ public:
const CGFloat* AsArray() const { return m_fRGBA; }
bool IsVisible() const { return m_fRGBA[3] > 0; }
void SetAlpha( float fAlpha ) { m_fRGBA[3] = fAlpha; }
+
+ CGFloat GetRed() const { return m_fRGBA[0]; }
+ CGFloat GetGreen() const { return m_fRGBA[1]; }
+ CGFloat GetBlue() const { return m_fRGBA[2]; }
+ CGFloat GetAlpha() const { return m_fRGBA[3]; }
private:
CGFloat m_fRGBA[4]; // red, green, blue, alpha
};
diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx
index 359b82c2b5df..565a56c02730 100644
--- a/vcl/source/gdi/outdev3.cxx
+++ b/vcl/source/gdi/outdev3.cxx
@@ -5846,6 +5846,14 @@ SalLayout* OutputDevice::ImplLayout( const OUString& rOrigStr, sal_Int32 nMinInd
ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen, nPixelWidth, pDXArray );
+#ifdef MACOSX
+ // CoreText layouts are immutable and already contain the text color
+ // so we need to provide the color already for the layout request
+ // even if this layout will never be drawn
+ if( mbInitTextColor )
+ const_cast<OutputDevice&>(*this).ImplInitTextColor();
+#endif
+
// get matching layout object for base font
SalLayout* pSalLayout = NULL;
if( mpPDFWriter )