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 <boost/assert.hpp>
26 #include <vector>
27 #include <hash_map>
28 #include <set>
29
30 #include "salgdi.h"
31 #include "atsfonts.hxx"
32
33 #include "vcl/svapp.hxx"
34 #include "vcl/impfont.hxx"
35
36 #include "basegfx/polygon/b2dpolygon.hxx"
37 #include "basegfx/matrix/b2dhommatrix.hxx"
38
39 typedef GlyphID ATSGlyphID;
40
41 // =======================================================================
42
43 // mac specific physically available font face
44 class AtsFontData
45 : public ImplMacFontData
46 {
47 public:
48 explicit AtsFontData( const ImplDevFontAttributes&, ATSUFontID );
49 virtual ~AtsFontData( 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 AtsFontList
60 : public SystemFontList
61 {
62 public:
63 explicit AtsFontList( void );
64 virtual ~AtsFontList( void );
65
66 virtual void AnnounceFonts( ImplDevFontList& ) const;
67 virtual ImplMacFontData* GetFontDataFromId( sal_IntPtr nFontId ) const;
68
69 private:
70 typedef std::hash_map<sal_IntPtr,AtsFontData*> AtsFontContainer;
71 AtsFontContainer maFontContainer;
72
73 void InitGlyphFallbacks( void );
74 ATSUFontFallbacks maFontFallbacks;
75 };
76
77 // =======================================================================
78
AtsFontData(const ImplDevFontAttributes & rDFA,ATSUFontID nFontId)79 AtsFontData::AtsFontData( const ImplDevFontAttributes& rDFA, ATSUFontID nFontId )
80 : ImplMacFontData( rDFA, (sal_IntPtr)nFontId )
81 {}
82
83 // -----------------------------------------------------------------------
84
~AtsFontData(void)85 AtsFontData::~AtsFontData( void )
86 {}
87
88 // -----------------------------------------------------------------------
89
Clone(void) const90 ImplFontData* AtsFontData::Clone( void ) const
91 {
92 AtsFontData* pClone = new AtsFontData(*this);
93 return pClone;
94 }
95
96 // -----------------------------------------------------------------------
97
CreateMacTextStyle(const ImplFontSelectData & rFSD) const98 ImplMacTextStyle* AtsFontData::CreateMacTextStyle( const ImplFontSelectData& rFSD ) const
99 {
100 return new AtsTextStyle( rFSD );
101 }
102
103 // -----------------------------------------------------------------------
104
CreateFontInstance(ImplFontSelectData & rFSD) const105 ImplFontEntry* AtsFontData::CreateFontInstance( /*const*/ ImplFontSelectData& rFSD ) const
106 {
107 return new ImplFontEntry( rFSD );
108 }
109
110 // -----------------------------------------------------------------------
111
GetFontTable(const char pTagName[5],unsigned char * pResultBuf) const112 int AtsFontData::GetFontTable( const char pTagName[5], unsigned char* pResultBuf ) const
113 {
114 DBG_ASSERT( aTagName[4]=='\0', "AtsFontData::GetFontTable with invalid tagname!\n" );
115
116 const FourCharCode pTagCode = (pTagName[0]<<24) + (pTagName[1]<<16) + (pTagName[2]<<8) + (pTagName[3]<<0);
117
118 // get the byte size of the raw table
119 ATSFontRef rATSFont = FMGetATSFontRefFromFont( (ATSUFontID)mnFontId );
120 ByteCount nBufSize = 0;
121 OSStatus eStatus = ATSFontGetTable( rATSFont, pTagCode, 0, 0, NULL, &nBufSize );
122 if( eStatus != noErr )
123 return 0;
124
125 // get the raw table data if requested
126 if( pResultBuf && (nBufSize > 0))
127 {
128 ByteCount nRawLength = 0;
129 eStatus = ATSFontGetTable( rATSFont, pTagCode, 0, nBufSize, (void*)pResultBuf, &nRawLength );
130 if( eStatus != noErr )
131 return 0;
132 DBG_ASSERT( (nBufSize==nRawLength), "AtsFontData::GetFontTable ByteCount mismatch!\n");
133 }
134
135 return nBufSize;
136 }
137
138 // =======================================================================
139
AtsTextStyle(const ImplFontSelectData & rFSD)140 AtsTextStyle::AtsTextStyle( const ImplFontSelectData& rFSD )
141 : ImplMacTextStyle( rFSD )
142 {
143 // create the style object for ATSUI font attributes
144 ATSUCreateStyle( &maATSUStyle );
145 const ImplFontSelectData* const pReqFont = &rFSD;
146
147 mpFontData = (AtsFontData*)rFSD.mpFontData;
148
149 // limit the ATS font size to avoid Fixed16.16 overflows
150 double fScaledFontHeight = pReqFont->mfExactHeight;
151 static const float fMaxFontHeight = 144.0;
152 if( fScaledFontHeight > fMaxFontHeight )
153 {
154 mfFontScale = fScaledFontHeight / fMaxFontHeight;
155 fScaledFontHeight = fMaxFontHeight;
156 }
157
158 // convert font rotation to radian
159 mfFontRotation = pReqFont->mnOrientation * (M_PI / 1800.0);
160
161 // determine if font stretching is needed
162 if( (pReqFont->mnWidth != 0) && (pReqFont->mnWidth != pReqFont->mnHeight) )
163 {
164 mfFontStretch = (float)pReqFont->mnWidth / pReqFont->mnHeight;
165 // set text style to stretching matrix
166 CGAffineTransform aMatrix = CGAffineTransformMakeScale( mfFontStretch, 1.0F );
167 const ATSUAttributeTag aMatrixTag = kATSUFontMatrixTag;
168 const ATSUAttributeValuePtr aAttr = &aMatrix;
169 const ByteCount aMatrixBytes = sizeof(aMatrix);
170 /*OSStatus eStatus =*/ ATSUSetAttributes( maATSUStyle, 1, &aMatrixTag, &aMatrixBytes, &aAttr );
171 }
172 }
173
174 // -----------------------------------------------------------------------
175
~AtsTextStyle(void)176 AtsTextStyle::~AtsTextStyle( void )
177 {
178 ATSUDisposeStyle( maATSUStyle );
179 }
180
181 // -----------------------------------------------------------------------
182
GetFontMetric(float fDPIY,ImplFontMetricData & rMetric) const183 void AtsTextStyle::GetFontMetric( float fDPIY, ImplFontMetricData& rMetric ) const
184 {
185 // get the font metrics (in point units)
186 // of the font that has eventually been size-limited
187
188 // get the matching ATSU font handle
189 ATSUFontID fontId;
190 OSStatus err = ::ATSUGetAttribute( maATSUStyle, kATSUFontTag, sizeof(ATSUFontID), &fontId, 0 );
191 DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font id\n");
192
193 ATSFontMetrics aMetrics;
194 ATSFontRef rFont = FMGetATSFontRefFromFont( fontId );
195 err = ATSFontGetHorizontalMetrics ( rFont, kATSOptionFlagsDefault, &aMetrics );
196 DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font metrics\n");
197 if( err != noErr )
198 return;
199
200 // all ATS fonts are scalable fonts
201 rMetric.mbScalableFont = true;
202 // TODO: check if any kerning is possible
203 rMetric.mbKernableFont = true;
204
205 // convert into VCL font metrics (in unscaled pixel units)
206
207 Fixed ptSize;
208 err = ATSUGetAttribute( maATSUStyle, kATSUSizeTag, sizeof(Fixed), &ptSize, 0);
209 DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font size\n");
210 const double fPointSize = Fix2X( ptSize );
211
212 // convert quartz units to pixel units
213 // please see the comment in AquaSalGraphics::SetFont() for details
214 const double fPixelSize = (mfFontScale * fDPIY * fPointSize);
215 rMetric.mnAscent = static_cast<long>(+aMetrics.ascent * fPixelSize + 0.5);
216 rMetric.mnDescent = static_cast<long>(-aMetrics.descent * fPixelSize + 0.5);
217 const long nExtDescent = static_cast<long>((-aMetrics.descent + aMetrics.leading) * fPixelSize + 0.5);
218 rMetric.mnExtLeading = nExtDescent - rMetric.mnDescent;
219 rMetric.mnIntLeading = 0;
220 // since ImplFontMetricData::mnWidth is only used for stretching/squeezing fonts
221 // setting this width to the pixel height of the fontsize is good enough
222 // it also makes the calculation of the stretch factor simple
223 rMetric.mnWidth = static_cast<long>(mfFontStretch * fPixelSize + 0.5);
224 }
225
226 // -----------------------------------------------------------------------
227
SetTextColor(const RGBAColor & rColor)228 void AtsTextStyle::SetTextColor( const RGBAColor& rColor )
229 {
230 RGBColor aAtsColor;
231 aAtsColor.red = (unsigned short)( rColor.GetRed() * 65535.0 );
232 aAtsColor.green = (unsigned short)( rColor.GetGreen() * 65535.0 );
233 aAtsColor.blue = (unsigned short)( rColor.GetColor() * 65535.0 );
234
235 ATSUAttributeTag aTag = kATSUColorTag;
236 ByteCount aValueSize = sizeof( aAtsColor );
237 ATSUAttributeValuePtr aValue = &aAtsColor;
238
239 /*OSStatus err =*/ ATSUSetAttributes( maATSUStyle, 1, &aTag, &aValueSize, &aValue );
240 }
241
242 // -----------------------------------------------------------------------
243
GetGlyphBoundRect(sal_GlyphId aGlyphId,Rectangle & rRect) const244 bool AtsTextStyle::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect ) const
245 {
246 ATSUStyle rATSUStyle = maATSUStyle; // TODO: handle glyph fallback
247 ATSGlyphID aGlyphId = aGlyphId;
248 ATSGlyphScreenMetrics aGlyphMetrics;
249 const bool bNonAntialiasedText = false;
250 OSStatus eStatus = ATSUGlyphGetScreenMetrics( rATSUStyle,
251 1, &aGlyphId, 0, FALSE, !bNonAntialiasedText, &aGlyphMetrics );
252 if( eStatus != noErr )
253 return false;
254
255 const long nMinX = (long)(+aGlyphMetrics.topLeft.x * mfFontScale - 0.5);
256 const long nMaxX = (long)(aGlyphMetrics.width * mfFontScale + 0.5) + nMinX;
257 const long nMinY = (long)(-aGlyphMetrics.topLeft.y * mfFontScale - 0.5);
258 const long nMaxY = (long)(aGlyphMetrics.height * mfFontScale + 0.5) + nMinY;
259 rRect = Rectangle( nMinX, nMinY, nMaxX, nMaxY );
260 return true;
261 }
262
263 // -----------------------------------------------------------------------
264
265 // callbacks from ATSUGlyphGetCubicPaths() fore GetGlyphOutline()
266 struct GgoData { basegfx::B2DPolygon maPolygon; basegfx::B2DPolyPolygon* mpPolyPoly; };
267
GgoLineToProc(const Float32Point * pPoint,void * pData)268 static OSStatus GgoLineToProc( const Float32Point* pPoint, void* pData )
269 {
270 basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
271 const basegfx::B2DPoint aB2DPoint( pPoint->x, pPoint->y );
272 rPolygon.append( aB2DPoint );
273 return noErr;
274 }
275
GgoCurveToProc(const Float32Point * pCP1,const Float32Point * pCP2,const Float32Point * pPoint,void * pData)276 static OSStatus GgoCurveToProc( const Float32Point* pCP1, const Float32Point* pCP2,
277 const Float32Point* pPoint, void* pData )
278 {
279 basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
280 const sal_uInt32 nPointCount = rPolygon.count();
281 const basegfx::B2DPoint aB2DControlPoint1( pCP1->x, pCP1->y );
282 rPolygon.setNextControlPoint( nPointCount-1, aB2DControlPoint1 );
283 const basegfx::B2DPoint aB2DEndPoint( pPoint->x, pPoint->y );
284 rPolygon.append( aB2DEndPoint );
285 const basegfx::B2DPoint aB2DControlPoint2( pCP2->x, pCP2->y );
286 rPolygon.setPrevControlPoint( nPointCount, aB2DControlPoint2 );
287 return noErr;
288 }
289
GgoClosePathProc(void * pData)290 static OSStatus GgoClosePathProc( void* pData )
291 {
292 GgoData* pGgoData = static_cast<GgoData*>(pData);
293 basegfx::B2DPolygon& rPolygon = pGgoData->maPolygon;
294 if( rPolygon.count() > 0 )
295 pGgoData->mpPolyPoly->append( rPolygon );
296 rPolygon.clear();
297 return noErr;
298 }
299
GgoMoveToProc(const Float32Point * pPoint,void * pData)300 static OSStatus GgoMoveToProc( const Float32Point* pPoint, void* pData )
301 {
302 GgoClosePathProc( pData );
303 OSStatus eStatus = GgoLineToProc( pPoint, pData );
304 return eStatus;
305 }
306
GetGlyphOutline(sal_GlyphId aGlyphId,basegfx::B2DPolyPolygon & rResult) const307 bool AtsTextStyle::GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolygon& rResult ) const
308 {
309 GgoData aGgoData;
310 aGgoData.mpPolyPoly = &rResult;
311 rResult.clear();
312
313 OSStatus eGgoStatus = noErr;
314 OSStatus eStatus = ATSUGlyphGetCubicPaths( maATSUStyle, aGlyphId,
315 GgoMoveToProc, GgoLineToProc, GgoCurveToProc, GgoClosePathProc,
316 &aGgoData, &eGgoStatus );
317 if( (eStatus != noErr) ) // TODO: why is (eGgoStatus!=noErr) when curves are involved?
318 return false;
319
320 GgoClosePathProc( &aGgoData );
321
322 // apply the font scale
323 if( mfFontScale != 1.0 ) {
324 basegfx::B2DHomMatrix aScale;
325 aScale.scale( +mfFontScale, +mfFontScale );
326 rResult.transform( aScale );
327 }
328
329 return true;
330 }
331
332 // =======================================================================
333
GetDevFontAttributes(ATSUFontID nFontID,ImplDevFontAttributes & rDFA)334 static bool GetDevFontAttributes( ATSUFontID nFontID, ImplDevFontAttributes& rDFA )
335 {
336 // all ATSU fonts are device fonts that can be directly rotated
337 rDFA.mbOrientation = true;
338 rDFA.mbDevice = true;
339 rDFA.mnQuality = 0;
340
341 // reset the attributes
342 rDFA.meFamily = FAMILY_DONTKNOW;
343 rDFA.mePitch = PITCH_VARIABLE;
344 rDFA.meWidthType = WIDTH_NORMAL;
345 rDFA.meWeight = WEIGHT_NORMAL;
346 rDFA.meItalic = ITALIC_NONE;
347 rDFA.mbSymbolFlag = false;
348
349 // ignore bitmap fonts
350 ATSFontRef rATSFontRef = FMGetATSFontRefFromFont( nFontID );
351 ByteCount nHeadLen = 0;
352 OSStatus rc = ATSFontGetTable( rATSFontRef, 0x68656164/*head*/, 0, 0, NULL, &nHeadLen );
353 if( (rc != noErr) || (nHeadLen <= 0) )
354 return false;
355
356 // all scalable fonts on this platform are subsettable
357 rDFA.mbSubsettable = true;
358 rDFA.mbEmbeddable = false;
359 // TODO: these members are needed only for our X11 platform targets
360 rDFA.meAntiAlias = ANTIALIAS_DONTKNOW;
361 rDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW;
362
363 // prepare iterating over all name strings of the font
364 ItemCount nFontNameCount = 0;
365 rc = ATSUCountFontNames( nFontID, &nFontNameCount );
366 if( rc != noErr )
367 return false;
368 int nBestNameValue = 0;
369 int nBestStyleValue = 0;
370 FontLanguageCode eBestLangCode = 0;
371 const FontLanguageCode eUILangCode = Application::GetSettings().GetUILanguage();
372 typedef std::vector<char> NameBuffer;
373 NameBuffer aNameBuffer( 256 );
374
375 // iterate over all available name strings of the font
376 for( ItemCount nNameIndex = 0; nNameIndex < nFontNameCount; ++nNameIndex )
377 {
378 ByteCount nNameLength = 0;
379
380 FontNameCode eFontNameCode;
381 FontPlatformCode eFontNamePlatform;
382 FontScriptCode eFontNameScript;
383 FontLanguageCode eFontNameLanguage;
384 rc = ATSUGetIndFontName( nFontID, nNameIndex, 0, NULL,
385 &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage );
386 if( rc != noErr )
387 continue;
388
389 // ignore non-interesting name entries
390 if( (eFontNameCode != kFontFamilyName)
391 && (eFontNameCode != kFontStyleName)
392 && (eFontNameCode != kFontPostscriptName) )
393 continue;
394
395 // heuristic to find the most common font name
396 // preferring default language names or even better the names matching to the UI language
397 int nNameValue = (eFontNameLanguage==eUILangCode) ? 0 : ((eFontNameLanguage==0) ? -10 : -20);
398 rtl_TextEncoding eEncoding = RTL_TEXTENCODING_UNICODE;
399 const int nPlatformEncoding = ((int)eFontNamePlatform << 8) + (int)eFontNameScript;
400 switch( nPlatformEncoding )
401 {
402 case 0x000: nNameValue += 23; break; // Unicode 1.0
403 case 0x001: nNameValue += 24; break; // Unicode 1.1
404 case 0x002: nNameValue += 25; break; // iso10646_1993
405 case 0x003: nNameValue += 26; break; // UCS-2
406 case 0x301: nNameValue += 27; break; // Win UCS-2
407 case 0x004: // UCS-4
408 case 0x30A: nNameValue += 0; // Win-UCS-4
409 eEncoding = RTL_TEXTENCODING_UCS4;
410 break;
411 case 0x100: nNameValue += 21; // Mac Roman
412 eEncoding = RTL_TEXTENCODING_APPLE_ROMAN;
413 break;
414 case 0x300: nNameValue = 0; // Win Symbol encoded name!
415 rDFA.mbSymbolFlag = true; // (often seen for symbol fonts)
416 break;
417 default: nNameValue = 0; // ignore other encodings
418 break;
419 }
420
421 // ignore name entries with no useful encoding
422 if( nNameValue <= 0 )
423 continue;
424 if( nNameLength >= aNameBuffer.size() )
425 continue;
426
427 // get the encoded name
428 aNameBuffer.reserve( nNameLength+1 ); // extra byte helps for debugging
429 rc = ATSUGetIndFontName( nFontID, nNameIndex, nNameLength, &aNameBuffer[0],
430 &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage );
431 if( rc != noErr )
432 continue;
433
434 // convert to unicode name
435 UniString aUtf16Name;
436 if( eEncoding == RTL_TEXTENCODING_UNICODE ) // we are just interested in UTF16 encoded names
437 aUtf16Name = UniString( (const sal_Unicode*)&aNameBuffer[0], nNameLength/2 );
438 else if( eEncoding == RTL_TEXTENCODING_UCS4 )
439 aUtf16Name = UniString(); // TODO
440 else // assume the non-unicode encoded names are byte encoded
441 aUtf16Name = UniString( &aNameBuffer[0], nNameLength, eEncoding );
442
443 // ignore empty strings
444 if( aUtf16Name.Len() <= 0 )
445 continue;
446
447 // handle the name depending on its namecode
448 switch( eFontNameCode )
449 {
450 case kFontFamilyName:
451 // ignore font names starting with '.'
452 if( aUtf16Name.GetChar(0) == '.' )
453 nNameValue = 0;
454 else if( rDFA.maName.Len() )
455 {
456 // even if a family name is not the one we are looking for
457 // it is still useful as a font name alternative
458 if( rDFA.maMapNames.Len() )
459 rDFA.maMapNames += ';';
460 rDFA.maMapNames += (nBestNameValue < nNameValue) ? rDFA.maName : aUtf16Name;
461 }
462 if( nBestNameValue < nNameValue )
463 {
464 // get the best family name
465 nBestNameValue = nNameValue;
466 eBestLangCode = eFontNameLanguage;
467 rDFA.maName = aUtf16Name;
468 }
469 break;
470 case kFontStyleName:
471 // get a style name matching to the family name
472 if( nBestStyleValue < nNameValue )
473 {
474 nBestStyleValue = nNameValue;
475 rDFA.maStyleName = aUtf16Name;
476 }
477 break;
478 case kFontPostscriptName:
479 // use the postscript name to get some useful info
480 UpdateAttributesFromPSName( aUtf16Name, rDFA );
481 break;
482 default:
483 // TODO: use other name entries too?
484 break;
485 }
486 }
487
488 bool bRet = (rDFA.maName.Len() > 0);
489 return bRet;
490 }
491
492 // =======================================================================
493
GetAtsFontList(void)494 SystemFontList* GetAtsFontList( void )
495 {
496 return new AtsFontList();
497 }
498
499 // =======================================================================
500
AtsFontList()501 AtsFontList::AtsFontList()
502 {
503 // count available system fonts
504 ItemCount nATSUICompatibleFontsAvailable = 0;
505 if( ATSUFontCount(&nATSUICompatibleFontsAvailable) != noErr )
506 return;
507 if( nATSUICompatibleFontsAvailable <= 0 )
508 return;
509
510 // enumerate available system fonts
511 typedef std::vector<ATSUFontID> AtsFontIDVector;
512 AtsFontIDVector aFontIDVector( nATSUICompatibleFontsAvailable );
513 ItemCount nFontItemsCount = 0;
514 if( ATSUGetFontIDs( &aFontIDVector[0], aFontIDVector.capacity(), &nFontItemsCount ) != noErr )
515 return;
516
517 BOOST_ASSERT(nATSUICompatibleFontsAvailable == nFontItemsCount && "Strange I would expect them to be equal");
518
519 // prepare use of the available fonts
520 AtsFontIDVector::const_iterator it = aFontIDVector.begin();
521 for(; it != aFontIDVector.end(); ++it )
522 {
523 const ATSUFontID nFontID = *it;
524 ImplDevFontAttributes aDevFontAttr;
525 if( !GetDevFontAttributes( nFontID, aDevFontAttr ) )
526 continue;
527 AtsFontData* pFontData = new AtsFontData( aDevFontAttr, nFontID );
528 maFontContainer[ nFontID ] = pFontData;
529 }
530
531 InitGlyphFallbacks();
532 }
533
534 // -----------------------------------------------------------------------
535
~AtsFontList()536 AtsFontList::~AtsFontList()
537 {
538 AtsFontContainer::const_iterator it = maFontContainer.begin();
539 for(; it != maFontContainer.end(); ++it )
540 delete (*it).second;
541 maFontContainer.clear();
542
543 ATSUDisposeFontFallbacks( maFontFallbacks );
544 }
545
546 // -----------------------------------------------------------------------
547
AnnounceFonts(ImplDevFontList & rFontList) const548 void AtsFontList::AnnounceFonts( ImplDevFontList& rFontList ) const
549 {
550 AtsFontContainer::const_iterator it = maFontContainer.begin();
551 for(; it != maFontContainer.end(); ++it )
552 rFontList.Add( (*it).second->Clone() );
553 }
554
555 // -----------------------------------------------------------------------
556
GetFontDataFromId(sal_IntPtr nFontId) const557 ImplMacFontData* AtsFontList::GetFontDataFromId( sal_IntPtr nFontId ) const
558 {
559 AtsFontContainer::const_iterator it = maFontContainer.find( nFontId );
560 if( it == maFontContainer.end() )
561 return NULL;
562 return (*it).second;
563 }
564
565 // -----------------------------------------------------------------------
566
567 // not all fonts are suitable for glyph fallback => sort them
568 struct GfbCompare{ bool operator()(const ImplMacFontData*, const ImplMacFontData*); };
569
operator ()(const ImplMacFontData * pA,const ImplMacFontData * pB)570 inline bool GfbCompare::operator()( const ImplMacFontData* pA, const ImplMacFontData* pB )
571 {
572 // use symbol fonts only as last resort
573 bool bPreferA = !pA->IsSymbolFont();
574 bool bPreferB = !pB->IsSymbolFont();
575 if( bPreferA != bPreferB )
576 return bPreferA;
577 // prefer scalable fonts
578 bPreferA = pA->IsScalable();
579 bPreferB = pB->IsScalable();
580 if( bPreferA != bPreferB )
581 return bPreferA;
582 // prefer non-slanted fonts
583 bPreferA = (pA->GetSlant() == ITALIC_NONE);
584 bPreferB = (pB->GetSlant() == ITALIC_NONE);
585 if( bPreferA != bPreferB )
586 return bPreferA;
587 // prefer normal weight fonts
588 bPreferA = (pA->GetWeight() == WEIGHT_NORMAL);
589 bPreferB = (pB->GetWeight() == WEIGHT_NORMAL);
590 if( bPreferA != bPreferB )
591 return bPreferA;
592 // prefer normal width fonts
593 bPreferA = (pA->GetWidthType() == WIDTH_NORMAL);
594 bPreferB = (pB->GetWidthType() == WIDTH_NORMAL);
595 if( bPreferA != bPreferB )
596 return bPreferA;
597 return false;
598 }
599
600 // -----------------------------------------------------------------------
601
InitGlyphFallbacks()602 void AtsFontList::InitGlyphFallbacks()
603 {
604 // sort fonts for "glyph fallback"
605 typedef std::multiset<const ImplMacFontData*,GfbCompare> FallbackSet;
606 FallbackSet aFallbackSet;
607 AtsFontContainer::const_iterator it = maFontContainer.begin();
608 for(; it != maFontContainer.end(); ++it )
609 {
610 const ImplMacFontData* pIFD = (*it).second;
611 // TODO: subsettable/embeddable glyph fallback only for PDF export?
612 if( pIFD->IsSubsettable() || pIFD->IsEmbeddable() )
613 aFallbackSet.insert( pIFD );
614 }
615
616 // tell ATSU about font preferences for "glyph fallback"
617 typedef std::vector<ATSUFontID> AtsFontIDVector;
618 AtsFontIDVector aFallbackVector;
619 aFallbackVector.reserve( maFontContainer.size() );
620 FallbackSet::const_iterator itFData = aFallbackSet.begin();
621 for(; itFData != aFallbackSet.end(); ++itFData )
622 {
623 const ImplMacFontData* pFontData = (*itFData);
624 ATSUFontID nFontID = (ATSUFontID)pFontData->GetFontId();
625 aFallbackVector.push_back( nFontID );
626 }
627
628 ATSUCreateFontFallbacks( &maFontFallbacks );
629 ATSUSetObjFontFallbacks( maFontFallbacks,
630 aFallbackVector.size(), &aFallbackVector[0], kATSUSequentialFallbacksPreferred );
631 }
632
633 // =======================================================================
634
635