xref: /trunk/main/vcl/aqua/source/gdi/atsfonts.cxx (revision cf6516809c57e1bb0a940545cca99cdad54d4ce2)
151747b8eSHerbert Dürr /**************************************************************
251747b8eSHerbert Dürr  *
351747b8eSHerbert Dürr  * Licensed to the Apache Software Foundation (ASF) under one
451747b8eSHerbert Dürr  * or more contributor license agreements.  See the NOTICE file
551747b8eSHerbert Dürr  * distributed with this work for additional information
651747b8eSHerbert Dürr  * regarding copyright ownership.  The ASF licenses this file
751747b8eSHerbert Dürr  * to you under the Apache License, Version 2.0 (the
851747b8eSHerbert Dürr  * "License"); you may not use this file except in compliance
951747b8eSHerbert Dürr  * with the License.  You may obtain a copy of the License at
1051747b8eSHerbert Dürr  *
1151747b8eSHerbert Dürr  *   http://www.apache.org/licenses/LICENSE-2.0
1251747b8eSHerbert Dürr  *
1351747b8eSHerbert Dürr  * Unless required by applicable law or agreed to in writing,
1451747b8eSHerbert Dürr  * software distributed under the License is distributed on an
1551747b8eSHerbert Dürr  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
1651747b8eSHerbert Dürr  * KIND, either express or implied.  See the License for the
1751747b8eSHerbert Dürr  * specific language governing permissions and limitations
1851747b8eSHerbert Dürr  * under the License.
1951747b8eSHerbert Dürr  *
2051747b8eSHerbert Dürr  *************************************************************/
2151747b8eSHerbert Dürr 
2251747b8eSHerbert Dürr // MARKER(update_precomp.py): autogen include statement, do not remove
2351747b8eSHerbert Dürr #include "precompiled_vcl.hxx"
2451747b8eSHerbert Dürr 
2551747b8eSHerbert Dürr #include <boost/assert.hpp>
2651747b8eSHerbert Dürr #include <vector>
27e26449d3SHerbert Dürr #include <hash_map>
2851747b8eSHerbert Dürr #include <set>
2951747b8eSHerbert Dürr 
30e26449d3SHerbert Dürr #include "salgdi.h"
3151747b8eSHerbert Dürr #include "atsfonts.hxx"
32e26449d3SHerbert Dürr 
33e26449d3SHerbert Dürr #include "vcl/svapp.hxx"
34e26449d3SHerbert Dürr #include "vcl/impfont.hxx"
35e26449d3SHerbert Dürr 
36e26449d3SHerbert Dürr #include "basegfx/polygon/b2dpolygon.hxx"
37e26449d3SHerbert Dürr #include "basegfx/matrix/b2dhommatrix.hxx"
38e26449d3SHerbert Dürr 
39e26449d3SHerbert Dürr typedef GlyphID ATSGlyphID;
40e26449d3SHerbert Dürr 
41e26449d3SHerbert Dürr // =======================================================================
42e26449d3SHerbert Dürr 
43e26449d3SHerbert Dürr // mac specific physically available font face
44e26449d3SHerbert Dürr class AtsFontData
45e26449d3SHerbert Dürr :   public ImplMacFontData
46e26449d3SHerbert Dürr {
47e26449d3SHerbert Dürr public:
48e26449d3SHerbert Dürr     explicit                AtsFontData( const ImplDevFontAttributes&, ATSUFontID );
49e26449d3SHerbert Dürr     virtual                 ~AtsFontData( void );
50e26449d3SHerbert Dürr     virtual ImplFontData*   Clone( void ) const;
51e26449d3SHerbert Dürr 
52e26449d3SHerbert Dürr     virtual ImplMacTextStyle*   CreateMacTextStyle( const ImplFontSelectData& ) const;
53e26449d3SHerbert Dürr     virtual ImplFontEntry*      CreateFontInstance( /*const*/ ImplFontSelectData& ) const;
54e26449d3SHerbert Dürr     virtual int                 GetFontTable( const char pTagName[5], unsigned char* ) const;
55e26449d3SHerbert Dürr };
56e26449d3SHerbert Dürr 
57e26449d3SHerbert Dürr // =======================================================================
58e26449d3SHerbert Dürr 
59e26449d3SHerbert Dürr class AtsFontList
60e26449d3SHerbert Dürr :   public SystemFontList
61e26449d3SHerbert Dürr {
62e26449d3SHerbert Dürr public:
63e26449d3SHerbert Dürr     explicit    AtsFontList( void );
64e26449d3SHerbert Dürr     virtual     ~AtsFontList( void );
65e26449d3SHerbert Dürr 
66e26449d3SHerbert Dürr     virtual void            AnnounceFonts( ImplDevFontList& ) const;
67e26449d3SHerbert Dürr     virtual ImplMacFontData* GetFontDataFromId( sal_IntPtr nFontId ) const;
68e26449d3SHerbert Dürr 
69e26449d3SHerbert Dürr private:
70e26449d3SHerbert Dürr     typedef std::hash_map<sal_IntPtr,AtsFontData*> AtsFontContainer;
71e26449d3SHerbert Dürr     AtsFontContainer maFontContainer;
72e26449d3SHerbert Dürr 
73e26449d3SHerbert Dürr     void InitGlyphFallbacks( void );
74e26449d3SHerbert Dürr     ATSUFontFallbacks   maFontFallbacks;
75e26449d3SHerbert Dürr };
76e26449d3SHerbert Dürr 
77e26449d3SHerbert Dürr // =======================================================================
78e26449d3SHerbert Dürr 
AtsFontData(const ImplDevFontAttributes & rDFA,ATSUFontID nFontId)79e26449d3SHerbert Dürr AtsFontData::AtsFontData( const ImplDevFontAttributes& rDFA, ATSUFontID nFontId )
80e26449d3SHerbert Dürr :   ImplMacFontData( rDFA, (sal_IntPtr)nFontId )
81e26449d3SHerbert Dürr {}
8251747b8eSHerbert Dürr 
8351747b8eSHerbert Dürr // -----------------------------------------------------------------------
8451747b8eSHerbert Dürr 
~AtsFontData(void)85e26449d3SHerbert Dürr AtsFontData::~AtsFontData( void )
86e26449d3SHerbert Dürr {}
87e26449d3SHerbert Dürr 
88e26449d3SHerbert Dürr // -----------------------------------------------------------------------
89e26449d3SHerbert Dürr 
Clone(void) const90e26449d3SHerbert Dürr ImplFontData* AtsFontData::Clone( void ) const
91e26449d3SHerbert Dürr {
92e26449d3SHerbert Dürr     AtsFontData* pClone = new AtsFontData(*this);
93e26449d3SHerbert Dürr     return pClone;
94e26449d3SHerbert Dürr }
95e26449d3SHerbert Dürr 
96e26449d3SHerbert Dürr // -----------------------------------------------------------------------
97e26449d3SHerbert Dürr 
CreateMacTextStyle(const ImplFontSelectData & rFSD) const98e26449d3SHerbert Dürr ImplMacTextStyle* AtsFontData::CreateMacTextStyle( const ImplFontSelectData& rFSD ) const
99e26449d3SHerbert Dürr {
100e26449d3SHerbert Dürr     return new AtsTextStyle( rFSD );
101e26449d3SHerbert Dürr }
102e26449d3SHerbert Dürr 
103e26449d3SHerbert Dürr // -----------------------------------------------------------------------
104e26449d3SHerbert Dürr 
CreateFontInstance(ImplFontSelectData & rFSD) const105e26449d3SHerbert Dürr ImplFontEntry* AtsFontData::CreateFontInstance( /*const*/ ImplFontSelectData& rFSD ) const
106e26449d3SHerbert Dürr {
107e26449d3SHerbert Dürr     return new ImplFontEntry( rFSD );
108e26449d3SHerbert Dürr }
109e26449d3SHerbert Dürr 
110e26449d3SHerbert Dürr // -----------------------------------------------------------------------
111e26449d3SHerbert Dürr 
GetFontTable(const char pTagName[5],unsigned char * pResultBuf) const112e26449d3SHerbert Dürr int AtsFontData::GetFontTable( const char pTagName[5], unsigned char* pResultBuf ) const
113e26449d3SHerbert Dürr {
114e26449d3SHerbert Dürr     DBG_ASSERT( aTagName[4]=='\0', "AtsFontData::GetFontTable with invalid tagname!\n" );
115e26449d3SHerbert Dürr 
116e26449d3SHerbert Dürr     const FourCharCode pTagCode = (pTagName[0]<<24) + (pTagName[1]<<16) + (pTagName[2]<<8) + (pTagName[3]<<0);
117e26449d3SHerbert Dürr 
118e26449d3SHerbert Dürr     // get the byte size of the raw table
119e26449d3SHerbert Dürr     ATSFontRef rATSFont = FMGetATSFontRefFromFont( (ATSUFontID)mnFontId );
120e26449d3SHerbert Dürr     ByteCount nBufSize = 0;
121e26449d3SHerbert Dürr     OSStatus eStatus = ATSFontGetTable( rATSFont, pTagCode, 0, 0, NULL, &nBufSize );
122e26449d3SHerbert Dürr     if( eStatus != noErr )
123e26449d3SHerbert Dürr         return 0;
124e26449d3SHerbert Dürr 
125e26449d3SHerbert Dürr     // get the raw table data if requested
126e26449d3SHerbert Dürr     if( pResultBuf && (nBufSize > 0))
127e26449d3SHerbert Dürr     {
128e26449d3SHerbert Dürr         ByteCount nRawLength = 0;
129e26449d3SHerbert Dürr         eStatus = ATSFontGetTable( rATSFont, pTagCode, 0, nBufSize, (void*)pResultBuf, &nRawLength );
130e26449d3SHerbert Dürr         if( eStatus != noErr )
131e26449d3SHerbert Dürr             return 0;
132e26449d3SHerbert Dürr         DBG_ASSERT( (nBufSize==nRawLength), "AtsFontData::GetFontTable ByteCount mismatch!\n");
133e26449d3SHerbert Dürr     }
134e26449d3SHerbert Dürr 
135e26449d3SHerbert Dürr     return nBufSize;
136e26449d3SHerbert Dürr }
137e26449d3SHerbert Dürr 
138e26449d3SHerbert Dürr // =======================================================================
139e26449d3SHerbert Dürr 
AtsTextStyle(const ImplFontSelectData & rFSD)140e26449d3SHerbert Dürr AtsTextStyle::AtsTextStyle( const ImplFontSelectData& rFSD )
141e26449d3SHerbert Dürr :   ImplMacTextStyle( rFSD )
142e26449d3SHerbert Dürr {
143e26449d3SHerbert Dürr     // create the style object for ATSUI font attributes
144e26449d3SHerbert Dürr     ATSUCreateStyle( &maATSUStyle );
145e26449d3SHerbert Dürr     const ImplFontSelectData* const pReqFont = &rFSD;
146e26449d3SHerbert Dürr 
147e26449d3SHerbert Dürr     mpFontData = (AtsFontData*)rFSD.mpFontData;
148e26449d3SHerbert Dürr 
149e26449d3SHerbert Dürr     // limit the ATS font size to avoid Fixed16.16 overflows
150e26449d3SHerbert Dürr     double fScaledFontHeight = pReqFont->mfExactHeight;
151e26449d3SHerbert Dürr     static const float fMaxFontHeight = 144.0;
152e26449d3SHerbert Dürr     if( fScaledFontHeight > fMaxFontHeight )
153e26449d3SHerbert Dürr     {
154e26449d3SHerbert Dürr         mfFontScale = fScaledFontHeight / fMaxFontHeight;
155e26449d3SHerbert Dürr         fScaledFontHeight = fMaxFontHeight;
156e26449d3SHerbert Dürr     }
157e26449d3SHerbert Dürr 
158e26449d3SHerbert Dürr     // convert font rotation to radian
159e26449d3SHerbert Dürr     mfFontRotation = pReqFont->mnOrientation * (M_PI / 1800.0);
160e26449d3SHerbert Dürr 
161e26449d3SHerbert Dürr     // determine if font stretching is needed
162e26449d3SHerbert Dürr     if( (pReqFont->mnWidth != 0) && (pReqFont->mnWidth != pReqFont->mnHeight) )
163e26449d3SHerbert Dürr     {
164e26449d3SHerbert Dürr         mfFontStretch = (float)pReqFont->mnWidth / pReqFont->mnHeight;
165e26449d3SHerbert Dürr         // set text style to stretching matrix
166e26449d3SHerbert Dürr         CGAffineTransform aMatrix = CGAffineTransformMakeScale( mfFontStretch, 1.0F );
167e26449d3SHerbert Dürr         const ATSUAttributeTag aMatrixTag = kATSUFontMatrixTag;
168e26449d3SHerbert Dürr         const ATSUAttributeValuePtr aAttr = &aMatrix;
169e26449d3SHerbert Dürr         const ByteCount aMatrixBytes = sizeof(aMatrix);
170e26449d3SHerbert Dürr         /*OSStatus eStatus =*/ ATSUSetAttributes( maATSUStyle, 1, &aMatrixTag, &aMatrixBytes, &aAttr );
171e26449d3SHerbert Dürr     }
172e26449d3SHerbert Dürr }
173e26449d3SHerbert Dürr 
174e26449d3SHerbert Dürr // -----------------------------------------------------------------------
175e26449d3SHerbert Dürr 
~AtsTextStyle(void)176e26449d3SHerbert Dürr AtsTextStyle::~AtsTextStyle( void )
177e26449d3SHerbert Dürr {
178e26449d3SHerbert Dürr     ATSUDisposeStyle( maATSUStyle );
179e26449d3SHerbert Dürr }
180e26449d3SHerbert Dürr 
181e26449d3SHerbert Dürr // -----------------------------------------------------------------------
182e26449d3SHerbert Dürr 
GetFontMetric(float fDPIY,ImplFontMetricData & rMetric) const183e26449d3SHerbert Dürr void AtsTextStyle::GetFontMetric( float fDPIY, ImplFontMetricData& rMetric ) const
184e26449d3SHerbert Dürr {
185e26449d3SHerbert Dürr     // get the font metrics (in point units)
186e26449d3SHerbert Dürr     // of the font that has eventually been size-limited
187e26449d3SHerbert Dürr 
188e26449d3SHerbert Dürr     // get the matching ATSU font handle
189e26449d3SHerbert Dürr     ATSUFontID fontId;
190e26449d3SHerbert Dürr     OSStatus err = ::ATSUGetAttribute( maATSUStyle, kATSUFontTag, sizeof(ATSUFontID), &fontId, 0 );
191e26449d3SHerbert Dürr     DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font id\n");
192e26449d3SHerbert Dürr 
193e26449d3SHerbert Dürr     ATSFontMetrics aMetrics;
194e26449d3SHerbert Dürr     ATSFontRef rFont = FMGetATSFontRefFromFont( fontId );
195e26449d3SHerbert Dürr     err = ATSFontGetHorizontalMetrics ( rFont, kATSOptionFlagsDefault, &aMetrics );
196e26449d3SHerbert Dürr     DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font metrics\n");
197e26449d3SHerbert Dürr     if( err != noErr )
198e26449d3SHerbert Dürr         return;
199e26449d3SHerbert Dürr 
200e26449d3SHerbert Dürr     // all ATS fonts are scalable fonts
201e26449d3SHerbert Dürr     rMetric.mbScalableFont = true;
202e26449d3SHerbert Dürr     // TODO: check if any kerning is possible
203e26449d3SHerbert Dürr     rMetric.mbKernableFont = true;
204e26449d3SHerbert Dürr 
205e26449d3SHerbert Dürr     // convert into VCL font metrics (in unscaled pixel units)
206e26449d3SHerbert Dürr 
207e26449d3SHerbert Dürr     Fixed ptSize;
208e26449d3SHerbert Dürr     err = ATSUGetAttribute( maATSUStyle, kATSUSizeTag, sizeof(Fixed), &ptSize, 0);
209e26449d3SHerbert Dürr     DBG_ASSERT( (err==noErr), "AquaSalGraphics::GetFontMetric() : could not get font size\n");
210e26449d3SHerbert Dürr     const double fPointSize = Fix2X( ptSize );
211e26449d3SHerbert Dürr 
212e26449d3SHerbert Dürr     // convert quartz units to pixel units
213e26449d3SHerbert Dürr     // please see the comment in AquaSalGraphics::SetFont() for details
214e26449d3SHerbert Dürr     const double fPixelSize = (mfFontScale * fDPIY * fPointSize);
215e26449d3SHerbert Dürr     rMetric.mnAscent       = static_cast<long>(+aMetrics.ascent  * fPixelSize + 0.5);
216e26449d3SHerbert Dürr     rMetric.mnDescent      = static_cast<long>(-aMetrics.descent * fPixelSize + 0.5);
217e26449d3SHerbert Dürr     const long nExtDescent = static_cast<long>((-aMetrics.descent + aMetrics.leading) * fPixelSize + 0.5);
218e26449d3SHerbert Dürr     rMetric.mnExtLeading   = nExtDescent - rMetric.mnDescent;
219e26449d3SHerbert Dürr     rMetric.mnIntLeading   = 0;
220e26449d3SHerbert Dürr     // since ImplFontMetricData::mnWidth is only used for stretching/squeezing fonts
221e26449d3SHerbert Dürr     // setting this width to the pixel height of the fontsize is good enough
222e26449d3SHerbert Dürr     // it also makes the calculation of the stretch factor simple
223e26449d3SHerbert Dürr     rMetric.mnWidth        = static_cast<long>(mfFontStretch * fPixelSize + 0.5);
224e26449d3SHerbert Dürr }
225e26449d3SHerbert Dürr 
226e26449d3SHerbert Dürr // -----------------------------------------------------------------------
227e26449d3SHerbert Dürr 
SetTextColor(const RGBAColor & rColor)228e26449d3SHerbert Dürr void AtsTextStyle::SetTextColor( const RGBAColor& rColor )
229e26449d3SHerbert Dürr {
230e26449d3SHerbert Dürr     RGBColor aAtsColor;
231e26449d3SHerbert Dürr     aAtsColor.red   = (unsigned short)( rColor.GetRed()   * 65535.0 );
232e26449d3SHerbert Dürr     aAtsColor.green = (unsigned short)( rColor.GetGreen() * 65535.0 );
233e26449d3SHerbert Dürr     aAtsColor.blue  = (unsigned short)( rColor.GetColor() * 65535.0 );
234e26449d3SHerbert Dürr 
235e26449d3SHerbert Dürr     ATSUAttributeTag aTag = kATSUColorTag;
236e26449d3SHerbert Dürr     ByteCount aValueSize = sizeof( aAtsColor );
237e26449d3SHerbert Dürr     ATSUAttributeValuePtr aValue = &aAtsColor;
238e26449d3SHerbert Dürr 
239e26449d3SHerbert Dürr     /*OSStatus err =*/ ATSUSetAttributes( maATSUStyle, 1, &aTag, &aValueSize, &aValue );
240e26449d3SHerbert Dürr }
241e26449d3SHerbert Dürr 
242e26449d3SHerbert Dürr // -----------------------------------------------------------------------
243e26449d3SHerbert Dürr 
GetGlyphBoundRect(sal_GlyphId aGlyphId,Rectangle & rRect) const244e26449d3SHerbert Dürr bool AtsTextStyle::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect ) const
245e26449d3SHerbert Dürr {
246e26449d3SHerbert Dürr     ATSUStyle rATSUStyle = maATSUStyle; // TODO: handle glyph fallback
247e26449d3SHerbert Dürr     ATSGlyphID aGlyphId = aGlyphId;
248e26449d3SHerbert Dürr     ATSGlyphScreenMetrics aGlyphMetrics;
249e26449d3SHerbert Dürr     const bool bNonAntialiasedText = false;
250e26449d3SHerbert Dürr     OSStatus eStatus = ATSUGlyphGetScreenMetrics( rATSUStyle,
251e26449d3SHerbert Dürr         1, &aGlyphId, 0, FALSE, !bNonAntialiasedText, &aGlyphMetrics );
252e26449d3SHerbert Dürr     if( eStatus != noErr )
253e26449d3SHerbert Dürr         return false;
254e26449d3SHerbert Dürr 
255e26449d3SHerbert Dürr     const long nMinX = (long)(+aGlyphMetrics.topLeft.x * mfFontScale - 0.5);
256e26449d3SHerbert Dürr     const long nMaxX = (long)(aGlyphMetrics.width * mfFontScale + 0.5) + nMinX;
257e26449d3SHerbert Dürr     const long nMinY = (long)(-aGlyphMetrics.topLeft.y * mfFontScale - 0.5);
258e26449d3SHerbert Dürr     const long nMaxY = (long)(aGlyphMetrics.height * mfFontScale + 0.5) + nMinY;
259e26449d3SHerbert Dürr     rRect = Rectangle( nMinX, nMinY, nMaxX, nMaxY );
260e26449d3SHerbert Dürr     return true;
261e26449d3SHerbert Dürr }
262e26449d3SHerbert Dürr 
263e26449d3SHerbert Dürr // -----------------------------------------------------------------------
264e26449d3SHerbert Dürr 
265e26449d3SHerbert Dürr // callbacks from ATSUGlyphGetCubicPaths() fore GetGlyphOutline()
266e26449d3SHerbert Dürr struct GgoData { basegfx::B2DPolygon maPolygon; basegfx::B2DPolyPolygon* mpPolyPoly; };
267e26449d3SHerbert Dürr 
GgoLineToProc(const Float32Point * pPoint,void * pData)268e26449d3SHerbert Dürr static OSStatus GgoLineToProc( const Float32Point* pPoint, void* pData )
269e26449d3SHerbert Dürr {
270e26449d3SHerbert Dürr     basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
271e26449d3SHerbert Dürr     const basegfx::B2DPoint aB2DPoint( pPoint->x, pPoint->y );
272e26449d3SHerbert Dürr     rPolygon.append( aB2DPoint );
273e26449d3SHerbert Dürr     return noErr;
274e26449d3SHerbert Dürr }
275e26449d3SHerbert Dürr 
GgoCurveToProc(const Float32Point * pCP1,const Float32Point * pCP2,const Float32Point * pPoint,void * pData)276e26449d3SHerbert Dürr static OSStatus GgoCurveToProc( const Float32Point* pCP1, const Float32Point* pCP2,
277e26449d3SHerbert Dürr     const Float32Point* pPoint, void* pData )
278e26449d3SHerbert Dürr {
279e26449d3SHerbert Dürr     basegfx::B2DPolygon& rPolygon = static_cast<GgoData*>(pData)->maPolygon;
280e26449d3SHerbert Dürr     const sal_uInt32 nPointCount = rPolygon.count();
281e26449d3SHerbert Dürr     const basegfx::B2DPoint aB2DControlPoint1( pCP1->x, pCP1->y );
282e26449d3SHerbert Dürr     rPolygon.setNextControlPoint( nPointCount-1, aB2DControlPoint1 );
283e26449d3SHerbert Dürr     const basegfx::B2DPoint aB2DEndPoint( pPoint->x, pPoint->y );
284e26449d3SHerbert Dürr     rPolygon.append( aB2DEndPoint );
285e26449d3SHerbert Dürr     const basegfx::B2DPoint aB2DControlPoint2( pCP2->x, pCP2->y );
286e26449d3SHerbert Dürr     rPolygon.setPrevControlPoint( nPointCount, aB2DControlPoint2 );
287e26449d3SHerbert Dürr     return noErr;
288e26449d3SHerbert Dürr }
289e26449d3SHerbert Dürr 
GgoClosePathProc(void * pData)290e26449d3SHerbert Dürr static OSStatus GgoClosePathProc( void* pData )
291e26449d3SHerbert Dürr {
292e26449d3SHerbert Dürr     GgoData* pGgoData = static_cast<GgoData*>(pData);
293e26449d3SHerbert Dürr     basegfx::B2DPolygon& rPolygon = pGgoData->maPolygon;
294e26449d3SHerbert Dürr     if( rPolygon.count() > 0 )
295e26449d3SHerbert Dürr         pGgoData->mpPolyPoly->append( rPolygon );
296e26449d3SHerbert Dürr     rPolygon.clear();
297e26449d3SHerbert Dürr     return noErr;
298e26449d3SHerbert Dürr }
299e26449d3SHerbert Dürr 
GgoMoveToProc(const Float32Point * pPoint,void * pData)300e26449d3SHerbert Dürr static OSStatus GgoMoveToProc( const Float32Point* pPoint, void* pData )
301e26449d3SHerbert Dürr {
302e26449d3SHerbert Dürr     GgoClosePathProc( pData );
303e26449d3SHerbert Dürr     OSStatus eStatus = GgoLineToProc( pPoint, pData );
304e26449d3SHerbert Dürr     return eStatus;
305e26449d3SHerbert Dürr }
306e26449d3SHerbert Dürr 
GetGlyphOutline(sal_GlyphId aGlyphId,basegfx::B2DPolyPolygon & rResult) const307e26449d3SHerbert Dürr bool AtsTextStyle::GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolygon& rResult ) const
308e26449d3SHerbert Dürr {
309e26449d3SHerbert Dürr     GgoData aGgoData;
310e26449d3SHerbert Dürr     aGgoData.mpPolyPoly = &rResult;
311e26449d3SHerbert Dürr     rResult.clear();
312e26449d3SHerbert Dürr 
313e26449d3SHerbert Dürr     OSStatus eGgoStatus = noErr;
314e26449d3SHerbert Dürr     OSStatus eStatus = ATSUGlyphGetCubicPaths( maATSUStyle, aGlyphId,
315e26449d3SHerbert Dürr         GgoMoveToProc, GgoLineToProc, GgoCurveToProc, GgoClosePathProc,
316e26449d3SHerbert Dürr         &aGgoData, &eGgoStatus );
317e26449d3SHerbert Dürr     if( (eStatus != noErr) ) // TODO: why is (eGgoStatus!=noErr) when curves are involved?
318e26449d3SHerbert Dürr         return false;
319e26449d3SHerbert Dürr 
320e26449d3SHerbert Dürr     GgoClosePathProc( &aGgoData );
321e26449d3SHerbert Dürr 
322e26449d3SHerbert Dürr     // apply the font scale
323e26449d3SHerbert Dürr     if( mfFontScale != 1.0 ) {
324e26449d3SHerbert Dürr         basegfx::B2DHomMatrix aScale;
325e26449d3SHerbert Dürr         aScale.scale( +mfFontScale, +mfFontScale );
326e26449d3SHerbert Dürr         rResult.transform( aScale );
327e26449d3SHerbert Dürr     }
328e26449d3SHerbert Dürr 
329e26449d3SHerbert Dürr     return true;
330e26449d3SHerbert Dürr }
331e26449d3SHerbert Dürr 
332e26449d3SHerbert Dürr // =======================================================================
333e26449d3SHerbert Dürr 
GetDevFontAttributes(ATSUFontID nFontID,ImplDevFontAttributes & rDFA)33451747b8eSHerbert Dürr static bool GetDevFontAttributes( ATSUFontID nFontID, ImplDevFontAttributes& rDFA )
33551747b8eSHerbert Dürr {
33651747b8eSHerbert Dürr     // all ATSU fonts are device fonts that can be directly rotated
33751747b8eSHerbert Dürr     rDFA.mbOrientation = true;
33851747b8eSHerbert Dürr     rDFA.mbDevice      = true;
33951747b8eSHerbert Dürr     rDFA.mnQuality     = 0;
34051747b8eSHerbert Dürr 
34151747b8eSHerbert Dürr     // reset the attributes
34251747b8eSHerbert Dürr     rDFA.meFamily     = FAMILY_DONTKNOW;
34351747b8eSHerbert Dürr     rDFA.mePitch      = PITCH_VARIABLE;
34451747b8eSHerbert Dürr     rDFA.meWidthType  = WIDTH_NORMAL;
34551747b8eSHerbert Dürr     rDFA.meWeight     = WEIGHT_NORMAL;
34651747b8eSHerbert Dürr     rDFA.meItalic     = ITALIC_NONE;
34751747b8eSHerbert Dürr     rDFA.mbSymbolFlag = false;
34851747b8eSHerbert Dürr 
34951747b8eSHerbert Dürr     // ignore bitmap fonts
35051747b8eSHerbert Dürr     ATSFontRef rATSFontRef = FMGetATSFontRefFromFont( nFontID );
35151747b8eSHerbert Dürr     ByteCount nHeadLen = 0;
35251747b8eSHerbert Dürr     OSStatus rc = ATSFontGetTable( rATSFontRef, 0x68656164/*head*/, 0, 0, NULL, &nHeadLen );
35351747b8eSHerbert Dürr     if( (rc != noErr) || (nHeadLen <= 0) )
35451747b8eSHerbert Dürr         return false;
35551747b8eSHerbert Dürr 
35651747b8eSHerbert Dürr     // all scalable fonts on this platform are subsettable
35751747b8eSHerbert Dürr     rDFA.mbSubsettable  = true;
35851747b8eSHerbert Dürr     rDFA.mbEmbeddable   = false;
359e26449d3SHerbert Dürr     // TODO: these members are needed only for our X11 platform targets
360e26449d3SHerbert Dürr     rDFA.meAntiAlias    = ANTIALIAS_DONTKNOW;
361e26449d3SHerbert Dürr     rDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW;
36251747b8eSHerbert Dürr 
36351747b8eSHerbert Dürr     // prepare iterating over all name strings of the font
36451747b8eSHerbert Dürr     ItemCount nFontNameCount = 0;
36551747b8eSHerbert Dürr     rc = ATSUCountFontNames( nFontID, &nFontNameCount );
36651747b8eSHerbert Dürr     if( rc != noErr )
36751747b8eSHerbert Dürr         return false;
36851747b8eSHerbert Dürr     int nBestNameValue = 0;
36951747b8eSHerbert Dürr     int nBestStyleValue = 0;
37051747b8eSHerbert Dürr     FontLanguageCode eBestLangCode = 0;
37151747b8eSHerbert Dürr     const FontLanguageCode eUILangCode = Application::GetSettings().GetUILanguage();
37251747b8eSHerbert Dürr     typedef std::vector<char> NameBuffer;
37351747b8eSHerbert Dürr     NameBuffer aNameBuffer( 256 );
37451747b8eSHerbert Dürr 
37551747b8eSHerbert Dürr     // iterate over all available name strings of the font
37651747b8eSHerbert Dürr     for( ItemCount nNameIndex = 0; nNameIndex < nFontNameCount; ++nNameIndex )
37751747b8eSHerbert Dürr     {
37851747b8eSHerbert Dürr         ByteCount nNameLength = 0;
37951747b8eSHerbert Dürr 
38051747b8eSHerbert Dürr         FontNameCode     eFontNameCode;
38151747b8eSHerbert Dürr         FontPlatformCode eFontNamePlatform;
38251747b8eSHerbert Dürr         FontScriptCode   eFontNameScript;
38351747b8eSHerbert Dürr         FontLanguageCode eFontNameLanguage;
38451747b8eSHerbert Dürr         rc = ATSUGetIndFontName( nFontID, nNameIndex, 0, NULL,
38551747b8eSHerbert Dürr             &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage );
38651747b8eSHerbert Dürr         if( rc != noErr )
38751747b8eSHerbert Dürr             continue;
38851747b8eSHerbert Dürr 
38951747b8eSHerbert Dürr         // ignore non-interesting name entries
39051747b8eSHerbert Dürr         if( (eFontNameCode != kFontFamilyName)
39151747b8eSHerbert Dürr         &&  (eFontNameCode != kFontStyleName)
39251747b8eSHerbert Dürr         &&  (eFontNameCode != kFontPostscriptName) )
39351747b8eSHerbert Dürr             continue;
39451747b8eSHerbert Dürr 
39551747b8eSHerbert Dürr         // heuristic to find the most common font name
396*86e1cf34SPedro Giffuni         // preferring default language names or even better the names matching to the UI language
39751747b8eSHerbert Dürr         int nNameValue = (eFontNameLanguage==eUILangCode) ? 0 : ((eFontNameLanguage==0) ? -10 : -20);
39851747b8eSHerbert Dürr         rtl_TextEncoding eEncoding = RTL_TEXTENCODING_UNICODE;
39951747b8eSHerbert Dürr         const int nPlatformEncoding = ((int)eFontNamePlatform << 8) + (int)eFontNameScript;
40051747b8eSHerbert Dürr         switch( nPlatformEncoding )
40151747b8eSHerbert Dürr         {
40251747b8eSHerbert Dürr             case 0x000: nNameValue += 23; break;    // Unicode 1.0
40351747b8eSHerbert Dürr             case 0x001: nNameValue += 24; break;    // Unicode 1.1
40451747b8eSHerbert Dürr             case 0x002: nNameValue += 25; break;    // iso10646_1993
40551747b8eSHerbert Dürr             case 0x003: nNameValue += 26; break;    // UCS-2
40651747b8eSHerbert Dürr             case 0x301: nNameValue += 27; break;    // Win UCS-2
40751747b8eSHerbert Dürr             case 0x004:                             // UCS-4
40851747b8eSHerbert Dürr             case 0x30A: nNameValue += 0;            // Win-UCS-4
40951747b8eSHerbert Dürr                 eEncoding = RTL_TEXTENCODING_UCS4;
41051747b8eSHerbert Dürr                 break;
41151747b8eSHerbert Dürr             case 0x100: nNameValue += 21;           // Mac Roman
41251747b8eSHerbert Dürr                 eEncoding = RTL_TEXTENCODING_APPLE_ROMAN;
41351747b8eSHerbert Dürr                 break;
41451747b8eSHerbert Dürr             case 0x300: nNameValue =  0;            // Win Symbol encoded name!
41551747b8eSHerbert Dürr                 rDFA.mbSymbolFlag = true;           // (often seen for symbol fonts)
41651747b8eSHerbert Dürr                 break;
41751747b8eSHerbert Dürr             default: nNameValue = 0;                // ignore other encodings
41851747b8eSHerbert Dürr                 break;
41951747b8eSHerbert Dürr         }
42051747b8eSHerbert Dürr 
42151747b8eSHerbert Dürr         // ignore name entries with no useful encoding
42251747b8eSHerbert Dürr         if( nNameValue <= 0 )
42351747b8eSHerbert Dürr             continue;
42451747b8eSHerbert Dürr         if( nNameLength >= aNameBuffer.size() )
42551747b8eSHerbert Dürr             continue;
42651747b8eSHerbert Dürr 
42751747b8eSHerbert Dürr         // get the encoded name
42851747b8eSHerbert Dürr         aNameBuffer.reserve( nNameLength+1 ); // extra byte helps for debugging
42951747b8eSHerbert Dürr         rc = ATSUGetIndFontName( nFontID, nNameIndex, nNameLength, &aNameBuffer[0],
43051747b8eSHerbert Dürr             &nNameLength, &eFontNameCode, &eFontNamePlatform, &eFontNameScript, &eFontNameLanguage );
43151747b8eSHerbert Dürr         if( rc != noErr )
43251747b8eSHerbert Dürr             continue;
43351747b8eSHerbert Dürr 
43451747b8eSHerbert Dürr         // convert to unicode name
43551747b8eSHerbert Dürr         UniString aUtf16Name;
43651747b8eSHerbert Dürr         if( eEncoding == RTL_TEXTENCODING_UNICODE ) // we are just interested in UTF16 encoded names
43751747b8eSHerbert Dürr             aUtf16Name = UniString( (const sal_Unicode*)&aNameBuffer[0], nNameLength/2 );
43851747b8eSHerbert Dürr         else if( eEncoding == RTL_TEXTENCODING_UCS4 )
43951747b8eSHerbert Dürr             aUtf16Name = UniString(); // TODO
44051747b8eSHerbert Dürr         else // assume the non-unicode encoded names are byte encoded
44151747b8eSHerbert Dürr             aUtf16Name = UniString( &aNameBuffer[0], nNameLength, eEncoding );
44251747b8eSHerbert Dürr 
44351747b8eSHerbert Dürr         // ignore empty strings
44451747b8eSHerbert Dürr         if( aUtf16Name.Len() <= 0 )
44551747b8eSHerbert Dürr             continue;
44651747b8eSHerbert Dürr 
44751747b8eSHerbert Dürr         // handle the name depending on its namecode
44851747b8eSHerbert Dürr         switch( eFontNameCode )
44951747b8eSHerbert Dürr         {
45051747b8eSHerbert Dürr         case kFontFamilyName:
45151747b8eSHerbert Dürr             // ignore font names starting with '.'
45251747b8eSHerbert Dürr             if( aUtf16Name.GetChar(0) == '.' )
45351747b8eSHerbert Dürr                 nNameValue = 0;
45451747b8eSHerbert Dürr             else if( rDFA.maName.Len() )
45551747b8eSHerbert Dürr             {
45651747b8eSHerbert Dürr                 // even if a family name is not the one we are looking for
45751747b8eSHerbert Dürr                 // it is still useful as a font name alternative
45851747b8eSHerbert Dürr                 if( rDFA.maMapNames.Len() )
45951747b8eSHerbert Dürr                     rDFA.maMapNames += ';';
46051747b8eSHerbert Dürr                 rDFA.maMapNames += (nBestNameValue < nNameValue) ? rDFA.maName : aUtf16Name;
46151747b8eSHerbert Dürr             }
46251747b8eSHerbert Dürr             if( nBestNameValue < nNameValue )
46351747b8eSHerbert Dürr             {
46451747b8eSHerbert Dürr                 // get the best family name
46551747b8eSHerbert Dürr                 nBestNameValue = nNameValue;
46651747b8eSHerbert Dürr                 eBestLangCode = eFontNameLanguage;
46751747b8eSHerbert Dürr                 rDFA.maName = aUtf16Name;
46851747b8eSHerbert Dürr             }
46951747b8eSHerbert Dürr             break;
47051747b8eSHerbert Dürr         case kFontStyleName:
47151747b8eSHerbert Dürr             // get a style name matching to the family name
47251747b8eSHerbert Dürr             if( nBestStyleValue < nNameValue )
47351747b8eSHerbert Dürr             {
47451747b8eSHerbert Dürr                 nBestStyleValue = nNameValue;
47551747b8eSHerbert Dürr                 rDFA.maStyleName = aUtf16Name;
47651747b8eSHerbert Dürr             }
47751747b8eSHerbert Dürr             break;
47851747b8eSHerbert Dürr         case kFontPostscriptName:
47951747b8eSHerbert Dürr             // use the postscript name to get some useful info
48051747b8eSHerbert Dürr             UpdateAttributesFromPSName( aUtf16Name, rDFA );
48151747b8eSHerbert Dürr             break;
48251747b8eSHerbert Dürr         default:
48351747b8eSHerbert Dürr             // TODO: use other name entries too?
48451747b8eSHerbert Dürr             break;
48551747b8eSHerbert Dürr         }
48651747b8eSHerbert Dürr     }
48751747b8eSHerbert Dürr 
48851747b8eSHerbert Dürr     bool bRet = (rDFA.maName.Len() > 0);
48951747b8eSHerbert Dürr     return bRet;
49051747b8eSHerbert Dürr }
49151747b8eSHerbert Dürr 
49251747b8eSHerbert Dürr // =======================================================================
49351747b8eSHerbert Dürr 
GetAtsFontList(void)494e26449d3SHerbert Dürr SystemFontList* GetAtsFontList( void )
495e26449d3SHerbert Dürr {
496e26449d3SHerbert Dürr     return new AtsFontList();
497e26449d3SHerbert Dürr }
498e26449d3SHerbert Dürr 
499e26449d3SHerbert Dürr // =======================================================================
500e26449d3SHerbert Dürr 
AtsFontList()501e26449d3SHerbert Dürr AtsFontList::AtsFontList()
50251747b8eSHerbert Dürr {
50351747b8eSHerbert Dürr     // count available system fonts
50451747b8eSHerbert Dürr     ItemCount nATSUICompatibleFontsAvailable = 0;
50551747b8eSHerbert Dürr     if( ATSUFontCount(&nATSUICompatibleFontsAvailable) != noErr )
50651747b8eSHerbert Dürr         return;
50751747b8eSHerbert Dürr     if( nATSUICompatibleFontsAvailable <= 0 )
50851747b8eSHerbert Dürr         return;
50951747b8eSHerbert Dürr 
51051747b8eSHerbert Dürr     // enumerate available system fonts
51151747b8eSHerbert Dürr     typedef std::vector<ATSUFontID> AtsFontIDVector;
51251747b8eSHerbert Dürr     AtsFontIDVector aFontIDVector( nATSUICompatibleFontsAvailable );
51351747b8eSHerbert Dürr     ItemCount nFontItemsCount = 0;
51451747b8eSHerbert Dürr     if( ATSUGetFontIDs( &aFontIDVector[0], aFontIDVector.capacity(), &nFontItemsCount ) != noErr )
51551747b8eSHerbert Dürr         return;
51651747b8eSHerbert Dürr 
51751747b8eSHerbert Dürr     BOOST_ASSERT(nATSUICompatibleFontsAvailable == nFontItemsCount && "Strange I would expect them to be equal");
51851747b8eSHerbert Dürr 
51951747b8eSHerbert Dürr     // prepare use of the available fonts
52051747b8eSHerbert Dürr     AtsFontIDVector::const_iterator it = aFontIDVector.begin();
52151747b8eSHerbert Dürr     for(; it != aFontIDVector.end(); ++it )
52251747b8eSHerbert Dürr     {
52351747b8eSHerbert Dürr         const ATSUFontID nFontID = *it;
52451747b8eSHerbert Dürr         ImplDevFontAttributes aDevFontAttr;
52551747b8eSHerbert Dürr         if( !GetDevFontAttributes( nFontID, aDevFontAttr ) )
52651747b8eSHerbert Dürr             continue;
527e26449d3SHerbert Dürr         AtsFontData* pFontData = new AtsFontData( aDevFontAttr, nFontID );
52851747b8eSHerbert Dürr         maFontContainer[ nFontID ] = pFontData;
52951747b8eSHerbert Dürr     }
53051747b8eSHerbert Dürr 
53151747b8eSHerbert Dürr     InitGlyphFallbacks();
53251747b8eSHerbert Dürr }
53351747b8eSHerbert Dürr 
53451747b8eSHerbert Dürr // -----------------------------------------------------------------------
53551747b8eSHerbert Dürr 
~AtsFontList()536e26449d3SHerbert Dürr AtsFontList::~AtsFontList()
53751747b8eSHerbert Dürr {
538e26449d3SHerbert Dürr     AtsFontContainer::const_iterator it = maFontContainer.begin();
53951747b8eSHerbert Dürr     for(; it != maFontContainer.end(); ++it )
54051747b8eSHerbert Dürr         delete (*it).second;
54151747b8eSHerbert Dürr     maFontContainer.clear();
54251747b8eSHerbert Dürr 
54351747b8eSHerbert Dürr     ATSUDisposeFontFallbacks( maFontFallbacks );
54451747b8eSHerbert Dürr }
54551747b8eSHerbert Dürr 
54651747b8eSHerbert Dürr // -----------------------------------------------------------------------
54751747b8eSHerbert Dürr 
AnnounceFonts(ImplDevFontList & rFontList) const548e26449d3SHerbert Dürr void AtsFontList::AnnounceFonts( ImplDevFontList& rFontList ) const
54951747b8eSHerbert Dürr {
550e26449d3SHerbert Dürr     AtsFontContainer::const_iterator it = maFontContainer.begin();
55151747b8eSHerbert Dürr     for(; it != maFontContainer.end(); ++it )
55251747b8eSHerbert Dürr         rFontList.Add( (*it).second->Clone() );
55351747b8eSHerbert Dürr }
55451747b8eSHerbert Dürr 
55551747b8eSHerbert Dürr // -----------------------------------------------------------------------
55651747b8eSHerbert Dürr 
GetFontDataFromId(sal_IntPtr nFontId) const557e26449d3SHerbert Dürr ImplMacFontData* AtsFontList::GetFontDataFromId( sal_IntPtr nFontId ) const
558e26449d3SHerbert Dürr {
559e26449d3SHerbert Dürr     AtsFontContainer::const_iterator it = maFontContainer.find( nFontId );
560e26449d3SHerbert Dürr     if( it == maFontContainer.end() )
561e26449d3SHerbert Dürr         return NULL;
562e26449d3SHerbert Dürr     return (*it).second;
563e26449d3SHerbert Dürr }
564e26449d3SHerbert Dürr 
565e26449d3SHerbert Dürr // -----------------------------------------------------------------------
566e26449d3SHerbert Dürr 
56751747b8eSHerbert Dürr // not all fonts are suitable for glyph fallback => sort them
56851747b8eSHerbert Dürr struct GfbCompare{ bool operator()(const ImplMacFontData*, const ImplMacFontData*); };
56951747b8eSHerbert Dürr 
operator ()(const ImplMacFontData * pA,const ImplMacFontData * pB)57051747b8eSHerbert Dürr inline bool GfbCompare::operator()( const ImplMacFontData* pA, const ImplMacFontData* pB )
57151747b8eSHerbert Dürr {
57251747b8eSHerbert Dürr     // use symbol fonts only as last resort
57351747b8eSHerbert Dürr     bool bPreferA = !pA->IsSymbolFont();
57451747b8eSHerbert Dürr     bool bPreferB = !pB->IsSymbolFont();
57551747b8eSHerbert Dürr     if( bPreferA != bPreferB )
57651747b8eSHerbert Dürr         return bPreferA;
57751747b8eSHerbert Dürr     // prefer scalable fonts
57851747b8eSHerbert Dürr     bPreferA = pA->IsScalable();
57951747b8eSHerbert Dürr     bPreferB = pB->IsScalable();
58051747b8eSHerbert Dürr     if( bPreferA != bPreferB )
58151747b8eSHerbert Dürr         return bPreferA;
58251747b8eSHerbert Dürr     // prefer non-slanted fonts
58351747b8eSHerbert Dürr     bPreferA = (pA->GetSlant() == ITALIC_NONE);
58451747b8eSHerbert Dürr     bPreferB = (pB->GetSlant() == ITALIC_NONE);
58551747b8eSHerbert Dürr     if( bPreferA != bPreferB )
58651747b8eSHerbert Dürr         return bPreferA;
58751747b8eSHerbert Dürr     // prefer normal weight fonts
58851747b8eSHerbert Dürr     bPreferA = (pA->GetWeight() == WEIGHT_NORMAL);
58951747b8eSHerbert Dürr     bPreferB = (pB->GetWeight() == WEIGHT_NORMAL);
59051747b8eSHerbert Dürr     if( bPreferA != bPreferB )
59151747b8eSHerbert Dürr         return bPreferA;
59251747b8eSHerbert Dürr     // prefer normal width fonts
59351747b8eSHerbert Dürr     bPreferA = (pA->GetWidthType() == WIDTH_NORMAL);
59451747b8eSHerbert Dürr     bPreferB = (pB->GetWidthType() == WIDTH_NORMAL);
59551747b8eSHerbert Dürr     if( bPreferA != bPreferB )
59651747b8eSHerbert Dürr         return bPreferA;
59751747b8eSHerbert Dürr     return false;
59851747b8eSHerbert Dürr }
59951747b8eSHerbert Dürr 
600e26449d3SHerbert Dürr // -----------------------------------------------------------------------
601e26449d3SHerbert Dürr 
InitGlyphFallbacks()602e26449d3SHerbert Dürr void AtsFontList::InitGlyphFallbacks()
60351747b8eSHerbert Dürr {
60451747b8eSHerbert Dürr     // sort fonts for "glyph fallback"
60551747b8eSHerbert Dürr     typedef std::multiset<const ImplMacFontData*,GfbCompare> FallbackSet;
60651747b8eSHerbert Dürr     FallbackSet aFallbackSet;
607e26449d3SHerbert Dürr     AtsFontContainer::const_iterator it = maFontContainer.begin();
60851747b8eSHerbert Dürr     for(; it != maFontContainer.end(); ++it )
60951747b8eSHerbert Dürr     {
61051747b8eSHerbert Dürr         const ImplMacFontData* pIFD = (*it).second;
61151747b8eSHerbert Dürr         // TODO: subsettable/embeddable glyph fallback only for PDF export?
61251747b8eSHerbert Dürr         if( pIFD->IsSubsettable() || pIFD->IsEmbeddable() )
61351747b8eSHerbert Dürr             aFallbackSet.insert( pIFD );
61451747b8eSHerbert Dürr     }
61551747b8eSHerbert Dürr 
61651747b8eSHerbert Dürr     // tell ATSU about font preferences for "glyph fallback"
61751747b8eSHerbert Dürr     typedef std::vector<ATSUFontID> AtsFontIDVector;
61851747b8eSHerbert Dürr     AtsFontIDVector aFallbackVector;
61951747b8eSHerbert Dürr     aFallbackVector.reserve( maFontContainer.size() );
62051747b8eSHerbert Dürr     FallbackSet::const_iterator itFData = aFallbackSet.begin();
62151747b8eSHerbert Dürr     for(; itFData != aFallbackSet.end(); ++itFData )
62251747b8eSHerbert Dürr     {
62351747b8eSHerbert Dürr         const ImplMacFontData* pFontData = (*itFData);
62451747b8eSHerbert Dürr         ATSUFontID nFontID = (ATSUFontID)pFontData->GetFontId();
62551747b8eSHerbert Dürr         aFallbackVector.push_back( nFontID );
62651747b8eSHerbert Dürr     }
62751747b8eSHerbert Dürr 
62851747b8eSHerbert Dürr     ATSUCreateFontFallbacks( &maFontFallbacks );
62951747b8eSHerbert Dürr     ATSUSetObjFontFallbacks( maFontFallbacks,
63051747b8eSHerbert Dürr         aFallbackVector.size(), &aFallbackVector[0], kATSUSequentialFallbacksPreferred );
63151747b8eSHerbert Dürr }
63251747b8eSHerbert Dürr 
633e26449d3SHerbert Dürr // =======================================================================
634