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