1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_vcl.hxx"
24
25 #include "impfont.hxx"
26 #include "outfont.hxx"
27 #include "sallayout.hxx"
28
29 #include "aqua/salinst.h"
30 #include "aqua/saldata.hxx"
31 #include "aqua/salgdi.h"
32 #include "ctfonts.hxx"
33
34 #include "basegfx/polygon/b2dpolygon.hxx"
35 #include "basegfx/matrix/b2dhommatrix.hxx"
36
37 #ifndef DISABLE_CORETEXT_DYNLOAD
38 #include <dlfcn.h>
39 #endif
40
41 // =======================================================================
42
43 // CoreText specific physically available font face
44 class CTFontData
45 : public ImplMacFontData
46 {
47 public:
48 explicit CTFontData( const ImplDevFontAttributes&, sal_IntPtr nFontId );
49 virtual ~CTFontData( void );
50 virtual ImplFontData* Clone( void ) const;
51
52 virtual ImplMacTextStyle* CreateMacTextStyle( const ImplFontSelectData& ) const;
53 virtual ImplFontEntry* CreateFontInstance( /*const*/ ImplFontSelectData& ) const;
54 virtual int GetFontTable( const char pTagName[5], unsigned char* ) const;
55 };
56
57 // =======================================================================
58
59 class CTFontList
60 : public SystemFontList
61 {
62 public:
63 explicit CTFontList( void );
64 virtual ~CTFontList( void );
65
66 bool Init( void );
67 void AddFont( CTFontData* );
68
69 virtual void AnnounceFonts( ImplDevFontList& ) const;
70 virtual ImplMacFontData* GetFontDataFromId( sal_IntPtr ) const;
71
72 private:
73 CTFontCollectionRef mpCTFontCollection;
74 CFArrayRef mpCTFontArray;
75
76 typedef std::hash_map<sal_IntPtr,CTFontData*> CTFontContainer;
77 CTFontContainer maFontContainer;
78 };
79
80 // =======================================================================
81
CTTextStyle(const ImplFontSelectData & rFSD)82 CTTextStyle::CTTextStyle( const ImplFontSelectData& rFSD )
83 : ImplMacTextStyle( rFSD )
84 , mpStyleDict( NULL )
85 {
86 mpFontData = (CTFontData*)rFSD.mpFontData;
87 const ImplFontSelectData* const pReqFont = &rFSD;
88
89 double fScaledFontHeight = pReqFont->mfExactHeight;
90 #if 0 // TODO: does CoreText need font size limiting???
91 static const float fMaxFontHeight = 144.0; // TODO: is there a limit for CoreText?
92 if( fScaledFontHeight > fMaxFontHeight )
93 {
94 mfFontScale = fScaledFontHeight / fMaxFontHeight;
95 fScaledFontHeight = fMaxFontHeight;
96 }
97 #endif
98
99 // convert font rotation to radian
100 mfFontRotation = pReqFont->mnOrientation * (M_PI / 1800.0);
101
102 // handle font stretching if any
103 const CGAffineTransform* pMatrix = NULL;
104 CGAffineTransform aMatrix;
105 if( (pReqFont->mnWidth != 0) && (pReqFont->mnWidth != pReqFont->mnHeight) )
106 {
107 mfFontStretch = (float)pReqFont->mnWidth / pReqFont->mnHeight;
108 aMatrix = CGAffineTransformMakeScale( mfFontStretch, 1.0F );
109 pMatrix = &aMatrix;
110 }
111
112 // handle emulation of italic/oblique styles if requested and the font doesn't provide them
113 if( ((pReqFont->meItalic == ITALIC_NORMAL) || (pReqFont->meItalic == ITALIC_OBLIQUE))
114 && (mpFontData->meItalic == ITALIC_NONE))
115 {
116 if( !pMatrix)
117 pMatrix = &(aMatrix = CGAffineTransformIdentity);
118 aMatrix = CGAffineTransformConcat(aMatrix, CGAffineTransformMake( 1, 0, 0.375F, 1, 0, 0));
119 }
120
121 // create the style object for CoreText font attributes
122 static const CFIndex nMaxDictSize = 16; // TODO: does this really suffice?
123 mpStyleDict = CFDictionaryCreateMutable( NULL, nMaxDictSize,
124 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
125
126 // set some default styles: no kerning, regular ligatures
127 static const CGFloat fValZero = 0.0;
128 CFNumberRef pCFFloatNumZero = CFNumberCreate( NULL, kCFNumberFloatType, &fValZero );
129 CFDictionarySetValue( mpStyleDict, kCTKernAttributeName, pCFFloatNumZero );
130 CFRelease( pCFFloatNumZero);
131 static const int nValOne = 1;
132 CFNumberRef pCFIntNumOne = CFNumberCreate( NULL, kCFNumberIntType, &nValOne );
133 CFDictionarySetValue( mpStyleDict, kCTLigatureAttributeName, pCFIntNumOne );
134 CFRelease( pCFIntNumOne);
135 CFBooleanRef pCFVertBool = pReqFont->mbVertical ? kCFBooleanTrue : kCFBooleanFalse;
136 CFDictionarySetValue( mpStyleDict, kCTVerticalFormsAttributeName, pCFVertBool );
137
138 CTFontDescriptorRef pFontDesc = (CTFontDescriptorRef)mpFontData->GetFontId();
139 CTFontRef pNewCTFont = CTFontCreateWithFontDescriptor( pFontDesc, fScaledFontHeight, pMatrix );
140 CFDictionarySetValue( mpStyleDict, kCTFontAttributeName, pNewCTFont );
141 CFRelease( pNewCTFont);
142
143 // allow delayed setting the font color, i.e. after the text layout
144 CFDictionarySetValue( mpStyleDict, kCTForegroundColorFromContextAttributeName, kCFBooleanTrue );
145
146 // handle emulation of bold styles if requested and the font that doesn't provide them
147 if( (pReqFont->meWeight > WEIGHT_MEDIUM)
148 && (mpFontData->meWeight <= WEIGHT_MEDIUM)
149 && (mpFontData->meWeight != WEIGHT_DONTKNOW))
150 {
151 const int nBoldFactor = -lrint( (3.5F * pReqFont->meWeight) / mpFontData->meWeight);
152 CFNumberRef pCFIntBold = CFNumberCreate( NULL, kCFNumberIntType, &nBoldFactor);
153 CFDictionarySetValue( mpStyleDict, kCTStrokeWidthAttributeName, pCFIntBold);
154 }
155
156 #if 0 // LastResort is implicit in CoreText's font cascading
157 const void* aGFBDescriptors[] = { CTFontDescriptorCreateWithNameAndSize( CFSTR("LastResort"), 0) }; // TODO: use the full GFB list
158 const int nGfbCount = sizeof(aGFBDescriptors) / sizeof(*aGFBDescriptors);
159 CFArrayRef pGfbList = CFArrayCreate( NULL, aGFBDescriptors, nGfbCount, &kCFTypeArrayCallBacks);
160 CFDictionaryAddValue( mpStyleDict, kCTFontCascadeListAttribute, pGfbList);
161 CFRelease( pGfbList);
162 #endif
163 }
164
165 // -----------------------------------------------------------------------
166
~CTTextStyle(void)167 CTTextStyle::~CTTextStyle( void )
168 {
169 if( mpStyleDict )
170 CFRelease( mpStyleDict );
171 }
172
173 // -----------------------------------------------------------------------
174
GetFontMetric(float fDPIY,ImplFontMetricData & rMetric) const175 void CTTextStyle::GetFontMetric( float fDPIY, ImplFontMetricData& rMetric ) const
176 {
177 // get the matching CoreText font handle
178 // TODO: is it worth it to cache the CTFontRef in SetFont() and reuse it here?
179 CTFontRef aCTFontRef = (CTFontRef)CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName );
180
181 const double fPixelSize = (mfFontScale * fDPIY);
182 const CGFloat fAscent = CTFontGetAscent( aCTFontRef );
183 const CGFloat fCapHeight = CTFontGetCapHeight( aCTFontRef );
184 rMetric.mnAscent = lrint( fAscent * fPixelSize);
185 rMetric.mnDescent = lrint( CTFontGetDescent( aCTFontRef ) * fPixelSize);
186 rMetric.mnExtLeading = lrint( CTFontGetLeading( aCTFontRef ) * fPixelSize);
187 rMetric.mnIntLeading = lrint( (fAscent - fCapHeight) * fPixelSize);
188
189 // since ImplFontMetricData::mnWidth is only used for stretching/squeezing fonts
190 // setting this width to the pixel height of the fontsize is good enough
191 // it also makes the calculation of the stretch factor simple
192 rMetric.mnWidth = lrint( CTFontGetSize( aCTFontRef ) * fPixelSize * mfFontStretch);
193
194 // all CoreText fonts are scalable
195 rMetric.mbScalableFont = true;
196 // TODO: check if any kerning is supported
197 rMetric.mbKernableFont = true;
198 }
199
200 // -----------------------------------------------------------------------
201
GetGlyphBoundRect(sal_GlyphId aGlyphId,Rectangle & rRect) const202 bool CTTextStyle::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect ) const
203 {
204 const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
205 CGGlyph nCGGlyph = aGlyphId & GF_IDXMASK; // NOTE: CoreText handles glyph fallback itself
206 CTFontRef aCTFontRef = (CTFontRef)CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName );
207
208 const CTFontOrientation aFontOrientation = kCTFontDefaultOrientation; // TODO: horz/vert
209 const CGRect aCGRect = rCT.FontGetBoundingRectsForGlyphs( aCTFontRef, aFontOrientation, &nCGGlyph, NULL, 1 );
210
211 rRect.Left() = lrint( mfFontScale * aCGRect.origin.x );
212 rRect.Top() = lrint( mfFontScale * aCGRect.origin.y );
213 rRect.Right() = lrint( mfFontScale * (aCGRect.origin.x + aCGRect.size.width) );
214 rRect.Bottom() = lrint( mfFontScale * (aCGRect.origin.y + aCGRect.size.height) );
215 return true;
216 }
217
218 // -----------------------------------------------------------------------
219
220 // callbacks from CTFontCreatePathForGlyph+CGPathApply for GetGlyphOutline()
221 struct GgoData { basegfx::B2DPolygon maPolygon; basegfx::B2DPolyPolygon* mpPolyPoly; };
222
MyCGPathApplierFunc(void * pData,const CGPathElement * pElement)223 static void MyCGPathApplierFunc( void* pData, const CGPathElement* pElement )
224 {
225 basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
226 const int nPointCount = rPolygon.count();
227
228 switch( pElement->type )
229 {
230 case kCGPathElementCloseSubpath:
231 case kCGPathElementMoveToPoint:
232 if( nPointCount > 0 ) {
233 static_cast<GgoData*>(pData)->mpPolyPoly->append( rPolygon );
234 rPolygon.clear();
235 }
236 // fall through for kCGPathElementMoveToPoint:
237 if( pElement->type != kCGPathElementMoveToPoint )
238 break;
239 case kCGPathElementAddLineToPoint:
240 rPolygon.append( basegfx::B2DPoint( +pElement->points[0].x, -pElement->points[0].y ) );
241 break;
242 case kCGPathElementAddCurveToPoint:
243 rPolygon.append( basegfx::B2DPoint( +pElement->points[2].x, -pElement->points[2].y ) );
244 rPolygon.setNextControlPoint( nPointCount-1, basegfx::B2DPoint( pElement->points[0].x, -pElement->points[0].y ) );
245 rPolygon.setPrevControlPoint( nPointCount+0, basegfx::B2DPoint( pElement->points[1].x, -pElement->points[1].y ) );
246 break;
247 case kCGPathElementAddQuadCurveToPoint: {
248 const basegfx::B2DPoint aStartPt = rPolygon.getB2DPoint( nPointCount-1 );
249 const basegfx::B2DPoint aCtrPt1( (aStartPt.getX() + 2* pElement->points[0].x) / 3.0,
250 (aStartPt.getY() - 2 * pElement->points[0].y) / 3.0 );
251 const basegfx::B2DPoint aCtrPt2( (+2 * +pElement->points[0].x + pElement->points[1].x) / 3.0,
252 (-2 * pElement->points[0].y - pElement->points[1].y) / 3.0 );
253 rPolygon.append( basegfx::B2DPoint( +pElement->points[1].x, -pElement->points[1].y ) );
254 rPolygon.setNextControlPoint( nPointCount-1, aCtrPt1 );
255 rPolygon.setPrevControlPoint( nPointCount+0, aCtrPt2 );
256 } break;
257 }
258 }
259
GetGlyphOutline(sal_GlyphId aGlyphId,basegfx::B2DPolyPolygon & rResult) const260 bool CTTextStyle::GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolygon& rResult ) const
261 {
262 rResult.clear();
263
264 const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
265 // TODO: GF_FONTMASK if using non-native glyph fallback
266 CGGlyph nCGGlyph = aGlyphId & GF_IDXMASK;
267 CTFontRef pCTFont = (CTFontRef)CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName );
268 CGPathRef xPath = rCT.FontCreatePathForGlyph( pCTFont, nCGGlyph, NULL );
269
270 GgoData aGgoData;
271 aGgoData.mpPolyPoly = &rResult;
272 CGPathApply( xPath, (void*)&aGgoData, MyCGPathApplierFunc );
273 #if 0 // TODO: does OSX ensure that the last polygon is always closed?
274 const CGPathElement aClosingElement = { kCGPathElementCloseSubpath, NULL };
275 MyCGPathApplierFunc( (void*)&aGgoData, &aClosingElement );
276 #endif
277
278 // apply the font scale
279 if( mfFontScale != 1.0 ) {
280 basegfx::B2DHomMatrix aScale;
281 aScale.scale( +mfFontScale, +mfFontScale );
282 rResult.transform( aScale );
283 }
284
285 return true;
286 }
287
288 // =======================================================================
289
CTFontData(const ImplDevFontAttributes & rDFA,sal_IntPtr nFontId)290 CTFontData::CTFontData( const ImplDevFontAttributes& rDFA, sal_IntPtr nFontId )
291 : ImplMacFontData( rDFA, nFontId )
292 {}
293
294 // -----------------------------------------------------------------------
295
~CTFontData(void)296 CTFontData::~CTFontData( void )
297 {
298 // TODO: any resources to release?
299 }
300
301 // -----------------------------------------------------------------------
302
Clone(void) const303 ImplFontData* CTFontData::Clone( void ) const
304 {
305 return new CTFontData( *this);
306 }
307
308 // -----------------------------------------------------------------------
309
CreateMacTextStyle(const ImplFontSelectData & rFSD) const310 ImplMacTextStyle* CTFontData::CreateMacTextStyle( const ImplFontSelectData& rFSD ) const
311 {
312 return new CTTextStyle( rFSD);
313 }
314
315 // -----------------------------------------------------------------------
316
CreateFontInstance(ImplFontSelectData & rFSD) const317 ImplFontEntry* CTFontData::CreateFontInstance( /*const*/ ImplFontSelectData& rFSD ) const
318 {
319 return new ImplFontEntry( rFSD);
320 }
321
322 // -----------------------------------------------------------------------
323
GetFontTable(const char pTagName[5],unsigned char * pResultBuf) const324 int CTFontData::GetFontTable( const char pTagName[5], unsigned char* pResultBuf ) const
325 {
326 DBG_ASSERT( pTagName[4]=='\0', "CTFontData::GetFontTable with invalid tagname!\n" );
327
328 const CTFontTableTag nTagCode = (pTagName[0]<<24) + (pTagName[1]<<16) + (pTagName[2]<<8) + (pTagName[3]<<0);
329
330 // get the raw table length
331 CTFontDescriptorRef pFontDesc = reinterpret_cast<CTFontDescriptorRef>( GetFontId());
332 CTFontRef rCTFont = CTFontCreateWithFontDescriptor( pFontDesc, 0.0, NULL);
333 CFDataRef pDataRef = CTFontCopyTable( rCTFont, nTagCode, kCTFontTableOptionExcludeSynthetic);
334 CFRelease( rCTFont);
335 if( !pDataRef)
336 return 0;
337
338 const CFIndex nByteLength = CFDataGetLength( pDataRef);
339
340 // get the raw table data if requested
341 if( pResultBuf && (nByteLength > 0))
342 {
343 const CFRange aFullRange = CFRangeMake( 0, nByteLength);
344 CFDataGetBytes( pDataRef, aFullRange, (UInt8*)pResultBuf);
345 }
346
347 CFRelease( pDataRef);
348
349 return (int)nByteLength;
350 }
351
352 // =======================================================================
353
CTFontEnumCallBack(const void * pValue,void * pContext)354 static void CTFontEnumCallBack( const void* pValue, void* pContext )
355 {
356 CTFontDescriptorRef pFD = static_cast<CTFontDescriptorRef>(pValue);
357
358 // all CoreText fonts are device fonts that can rotate just fine
359 ImplDevFontAttributes rDFA;
360 rDFA.mbOrientation = true;
361 rDFA.mbDevice = true;
362 rDFA.mnQuality = 0;
363
364 // reset the font attributes
365 rDFA.meFamily = FAMILY_DONTKNOW;
366 rDFA.mePitch = PITCH_VARIABLE;
367 rDFA.meWidthType = WIDTH_NORMAL;
368 rDFA.meWeight = WEIGHT_NORMAL;
369 rDFA.meItalic = ITALIC_NONE;
370 rDFA.mbSymbolFlag = false;
371
372 // all scalable fonts on this platform are subsettable
373 rDFA.mbEmbeddable = false;
374 rDFA.mbSubsettable = true;
375
376 // get font name
377 // TODO: use kCTFontDisplayNameAttribute instead???
378 CFStringRef pFamilyName = (CFStringRef)CTFontDescriptorCopyAttribute( pFD, kCTFontFamilyNameAttribute );
379 rDFA.maName = GetOUString( pFamilyName );
380 // get font style
381 CFStringRef pStyleName = (CFStringRef)CTFontDescriptorCopyAttribute( pFD, kCTFontStyleNameAttribute );
382 rDFA.maStyleName = GetOUString( pStyleName );
383
384 // get font-enabled status
385 int bFontEnabled = FALSE;
386 CFNumberRef pFontEnabled = (CFNumberRef)CTFontDescriptorCopyAttribute( pFD, kCTFontEnabledAttribute );
387 CFNumberGetValue( pFontEnabled, kCFNumberIntType, &bFontEnabled );
388
389 // get font attributes
390 CFDictionaryRef pAttrDict = (CFDictionaryRef)CTFontDescriptorCopyAttribute( pFD, kCTFontTraitsAttribute );
391
392 // get symbolic trait
393 // TODO: use other traits such as MonoSpace/Condensed/Expanded or Vertical too
394 SInt64 nSymbolTrait = 0;
395 CFNumberRef pSymbolNum = NULL;
396 if( CFDictionaryGetValueIfPresent( pAttrDict, kCTFontSymbolicTrait, (const void**)&pSymbolNum ) ) {
397 CFNumberGetValue( pSymbolNum, kCFNumberSInt64Type, &nSymbolTrait );
398 rDFA.mbSymbolFlag = ((nSymbolTrait & kCTFontClassMaskTrait) == kCTFontSymbolicClass);
399 }
400
401 // get the font weight
402 double fWeight = 0;
403 CFNumberRef pWeightNum = (CFNumberRef)CFDictionaryGetValue( pAttrDict, kCTFontWeightTrait );
404 CFNumberGetValue( pWeightNum, kCFNumberDoubleType, &fWeight );
405 int nInt = WEIGHT_NORMAL;
406 if( fWeight > 0 ) {
407 nInt = rint(WEIGHT_NORMAL + fWeight * ((WEIGHT_BLACK - WEIGHT_NORMAL)/0.68));
408 if( nInt > WEIGHT_BLACK )
409 nInt = WEIGHT_BLACK;
410 } else if( fWeight < 0 ) {
411 nInt = rint(WEIGHT_NORMAL + fWeight * ((WEIGHT_NORMAL - WEIGHT_THIN)/0.9));
412 if( nInt < WEIGHT_THIN )
413 nInt = WEIGHT_THIN;
414 }
415 rDFA.meWeight = (FontWeight)nInt;
416
417 // get the font slant
418 double fSlant = 0;
419 CFNumberRef pSlantNum = (CFNumberRef)CFDictionaryGetValue( pAttrDict, kCTFontSlantTrait );
420 CFNumberGetValue( pSlantNum, kCFNumberDoubleType, &fSlant );
421 if( fSlant >= 0.035 )
422 rDFA.meItalic = ITALIC_NORMAL;
423
424 // get width trait
425 double fWidth = 0;
426 CFNumberRef pWidthNum = (CFNumberRef)CFDictionaryGetValue( pAttrDict, kCTFontWidthTrait );
427 CFNumberGetValue( pWidthNum, kCFNumberDoubleType, &fWidth );
428 nInt = WIDTH_NORMAL;
429 if( fWidth > 0 ) {
430 nInt = rint( WIDTH_NORMAL + fWidth * ((WIDTH_ULTRA_EXPANDED - WIDTH_NORMAL)/0.4));
431 if( nInt > WIDTH_ULTRA_EXPANDED )
432 nInt = WIDTH_ULTRA_EXPANDED;
433 } else if( fWidth < 0 ) {
434 nInt = rint( WIDTH_NORMAL + fWidth * ((WIDTH_NORMAL - WIDTH_ULTRA_CONDENSED)/0.5));
435 if( nInt < WIDTH_ULTRA_CONDENSED )
436 nInt = WIDTH_ULTRA_CONDENSED;
437 }
438 rDFA.meWidthType = (FontWidth)nInt;
439
440 // release the attribute dict that we had copied
441 CFRelease( pAttrDict );
442
443 // TODO? also use the HEAD table if available to get more attributes
444 // CFDataRef CTFontCopyTable( CTFontRef, kCTFontTableHead, /*kCTFontTableOptionNoOptions*/kCTFontTableOptionExcludeSynthetic );
445
446 #if (OSL_DEBUG_LEVEL >= 1)
447 // update font attributes using the font's postscript name
448 ImplDevFontAttributes rDFA2;
449 CTFontRef pFont = CTFontCreateWithFontDescriptor( pFD, 0.0, NULL );
450 CFStringRef pPSName = CTFontCopyPostScriptName( pFont );
451 const String aPSName = GetOUString( pPSName );
452
453 rDFA2.mbSymbolFlag = false;
454 rDFA2.mePitch = PITCH_VARIABLE;
455 rDFA2.meWidthType = WIDTH_NORMAL;
456 rDFA2.meWeight = WEIGHT_NORMAL;
457 rDFA2.meItalic = ITALIC_NONE;
458
459 UpdateAttributesFromPSName( aPSName, rDFA2 );
460 CFRelease( pPSName );
461 CFRelease( pFont );
462
463 // show the font details and compare the CTFontDescriptor vs. PSName traits
464 char cMatch = (rDFA.mbSymbolFlag==rDFA2.mbSymbolFlag);
465 cMatch &= (rDFA.meWeight==rDFA2.meWeight);
466 cMatch &= ((rDFA.meItalic==ITALIC_NONE) == (rDFA2.meItalic==ITALIC_NONE));
467 cMatch &= (rDFA.meWidthType==rDFA2.meWidthType);
468 cMatch = cMatch ? '.' : '#';
469
470 char aFN[256], aSN[256];
471 CFStringGetCString( pFamilyName, aFN, sizeof(aFN), kCFStringEncodingUTF8 );
472 CFStringGetCString( pStyleName, aSN, sizeof(aSN), kCFStringEncodingUTF8 );
473
474 const ByteString aPSCName( aPSName, RTL_TEXTENCODING_UTF8 );
475 const char* aPN = aPSCName.GetBuffer();
476 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",
477 (int)rDFA.mbSymbolFlag,(int)rDFA.meWeight,(int)rDFA.meItalic,(int)rDFA.meWidthType,
478 cMatch,
479 (int)rDFA2.mbSymbolFlag,(int)rDFA2.meWeight,(int)rDFA2.meItalic,(int)rDFA2.meWidthType,
480 bFontEnabled,
481 (int)(nSymbolTrait>>kCTFontClassMaskShift),fWeight,fSlant,fWidth,aFN,aSN,aPN);
482 #endif // (OSL_DEBUG_LEVEL >= 1)
483
484 if( bFontEnabled)
485 {
486 const sal_IntPtr nFontId = (sal_IntPtr)pValue;
487 CTFontData* pFontData = new CTFontData( rDFA, nFontId );
488 CTFontList* pFontList = (CTFontList*)pContext;
489 pFontList->AddFont( pFontData );
490 }
491 }
492
493 // =======================================================================
494
CTFontList()495 CTFontList::CTFontList()
496 : mpCTFontCollection( NULL )
497 , mpCTFontArray( NULL )
498 {}
499
500 // -----------------------------------------------------------------------
501
~CTFontList()502 CTFontList::~CTFontList()
503 {
504 CTFontContainer::const_iterator it = maFontContainer.begin();
505 for(; it != maFontContainer.end(); ++it )
506 delete (*it).second;
507 maFontContainer.clear();
508
509 if( mpCTFontArray )
510 CFRelease( mpCTFontArray );
511 if( mpCTFontCollection )
512 CFRelease( mpCTFontCollection );
513 }
514
515 // -----------------------------------------------------------------------
516
AddFont(CTFontData * pFontData)517 void CTFontList::AddFont( CTFontData* pFontData )
518 {
519 sal_IntPtr nFontId = pFontData->GetFontId();
520 maFontContainer[ nFontId ] = pFontData;
521 }
522
523 // -----------------------------------------------------------------------
524
AnnounceFonts(ImplDevFontList & rFontList) const525 void CTFontList::AnnounceFonts( ImplDevFontList& rFontList ) const
526 {
527 CTFontContainer::const_iterator it = maFontContainer.begin();
528 for(; it != maFontContainer.end(); ++it )
529 rFontList.Add( (*it).second->Clone() );
530 }
531
532 // -----------------------------------------------------------------------
533
GetFontDataFromId(sal_IntPtr nFontId) const534 ImplMacFontData* CTFontList::GetFontDataFromId( sal_IntPtr nFontId ) const
535 {
536 CTFontContainer::const_iterator it = maFontContainer.find( nFontId );
537 if( it == maFontContainer.end() )
538 return NULL;
539 return (*it).second;
540 }
541
542 // -----------------------------------------------------------------------
543
Init(void)544 bool CTFontList::Init( void )
545 {
546 #ifndef DISABLE_CORETEXT_DYNLOAD
547 // check availability of the CoreText API
548 const DynCoreTextSyms& rCT = DynCoreTextSyms::get();
549 if( !rCT.IsActive() )
550 return false;
551 #endif // DISABLE_CORETEXT_DYNLOAD
552
553 // enumerate available system fonts
554 static const int nMaxDictEntries = 8;
555 CFMutableDictionaryRef pCFDict = CFDictionaryCreateMutable( NULL,
556 nMaxDictEntries, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
557 CFDictionaryAddValue( pCFDict, kCTFontCollectionRemoveDuplicatesOption, kCFBooleanTrue );
558 mpCTFontCollection = rCT.FontCollectionCreateFromAvailableFonts( pCFDict );
559 CFRelease( pCFDict );
560
561 mpCTFontArray = rCT.FontCollectionCreateMatchingFontDescriptors( mpCTFontCollection );
562 const int nFontCount = CFArrayGetCount( mpCTFontArray );
563 const CFRange aFullRange = CFRangeMake( 0, nFontCount );
564 CFArrayApplyFunction( mpCTFontArray, aFullRange, CTFontEnumCallBack, this );
565
566 return true;
567 }
568
569 // =======================================================================
570
571 #ifndef DISABLE_CORETEXT_DYNLOAD
572
DynCoreTextSyms(void)573 DynCoreTextSyms::DynCoreTextSyms( void )
574 {
575 mbIsActive = false;
576
577 // check if CoreText has been explicitely disabled
578 const char* pEnvStr = getenv( "SAL_DISABLE_CORETEXT");
579 if( pEnvStr && (pEnvStr[0] != '0') )
580 return;
581
582 // check CoreText version
583 GetCoreTextVersion = (uint32_t(*)(void))dlsym( RTLD_DEFAULT, "CTGetCoreTextVersion");
584 if( !GetCoreTextVersion) return;
585
586 const uint32_t nCTVersion = GetCoreTextVersion();
587 static const uint32_t mykCTVersionNumber10_5 = 0x00020000;
588 if( nCTVersion < mykCTVersionNumber10_5)
589 return;
590
591 // load CoreText symbols dynamically
592 LineGetTrailingWhitespaceWidth = (double(*)(CTLineRef))dlsym( RTLD_DEFAULT, "CTLineGetTrailingWhitespaceWidth");
593 if( !LineGetTrailingWhitespaceWidth) return;
594
595 LineCreateJustifiedLine = (CTLineRef(*)(CTLineRef,CGFloat,double))dlsym( RTLD_DEFAULT, "CTLineCreateJustifiedLine");
596 if( !LineCreateJustifiedLine) return;
597
598 LineGetOffsetForStringIndex = (CGFloat(*)(CTLineRef,CFIndex,CGFloat*))dlsym( RTLD_DEFAULT, "CTLineGetOffsetForStringIndex");
599 if( !LineGetOffsetForStringIndex) return;
600
601 LineGetGlyphRuns = (CFArrayRef(*)(CTLineRef))dlsym( RTLD_DEFAULT, "CTLineGetGlyphRuns");
602 if( !LineGetGlyphRuns) return;
603
604 RunGetGlyphCount = (CFIndex(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetGlyphCount");
605 if( !RunGetGlyphCount) return;
606
607 RunGetGlyphsPtr = (const CGGlyph*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetGlyphsPtr");
608 if( !RunGetGlyphsPtr) return;
609
610 RunGetPositionsPtr = (const CGPoint*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetPositionsPtr");
611 if( !RunGetPositionsPtr) return;
612
613 RunGetAdvancesPtr = (const CGSize*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetAdvancesPtr");
614 if( !RunGetAdvancesPtr) return;
615
616 RunGetStringIndicesPtr = (const CFIndex*(*)(CTRunRef))dlsym( RTLD_DEFAULT, "CTRunGetStringIndicesPtr");
617 if( !RunGetStringIndicesPtr) return;
618
619 FontCollectionCreateFromAvailableFonts = (CTFontCollectionRef(*)(CFDictionaryRef))dlsym( RTLD_DEFAULT, "CTFontCollectionCreateFromAvailableFonts");
620 if( !FontCollectionCreateFromAvailableFonts) return;
621
622 FontCollectionCreateMatchingFontDescriptors = (CFArrayRef(*)(CTFontCollectionRef))dlsym( RTLD_DEFAULT, "CTFontCollectionCreateMatchingFontDescriptors");
623 if( !FontCollectionCreateMatchingFontDescriptors) return;
624
625 FontCreatePathForGlyph = (CGPathRef(*)(CTFontRef,CGGlyph,const CGAffineTransform*))dlsym( RTLD_DEFAULT, "CTFontCreatePathForGlyph");
626 if( !FontCreatePathForGlyph) return;
627
628 FontGetBoundingRectsForGlyphs = (CGRect(*)(CTFontRef,CTFontOrientation,CGGlyph*,CGRect*,CFIndex))dlsym( RTLD_DEFAULT, "CTFontGetBoundingRectsForGlyphs");
629 if( !FontGetBoundingRectsForGlyphs) return;
630
631 mbIsActive = true;
632 }
633
634 // -----------------------------------------------------------------------
635
get(void)636 const DynCoreTextSyms& DynCoreTextSyms::get( void )
637 {
638 static DynCoreTextSyms aCT;
639 return aCT;
640 }
641
642 #endif // DISABLE_CORETEXT_DYNLOAD
643
644 // =======================================================================
645
GetCoretextFontList(void)646 SystemFontList* GetCoretextFontList( void )
647 {
648 CTFontList* pList = new CTFontList();
649 if( !pList->Init() ) {
650 delete pList;
651 return NULL;
652 }
653
654 return pList;
655 }
656
657 // =======================================================================
658
659