xref: /aoo41x/main/vcl/os2/source/gdi/salgdi3.cxx (revision 9f62ea84)
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 
23 
24 #define INCL_GRE_STRINGS
25 #define INCL_GPI
26 #define INCL_DOS
27 
28 #include <string.h>
29 #include <stdlib.h>
30 #include <math.h>
31 #include <svpm.h>
32 
33 #define _SV_SALGDI3_CXX
34 #include <tools/svwin.h>
35 #include <rtl/tencinfo.h>
36 #ifndef _OSL_FILE_HXX
37 #include <osl/file.hxx>
38 #endif
39 #ifndef _OSL_THREAD_HXX
40 #include <osl/thread.hxx>
41 #endif
42 #ifndef _OSL_PROCESS_HXX
43 #include <osl/process.h>
44 #endif
45 #include <vcl/svapp.hxx>
46 #include <saldata.hxx>
47 #include <salgdi.h>
48 #include <vcl/font.hxx>
49 #include <vcl/sallayout.hxx>
50 #include <tools/poly.hxx>
51 #include <tools/debug.hxx>
52 #include <rtl/textcvt.h>
53 #include <tools/debug.hxx>
54 #include <saldata.hxx>
55 #include <salgdi.h>
56 #ifndef _SV_OUTFONT_HXX
57 #include <vcl/outfont.hxx>
58 #endif
59 #include <sallayout.h>
60 #include <tools/poly.hxx>
61 #include <basegfx/polygon/b2dpolygon.hxx>
62 #include <basegfx/polygon/b2dpolypolygon.hxx>
63 #include <basegfx/matrix/b2dhommatrix.hxx>
64 
65 #ifndef __H_FT2LIB
66 #include <wingdi.h>
67 #include <ft2lib.h>
68 #endif
69 
70 #include "sft.hxx"
71 
72 #ifdef GCP_KERN_HACK
73 #include <algorithm>
74 #endif
75 
76 using namespace vcl;
77 
78 // -----------
79 // - Inlines -
80 // -----------
81 
82 
83 inline W32FIXED FixedFromDouble( double d )
84 {
85     const long l = (long) ( d * 65536. );
86     return *(W32FIXED*) &l;
87 }
88 
89 // -----------------------------------------------------------------------
90 
91 inline int IntTimes256FromFixed(W32FIXED f)
92 {
93     int nFixedTimes256 = (f.value << 8) + ((f.fract+0x80) >> 8);
94     return nFixedTimes256;
95 }
96 
97 // -----------
98 // - Defines -
99 // -----------
100 
101 // this is a special codepage code, used to identify OS/2 symbol font.
102 #define SYMBOL_CHARSET					65400
103 
104 // =======================================================================
105 
106 UniString ImplSalGetUniString( const sal_Char* pStr, xub_StrLen nLen = STRING_LEN)
107 {
108 	return UniString( pStr, nLen, gsl_getSystemTextEncoding(),
109 					  RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT |
110 					  RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
111 					  RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT );
112 }
113 
114 // =======================================================================
115 
116 static USHORT ImplSalToCharSet( CharSet eCharSet )
117 {
118 	// !!! Fuer DBCS-Systeme muss dieser Code auskommentiert werden und 0
119 	// !!! zurueckgegeben werden, solange die DBCS-Charsets nicht
120 	// !!! durchgereicht werden
121 
122 	switch ( eCharSet )
123 	{
124 		case RTL_TEXTENCODING_IBM_437:
125 			return 437;
126 
127 		case RTL_TEXTENCODING_IBM_850:
128 			return 850;
129 
130 		case RTL_TEXTENCODING_IBM_860:
131 			return 860;
132 
133 		case RTL_TEXTENCODING_IBM_861:
134 			return 861;
135 
136 		case RTL_TEXTENCODING_IBM_863:
137 			return 863;
138 
139 		case RTL_TEXTENCODING_IBM_865:
140 			return 865;
141 		case RTL_TEXTENCODING_MS_1252:
142 			return 1004;
143 		case RTL_TEXTENCODING_SYMBOL:
144 			return 65400;
145 	}
146 
147 	return 0;
148 }
149 
150 // -----------------------------------------------------------------------
151 
152 static CharSet ImplCharSetToSal( USHORT usCodePage )
153 {
154 	switch ( usCodePage )
155 	{
156 		case 437:
157 			return RTL_TEXTENCODING_IBM_437;
158 
159 		case 850:
160 			return RTL_TEXTENCODING_IBM_850;
161 
162 		case 860:
163 			return RTL_TEXTENCODING_IBM_860;
164 
165 		case 861:
166 			return RTL_TEXTENCODING_IBM_861;
167 
168 		case 863:
169 			return RTL_TEXTENCODING_IBM_863;
170 
171 		case 865:
172 			return RTL_TEXTENCODING_IBM_865;
173 		case 1004:
174 			return RTL_TEXTENCODING_MS_1252;
175 		case 65400:
176 			return RTL_TEXTENCODING_SYMBOL;
177 	}
178 
179 	return RTL_TEXTENCODING_DONTKNOW;
180 }
181 
182 // -----------------------------------------------------------------------
183 
184 static FontFamily ImplFamilyToSal( BYTE bFamilyType )
185 {
186     switch ( bFamilyType )
187     {
188         case 4:
189             return FAMILY_DECORATIVE;
190         case 3:
191             return FAMILY_SCRIPT;
192     }
193 
194     return FAMILY_DONTKNOW;
195 }
196 
197 // -----------------------------------------------------------------------
198 
199 static FontWeight ImplWeightToSal( USHORT nWeight )
200 {
201 	// Falls sich jemand an die alte Doku gehalten hat
202 	if ( nWeight > 999 )
203 		nWeight /= 1000;
204 
205 	switch ( nWeight )
206 	{
207 		case 1:
208 			return WEIGHT_THIN;
209 
210 		case 2:
211 			return WEIGHT_ULTRALIGHT;
212 
213 		case 3:
214 			return WEIGHT_LIGHT;
215 
216 		case 4:
217 			return WEIGHT_SEMILIGHT;
218 
219 		case 5:
220 			return WEIGHT_NORMAL;
221 
222 		case 6:
223 			return WEIGHT_SEMIBOLD;
224 
225 		case 7:
226 			return WEIGHT_BOLD;
227 
228 		case 8:
229 			return WEIGHT_ULTRABOLD;
230 
231 		case 9:
232 			return WEIGHT_BLACK;
233 	}
234 
235 	return WEIGHT_DONTKNOW;
236 }
237 
238 // -----------------------------------------------------------------------
239 
240 static UniString ImpStyleNameToSal( const char* pFamilyName,
241 								   const char* pFaceName,
242 								   USHORT nLen )
243 {
244 	if ( !nLen )
245 		nLen = strlen(pFamilyName);
246 
247 	// strip FamilyName from FaceName
248 	if ( strncmp( pFamilyName, pFaceName, nLen ) == 0 )
249 	{
250 		USHORT nFaceLen = (USHORT)strlen( pFaceName+nLen );
251 		// Ist Facename laenger, schneiden wir den FamilyName ab
252 		if ( nFaceLen > 1 )
253 			return UniString( pFaceName+(nLen+1), gsl_getSystemTextEncoding());
254 		else
255 			return UniString();
256 	}
257 	else
258 		return UniString( pFaceName, gsl_getSystemTextEncoding());
259 }
260 
261 // -----------------------------------------------------------------------
262 
263 inline FontPitch ImplLogPitchToSal( BYTE fsType )
264 {
265     if ( fsType & FM_TYPE_FIXED )
266         return PITCH_FIXED;
267     else
268         return PITCH_VARIABLE;
269 }
270 
271 // -----------------------------------------------------------------------
272 
273 inline BYTE ImplPitchToWin( FontPitch ePitch )
274 {
275     if ( ePitch == PITCH_FIXED )
276         return FM_TYPE_FIXED;
277     //else if ( ePitch == PITCH_VARIABLE )
278 
279 	return 0;
280 }
281 
282 // -----------------------------------------------------------------------
283 
284 static ImplDevFontAttributes Os2Font2DevFontAttributes( const PFONTMETRICS pFontMetric)
285 {
286     ImplDevFontAttributes aDFA;
287 
288     // get font face attributes
289     aDFA.meFamily       = ImplFamilyToSal( pFontMetric->panose.bFamilyType);
290     aDFA.meWidthType    = WIDTH_DONTKNOW;
291     aDFA.meWeight       = ImplWeightToSal( pFontMetric->usWeightClass);
292     aDFA.meItalic       = (pFontMetric->fsSelection & FM_SEL_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE;
293     aDFA.mePitch        = ImplLogPitchToSal( pFontMetric->fsType );
294     aDFA.mbSymbolFlag   = (pFontMetric->usCodePage == SYMBOL_CHARSET);
295 
296 	// get the font face name
297 	// the maName field stores the font name without the style, so under OS/2
298 	// we must use the family name
299 	aDFA.maName = UniString( pFontMetric->szFamilyname, gsl_getSystemTextEncoding());
300 
301 	aDFA.maStyleName = ImpStyleNameToSal( pFontMetric->szFamilyname,
302  										  pFontMetric->szFacename,
303  										  strlen( pFontMetric->szFamilyname) );
304 
305     // get device specific font attributes
306     aDFA.mbOrientation  = (pFontMetric->fsDefn & FM_DEFN_OUTLINE) != 0;
307     aDFA.mbDevice       = (pFontMetric->fsDefn & FM_DEFN_GENERIC) ? FALSE : TRUE;
308 
309     aDFA.mbEmbeddable   = false;
310     aDFA.mbSubsettable  = false;
311     DWORD fontType = Ft2QueryFontType( 0, pFontMetric->szFamilyname);
312     if( fontType == FT2_FONTTYPE_TRUETYPE && !aDFA.mbDevice)
313 		aDFA.mbSubsettable = true;
314     // for now we can only embed Type1 fonts
315     if( fontType == FT2_FONTTYPE_TYPE1 )
316         aDFA.mbEmbeddable = true;
317 
318     // heuristics for font quality
319     // -   standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
320     // -   subsetting > embedding > none
321     aDFA.mnQuality = 0;
322     if( fontType == FT2_FONTTYPE_TRUETYPE )
323         aDFA.mnQuality += 50;
324     if( aDFA.mbSubsettable )
325         aDFA.mnQuality += 200;
326     else if( aDFA.mbEmbeddable )
327         aDFA.mnQuality += 100;
328 
329     // #i38665# prefer Type1 versions of the standard postscript fonts
330     if( aDFA.mbEmbeddable )
331     {
332         if( aDFA.maName.EqualsAscii( "AvantGarde" )
333         ||  aDFA.maName.EqualsAscii( "Bookman" )
334         ||  aDFA.maName.EqualsAscii( "Courier" )
335         ||  aDFA.maName.EqualsAscii( "Helvetica" )
336         ||  aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
337         ||  aDFA.maName.EqualsAscii( "Palatino" )
338         ||  aDFA.maName.EqualsAscii( "Symbol" )
339         ||  aDFA.maName.EqualsAscii( "Times" )
340         ||  aDFA.maName.EqualsAscii( "ZapfChancery" )
341         ||  aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
342             aDFA.mnQuality += 500;
343     }
344 
345     aDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW;
346     aDFA.meAntiAlias = ANTIALIAS_DONTKNOW;
347 
348     // TODO: add alias names
349 
350     return aDFA;
351 }
352 
353 // =======================================================================
354 
355 // -----------------------------------------------------------------------
356 
357 // =======================================================================
358 
359 ImplOs2FontData::ImplOs2FontData( PFONTMETRICS _pFontMetric,
360     int nHeight, BYTE nPitchAndFamily )
361 :	ImplFontData( Os2Font2DevFontAttributes(_pFontMetric), 0 ),
362     pFontMetric( _pFontMetric ),
363 	meOs2CharSet( _pFontMetric->usCodePage),
364     mnPitchAndFamily( nPitchAndFamily ),
365     mpFontCharSets( NULL ),
366     mpUnicodeMap( NULL ),
367     mbDisableGlyphApi( false ),
368     mbHasKoreanRange( false ),
369     mbHasCJKSupport( false ),
370     mbAliasSymbolsLow( false ),
371     mbAliasSymbolsHigh( false ),
372     mnId( 0 )
373 {
374     SetBitmapSize( 0, nHeight );
375 }
376 
377 // -----------------------------------------------------------------------
378 
379 ImplOs2FontData::~ImplOs2FontData()
380 {
381     delete[] mpFontCharSets;
382 
383     if( mpUnicodeMap )
384         mpUnicodeMap->DeReference();
385 }
386 
387 // -----------------------------------------------------------------------
388 
389 sal_IntPtr ImplOs2FontData::GetFontId() const
390 {
391     return mnId;
392 }
393 
394 // -----------------------------------------------------------------------
395 
396 void ImplOs2FontData::UpdateFromHPS( HPS hPS ) const
397 {
398     // short circuit if already initialized
399     if( mpUnicodeMap != NULL )
400         return;
401 
402     ReadCmapTable( hPS );
403     ReadOs2Table( hPS );
404 
405     // even if the font works some fonts have problems with the glyph API
406     // => the heuristic below tries to figure out which fonts have the problem
407 	DWORD	fontType = Ft2QueryFontType( 0, pFontMetric->szFacename);
408     if( fontType != FT2_FONTTYPE_TRUETYPE
409 		&& (pFontMetric->fsDefn & FM_DEFN_GENERIC) == 0)
410 		mbDisableGlyphApi = true;
411 }
412 
413 // -----------------------------------------------------------------------
414 
415 #ifdef GNG_VERT_HACK
416 bool ImplOs2FontData::HasGSUBstitutions( HPS hPS ) const
417 {
418     if( !mbGsubRead )
419         ReadGsubTable( hPS );
420     return !maGsubTable.empty();
421 }
422 
423 // -----------------------------------------------------------------------
424 
425 bool ImplOs2FontData::IsGSUBstituted( sal_Ucs cChar ) const
426 {
427     return( maGsubTable.find( cChar ) != maGsubTable.end() );
428 }
429 #endif // GNG_VERT_HACK
430 
431 // -----------------------------------------------------------------------
432 
433 const ImplFontCharMap* ImplOs2FontData::GetImplFontCharMap() const
434 {
435     return mpUnicodeMap;
436 }
437 
438 // -----------------------------------------------------------------------
439 
440 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
441 static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
442 static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
443 static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); }
444 
445 void ImplOs2FontData::ReadOs2Table( HPS hPS ) const
446 {
447     const DWORD Os2Tag = CalcTag( "OS/2" );
448     DWORD nLength = Ft2GetFontData( hPS, Os2Tag, 0, NULL, 0 );
449     if( (nLength == FT2_ERROR) || !nLength )
450         return;
451     std::vector<unsigned char> aOS2map( nLength );
452     unsigned char* pOS2map = &aOS2map[0];
453     DWORD nRC = Ft2GetFontData( hPS, Os2Tag, 0, pOS2map, nLength );
454     sal_uInt32 nVersion = GetUShort( pOS2map );
455     if ( nVersion >= 0x0001 && nLength >= 58 )
456     {
457         // We need at least version 0x0001 (TrueType rev 1.66)
458         // to have access to the needed struct members.
459         sal_uInt32 ulUnicodeRange1 = GetUInt( pOS2map + 42 );
460         sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
461         sal_uInt32 ulUnicodeRange3 = GetUInt( pOS2map + 50 );
462         sal_uInt32 ulUnicodeRange4 = GetUInt( pOS2map + 54 );
463 
464         // Check for CJK capabilities of the current font
465         mbHasCJKSupport = (ulUnicodeRange2 & 0x2fff0000)
466                         | (ulUnicodeRange3 & 0x00000001);
467         mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000)
468                         | (ulUnicodeRange2 & 0x01100000);
469     }
470 }
471 
472 
473 // -----------------------------------------------------------------------
474 
475 #ifdef GNG_VERT_HACK
476 void ImplOs2FontData::ReadGsubTable( HPS hPS ) const
477 {
478     mbGsubRead = true;
479 
480     // check the existence of a GSUB table
481     const DWORD GsubTag = CalcTag( "GSUB" );
482     DWORD nRC = Ft2GetFontData( hPS, GsubTag, 0, NULL, 0 );
483     if( (nRC == FT2_ERROR) || !nRC )
484         return;
485 
486     // TODO: directly read the GSUB table instead of going through sft
487 
488     // get raw font file data
489     DWORD nFontSize = Ft2GetFontData( hPS, 0, 0, NULL, 0 );
490     if( nFontSize == FT2_ERROR )
491         return;
492     std::vector<char> aRawFont( nFontSize+1 );
493     aRawFont[ nFontSize ] = 0;
494     DWORD nFontSize2 = Ft2GetFontData( hPS, 0, 0, (void*)&aRawFont[0], nFontSize );
495     if( nFontSize != nFontSize2 )
496         return;
497 
498     // open font file
499     sal_uInt32 nFaceNum = 0;
500     if( !aRawFont[0] )  // TTC candidate
501         nFaceNum = ~0U;  // indicate "TTC font extracts only"
502 
503     TrueTypeFont* pTTFont = NULL;
504     ::OpenTTFontBuffer( &aRawFont[0], nFontSize, nFaceNum, &pTTFont );
505     if( !pTTFont )
506         return;
507 
508     // add vertically substituted characters to list
509     static const sal_Unicode aGSUBCandidates[] = {
510         0x0020, 0x0080, // ASCII
511         0x2000, 0x2600, // misc
512         0x3000, 0x3100, // CJK punctutation
513         0x3300, 0x3400, // squared words
514         0xFF00, 0xFFF0, // halfwidth|fullwidth forms
515     0 };
516 
517     for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
518         for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
519             if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
520                 maGsubTable.insert( cChar ); // insert GSUBbed unicodes
521 
522     CloseTTFont( pTTFont );
523 
524 #if 0
525     TrueTypeFont* pTTFont = NULL;
526     ::OpenTTFont( &aRawFont[0], nFontSize, nFaceNum, &pTTFont );
527     if( !pTTFont )
528         return;
529 
530     // add vertically substituted characters to list
531     static const sal_Unicode aGSUBCandidates[] = {
532         0x0020, 0x0080, // ASCII
533         0x2000, 0x2600, // misc
534         0x3000, 0x3100, // CJK punctutation
535         0x3300, 0x3400, // squared words
536         0xFF00, 0xFFF0, // halfwidth|fullwidth forms
537     0 };
538 
539     for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
540         for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
541             if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
542                 maGsubTable.insert( cChar ); // insert GSUBbed unicodes
543 
544     CloseTTFont( pTTFont );
545 #endif
546 }
547 #endif // GNG_VERT_HACK
548 
549 // -----------------------------------------------------------------------
550 
551 void ImplOs2FontData::ReadCmapTable( HPS hPS ) const
552 {
553     CmapResult aResult;
554     aResult.mnPairCount = 0;
555     aResult.mbSymbolic  = (meOs2CharSet == SYMBOL_CHARSET);
556     aResult.mbRecoded   = true;
557 
558     // get the CMAP table from the font which is selected into the DC
559     const DWORD CmapTag = CalcTag( "cmap" );
560     DWORD nRC = Ft2GetFontData( hPS, CmapTag, 0, NULL, 0 );
561     // read the CMAP table if available
562     if( nRC != FT2_ERROR )
563     {
564         const int nLength = nRC;
565         std::vector<unsigned char> aCmap( nLength );
566         unsigned char* pCmap = &aCmap[0];
567         nRC = Ft2GetFontData( hPS, CmapTag, 0, pCmap, nLength );
568         // parse the CMAP table
569         if( nRC == nLength )
570             ParseCMAP( pCmap, nLength, aResult );
571     } else {
572 		// we need to define at least a simple charmap, otherwise this font
573 		// will be mapped to default charmap, and OOo doesn't accept the
574 		// system font to match the default charmap
575 		aResult.mnPairCount = 1;
576 		// ImplFontCharMap destructor will free this memory
577 		aResult.mpPairCodes = new sal_uInt32[ 2 * aResult.mnPairCount ];
578 		aResult.mpPairCodes[0] = 0x0020;
579 		aResult.mpPairCodes[1] = 0x00FF;
580 		aResult.mpStartGlyphs = NULL;
581 	}
582 
583     mbDisableGlyphApi |= aResult.mbRecoded;
584 
585     if( aResult.mnPairCount > 0 )
586         mpUnicodeMap = new ImplFontCharMap( aResult.mnPairCount,
587             aResult.mpPairCodes, aResult.mpStartGlyphs );
588     else
589         mpUnicodeMap = ImplFontCharMap::GetDefaultMap();
590 	mpUnicodeMap->AddReference();
591 }
592 
593 // =======================================================================
594 
595 void Os2SalGraphics::SetTextColor( SalColor nSalColor )
596 {
597 	CHARBUNDLE cb;
598 
599 	cb.lColor = RGBCOLOR( SALCOLOR_RED( nSalColor ),
600 						  SALCOLOR_GREEN( nSalColor ),
601 						  SALCOLOR_BLUE( nSalColor ) );
602 
603 	// set default color attributes
604 	Ft2SetAttrs( mhPS,
605 				 PRIM_CHAR,
606 				 CBB_COLOR,
607 				 0,
608 				 &cb );
609 }
610 
611 // -----------------------------------------------------------------------
612 
613 USHORT Os2SalGraphics::ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, int nFallbackLevel)
614 {
615 
616 #if OSL_DEBUG_LEVEL>10
617     debug_printf( "Os2SalGraphics::ImplDoSetFont\n");
618 #endif
619 
620 	ImplOs2FontData* pFontData = (ImplOs2FontData*)i_pFont->mpFontData;
621 	PFONTMETRICS 	pFontMetric = NULL;
622 	FATTRS		  	aFAttrs;
623 	BOOL		  	bOutline = FALSE;
624 	APIRET			rc;
625 
626 	memset( &aFAttrs, 0, sizeof( FATTRS ) );
627 	aFAttrs.usRecordLength = sizeof( FATTRS );
628 
629 	aFAttrs.lMaxBaselineExt = i_pFont->mnHeight;
630 	aFAttrs.lAveCharWidth	= i_pFont->mnWidth;
631 
632 	// do we have a pointer to the FONTMETRICS of the selected font? -> use it!
633 	if ( pFontData )
634 	{
635 		pFontMetric = pFontData->GetFontMetrics();
636 
637 		bOutline = (pFontMetric->fsDefn & FM_DEFN_OUTLINE) != 0;
638 
639 		// use match&registry fields to get correct match
640 		aFAttrs.lMatch	     	= pFontMetric->lMatch;
641 		aFAttrs.idRegistry 		= pFontMetric->idRegistry;
642 		aFAttrs.usCodePage 		= pFontMetric->usCodePage;
643 
644 		if ( bOutline )
645 		{
646 			aFAttrs.fsFontUse |= FATTR_FONTUSE_OUTLINE;
647 			if ( i_pFont->mnOrientation )
648 				aFAttrs.fsFontUse |= FATTR_FONTUSE_TRANSFORMABLE;
649 		}
650 		else
651 		{
652 			aFAttrs.lMaxBaselineExt = pFontMetric->lMaxBaselineExt;
653 			aFAttrs.lAveCharWidth	= pFontMetric->lAveCharWidth;
654 		}
655 
656 	}
657 
658 	// use family name for outline fonts
659     if ( mbPrinter ) {
660 		// use font face name for printers because otherwise ft2lib will fail
661 		// to select the correct font for GPI (ticket#117)
662 		strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFacename, sizeof( aFAttrs.szFacename ) );
663 	} else if ( !pFontMetric) {
664 		// use OOo name if fontmetrics not available!
665 		ByteString aName( i_pFont->maName.GetToken( 0 ), gsl_getSystemTextEncoding());
666 		strncpy( (char*)(aFAttrs.szFacename), aName.GetBuffer(), sizeof( aFAttrs.szFacename ) );
667 	} else if ( bOutline) {
668 		// use fontmetric family name for outline fonts
669 		strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFamilyname, sizeof( aFAttrs.szFacename ) );
670 	} else {
671 		// use real font face name for bitmaps (WarpSans only)
672 		strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFacename, sizeof( aFAttrs.szFacename ) );
673 	}
674 
675 	if ( i_pFont->meItalic != ITALIC_NONE )
676 		aFAttrs.fsSelection |= FATTR_SEL_ITALIC;
677 	if ( i_pFont->meWeight > WEIGHT_MEDIUM )
678 		aFAttrs.fsSelection |= FATTR_SEL_BOLD;
679 
680 #if OSL_DEBUG_LEVEL>1
681 	if (pFontMetric->szFacename[0] == 'A') {
682 		debug_printf( "Os2SalGraphics::SetFont hps %x lMatch '%d'\n", mhPS, pFontMetric->lMatch);
683 		debug_printf( "Os2SalGraphics::SetFont hps %x fontmetrics facename '%s'\n", mhPS, pFontMetric->szFacename);
684 		debug_printf( "Os2SalGraphics::SetFont hps %x fattrs facename '%s'\n", mhPS, aFAttrs.szFacename);
685 	}
686 #endif
687 
688 	Ft2DeleteSetId( mhPS, nFallbackLevel + LCID_BASE);
689 	if ( (rc=Ft2CreateLogFont( mhPS, NULL, nFallbackLevel + LCID_BASE, &aFAttrs)) == GPI_ERROR ) {
690 #if OSL_DEBUG_LEVEL>1
691 		ERRORID nLastError = WinGetLastError( GetSalData()->mhAB );
692     	debug_printf( "Os2SalGraphics::SetFont hps %x Ft2CreateLogFont failed err %x\n", mhPS, nLastError );
693 #endif
694 		return SAL_SETFONT_REMOVEANDMATCHNEW;
695 	}
696 
697 	CHARBUNDLE aBundle;
698 
699 	ULONG nAttrsDefault = 0;
700 	ULONG nAttrs = CBB_SET;
701 	aBundle.usSet = nFallbackLevel + LCID_BASE;
702 
703 	if ( bOutline )
704 	{
705 		nAttrs |= CBB_BOX;
706 		aBundle.sizfxCell.cy = MAKEFIXED( i_pFont->mnHeight, 0 );
707 
708 		if ( !i_pFont->mnWidth )
709 		{
710 			LONG nXFontRes;
711 			LONG nYFontRes;
712 			LONG nHeight;
713 
714 			// Auf die Aufloesung achten, damit das Ergebnis auch auf
715 			// Drucken mit 180*360 DPI stimmt. Ausserdem muss gerundet
716 			// werden, da auf meinem OS2 beispielsweise als
717 			// Bildschirmaufloesung 3618*3622 PixelPerMeter zurueck-
718 			// gegeben wird
719 			GetResolution( nXFontRes, nYFontRes );
720 			nHeight = i_pFont->mnHeight;
721 			nHeight *= nXFontRes;
722 			nHeight += nYFontRes/2;
723 			nHeight /= nYFontRes;
724 			aBundle.sizfxCell.cx = MAKEFIXED( nHeight, 0 );
725 		}
726 		else
727 			aBundle.sizfxCell.cx = MAKEFIXED( i_pFont->mnWidth, 0 );
728 	}
729 
730 	// set orientation for outlinefonts
731 	if ( i_pFont->mnOrientation )
732 	{
733 		if ( bOutline )
734 		{
735 			nAttrs |= CBB_ANGLE;
736 			double alpha = (double)(i_pFont->mnOrientation);
737 			alpha *= 0.0017453292;	 // *PI / 1800
738 			mnOrientationY = (long) (1000.0 * sin( alpha ));
739 			mnOrientationX = (long) (1000.0 * cos( alpha ));
740 			aBundle.ptlAngle.x = mnOrientationX;
741 			aBundle.ptlAngle.y = mnOrientationY;
742 		}
743 		else
744 		{
745 			mnOrientationX = 1;
746 			mnOrientationY = 0;
747 			nAttrs |= CBB_ANGLE;
748 			aBundle.ptlAngle.x = 1;
749 			aBundle.ptlAngle.y = 0;
750 		}
751 	}
752 	else
753 	{
754 		mnOrientationX = 1;
755 		mnOrientationY = 0;
756 		nAttrs |= CBB_ANGLE;
757 		aBundle.ptlAngle.x = 1;
758 		aBundle.ptlAngle.y = 0;
759 	}
760 
761 	rc = Ft2SetAttrs( mhPS, PRIM_CHAR, nAttrs, nAttrsDefault, &aBundle );
762 
763 #if OSL_DEBUG_LEVEL>1
764 	FONTMETRICS aOS2Metric = {0};
765 	Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
766 #endif
767 
768 	return 0;
769 }
770 
771 
772 USHORT Os2SalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel )
773 {
774 
775     // return early if there is no new font
776     if( !pFont )
777     {
778 #if 0
779         // deselect still active font
780         if( mhDefFont )
781             Ft2SetCharSet( mhPS, mhDefFont );
782         // release no longer referenced font handles
783         for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
784         {
785             if( mhFonts[i] )
786                 Ft2DeleteSetId( mhPS, mhFonts[i] );
787             mhFonts[ i ] = 0;
788         }
789 #endif
790         mhDefFont = 0;
791         return 0;
792     }
793 
794 #if OSL_DEBUG_LEVEL>10
795     debug_printf( "Os2SalGraphics::SetFont\n");
796 #endif
797 
798     DBG_ASSERT( pFont->mpFontData, "WinSalGraphics mpFontData==NULL");
799     mpOs2FontEntry[ nFallbackLevel ] = reinterpret_cast<ImplOs2FontEntry*>( pFont->mpFontEntry );
800     mpOs2FontData[ nFallbackLevel ] = static_cast<const ImplOs2FontData*>( pFont->mpFontData );
801 
802 	ImplDoSetFont( pFont, mfFontScale, nFallbackLevel);
803 
804     if( !mhDefFont )
805     {
806         // keep default font
807         mhDefFont = nFallbackLevel + LCID_BASE;
808     }
809     else
810     {
811         // release no longer referenced font handles
812         for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
813         {
814             if( mhFonts[i] )
815             {
816 #if 0
817                 Ft2DeleteSetId( mhPS, mhFonts[i] );
818 #endif
819                 mhFonts[i] = 0;
820             }
821         }
822     }
823 
824     // store new font in correct layer
825     mhFonts[ nFallbackLevel ] = nFallbackLevel + LCID_BASE;
826 
827     // now the font is live => update font face
828     if( mpOs2FontData[ nFallbackLevel ] )
829         mpOs2FontData[ nFallbackLevel ]->UpdateFromHPS( mhPS );
830 
831     if( !nFallbackLevel )
832     {
833         mbFontKernInit = TRUE;
834         if ( mpFontKernPairs )
835         {
836             delete[] mpFontKernPairs;
837             mpFontKernPairs = NULL;
838         }
839         mnFontKernPairCount = 0;
840     }
841 
842     // some printers have higher internal resolution, so their
843     // text output would be different from what we calculated
844     // => suggest DrawTextArray to workaround this problem
845     if ( mbPrinter )
846         return SAL_SETFONT_USEDRAWTEXTARRAY;
847     else
848         return 0;
849 }
850 
851 // -----------------------------------------------------------------------
852 
853 void Os2SalGraphics::GetFontMetric( ImplFontMetricData* pMetric )
854 {
855 	FONTMETRICS aOS2Metric;
856 	Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
857 
858 #if OSL_DEBUG_LEVEL>1
859 	debug_printf( "Os2SalGraphics::GetFontMetric hps %x\n", mhPS);
860 	if (aOS2Metric.szFacename[0] == 'A') {
861 		debug_printf( "Os2SalGraphics::GetFontMetric hps %x fontmetrics facename '%s'\n", mhPS, aOS2Metric.szFacename);
862 		debug_printf( "Os2SalGraphics::GetFontMetric hps %x fontmetrics lMatch '%d'\n", mhPS, aOS2Metric.lMatch);
863 	}
864 #endif
865 
866 	pMetric->maName 			= UniString( aOS2Metric.szFamilyname, gsl_getSystemTextEncoding());
867 	pMetric->maStyleName		= ImpStyleNameToSal( aOS2Metric.szFamilyname,
868 													 aOS2Metric.szFacename,
869 													 strlen( aOS2Metric.szFamilyname ) );
870 
871     // device independent font attributes
872     pMetric->meFamily       = ImplFamilyToSal( aOS2Metric.panose.bFamilyType);
873     pMetric->mbSymbolFlag   = (aOS2Metric.usCodePage == SYMBOL_CHARSET);
874     pMetric->meWeight       = ImplWeightToSal( aOS2Metric.usWeightClass );
875     pMetric->mePitch        = ImplLogPitchToSal( aOS2Metric.fsType );
876     pMetric->meItalic       = (aOS2Metric.fsSelection & FM_SEL_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE;
877     pMetric->mnSlant        = 0;
878 
879     // device dependend font attributes
880     pMetric->mbDevice       = (aOS2Metric.fsDefn & FM_DEFN_GENERIC) ? FALSE : TRUE;
881     pMetric->mbScalableFont = (aOS2Metric.fsDefn & FM_DEFN_OUTLINE) ? true : false;
882     if( pMetric->mbScalableFont )
883     {
884         // check if there are kern pairs
885         // TODO: does this work with GPOS kerning?
886         pMetric->mbKernableFont = (aOS2Metric.sKerningPairs > 0);
887     }
888     else
889     {
890         // bitmap fonts cannot be rotated directly
891         pMetric->mnOrientation  = 0;
892         // bitmap fonts have no kerning
893         pMetric->mbKernableFont = false;
894     }
895 
896     // transformation dependend font metrics
897 	if ( aOS2Metric.fsDefn & FM_DEFN_OUTLINE )
898 	{
899 		pMetric->mnWidth	   = aOS2Metric.lEmInc;
900 	}
901 	else
902 	{
903 		pMetric->mnWidth	   = aOS2Metric.lAveCharWidth;
904 		pMetric->mnOrientation = 0;
905 	}
906 	pMetric->mnIntLeading		= aOS2Metric.lInternalLeading;
907 	pMetric->mnExtLeading		= aOS2Metric.lExternalLeading;
908 	pMetric->mnAscent			= aOS2Metric.lMaxAscender;
909 	pMetric->mnDescent			= aOS2Metric.lMaxDescender;
910 
911     // #107888# improved metric compatibility for Asian fonts...
912     // TODO: assess workaround below for CWS >= extleading
913     // TODO: evaluate use of aWinMetric.sTypo* members for CJK
914     if( mpOs2FontData[0] && mpOs2FontData[0]->SupportsCJK() )
915     {
916         pMetric->mnIntLeading += pMetric->mnExtLeading;
917 
918         // #109280# The line height for Asian fonts is too small.
919         // Therefore we add half of the external leading to the
920         // ascent, the other half is added to the descent.
921         const long nHalfTmpExtLeading = pMetric->mnExtLeading / 2;
922         const long nOtherHalfTmpExtLeading = pMetric->mnExtLeading - nHalfTmpExtLeading;
923 
924         // #110641# external leading for Asian fonts.
925         // The factor 0.3 has been confirmed with experiments.
926         long nCJKExtLeading = static_cast<long>(0.30 * (pMetric->mnAscent + pMetric->mnDescent));
927         nCJKExtLeading -= pMetric->mnExtLeading;
928         pMetric->mnExtLeading = (nCJKExtLeading > 0) ? nCJKExtLeading : 0;
929 
930         pMetric->mnAscent   += nHalfTmpExtLeading;
931         pMetric->mnDescent  += nOtherHalfTmpExtLeading;
932 
933         // #109280# HACK korean only: increase descent for wavelines and impr
934 		// YD win9x only
935     }
936 
937 }
938 
939 // -----------------------------------------------------------------------
940 
941 ULONG Os2SalGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs )
942 {
943 	DBG_ASSERT( sizeof( KERNINGPAIRS ) == sizeof( ImplKernPairData ),
944 				"Os2SalGraphics::GetKernPairs(): KERNINGPAIRS != ImplKernPairData" );
945 
946     if ( mbFontKernInit )
947     {
948         if( mpFontKernPairs )
949         {
950             delete[] mpFontKernPairs;
951             mpFontKernPairs = NULL;
952         }
953         mnFontKernPairCount = 0;
954 
955         {
956             KERNINGPAIRS* pPairs = NULL;
957 			FONTMETRICS aOS2Metric;
958 			Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
959             int nCount = aOS2Metric.sKerningPairs;
960             if( nCount )
961             {
962 #ifdef GCP_KERN_HACK
963                 pPairs = new KERNINGPAIRS[ nCount+1 ];
964                 mpFontKernPairs = pPairs;
965                 mnFontKernPairCount = nCount;
966 				Ft2QueryKerningPairs( mhPS, nCount, (KERNINGPAIRS*)pPairs );
967 #else // GCP_KERN_HACK
968 				pPairs = (KERNINGPAIRS*)pKernPairs;
969 				nCount = (nCount < nPairs) ? nCount : nPairs;
970 				Ft2QueryKerningPairs( mhPS, nCount, (KERNINGPAIRS*)pPairs );
971                 return nCount;
972 #endif // GCP_KERN_HACK
973             }
974         }
975 
976         mbFontKernInit = FALSE;
977 
978         std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData );
979     }
980 
981     if( !pKernPairs )
982         return mnFontKernPairCount;
983     else if( mpFontKernPairs )
984     {
985         if ( nPairs < mnFontKernPairCount )
986             nPairs = mnFontKernPairCount;
987         memcpy( pKernPairs, mpFontKernPairs,
988                 nPairs*sizeof( ImplKernPairData ) );
989         return nPairs;
990     }
991 
992     return 0;
993 }
994 
995 
996 // -----------------------------------------------------------------------
997 
998 static const ImplFontCharMap* pOs2DefaultImplFontCharMap = NULL;
999 static const sal_uInt32 pOs2DefaultRangeCodes[] = {0x0020,0x00FF};
1000 
1001 const ImplFontCharMap* Os2SalGraphics::GetImplFontCharMap() const
1002 {
1003     if( !mpOs2FontData[0] )
1004         return ImplFontCharMap::GetDefaultMap();
1005     return mpOs2FontData[0]->GetImplFontCharMap();
1006 }
1007 
1008 // -----------------------------------------------------------------------
1009 
1010 bool Os2SalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
1011     const String& rFontFileURL, const String& rFontName )
1012 {
1013 #if OSL_DEBUG_LEVEL>0
1014     debug_printf("Os2SalGraphics::AddTempDevFont\n");
1015 #endif
1016     return false;
1017 }
1018 
1019 // -----------------------------------------------------------------------
1020 
1021 void Os2SalGraphics::GetDevFontList( ImplDevFontList* pList )
1022 {
1023 	PFONTMETRICS	pFontMetrics;
1024 	ULONG			nFontMetricCount;
1025 	SalData*		pSalData;
1026 
1027 #if OSL_DEBUG_LEVEL>0
1028 	debug_printf("Os2SalGraphics::GetDevFontList\n");
1029 #endif
1030 
1031 	// install OpenSymbol
1032 	HMODULE hMod;
1033 	ULONG	ObjNum, Offset, rc;
1034 	CHAR	Buff[2*_MAX_PATH];
1035 	char 	drive[_MAX_DRIVE], dir[_MAX_DIR];
1036 	char 	fname[_MAX_FNAME], ext[_MAX_EXT];
1037 	// get module handle (and name)
1038 	rc = DosQueryModFromEIP( &hMod, &ObjNum, sizeof( Buff), Buff,
1039 							&Offset, (ULONG)ImplSalGetUniString);
1040 	DosQueryModuleName(hMod, sizeof(Buff), Buff);
1041 	// replace module path with font path
1042 	char* slash = strrchr( Buff, '\\');
1043 	*slash = '\0';
1044 	slash = strrchr( Buff, '\\');
1045 	*slash = '\0';
1046 	strcat( Buff, "\\SHARE\\FONTS\\TRUETYPE\\OPENS___.TTF");
1047 	rc = GpiLoadPublicFonts( GetSalData()->mhAB, Buff);
1048 
1049 	if ( !mbPrinter )
1050 	{
1051 		// Bei Bildschirm-Devices cachen wir die Liste global, da
1052 		// dies im unabhaengigen Teil auch so gemacht wird und wir
1053 		// ansonsten auf geloeschten Systemdaten arbeiten koennten
1054 		pSalData = GetSalData();
1055 		nFontMetricCount	= pSalData->mnFontMetricCount;
1056 		pFontMetrics		= pSalData->mpFontMetrics;
1057 		// Bei Bildschirm-Devices holen wir uns die Fontliste jedesmal neu
1058 		if ( pFontMetrics )
1059 		{
1060 			delete pFontMetrics;
1061 			pFontMetrics		= NULL;
1062 			nFontMetricCount	= 0;
1063 		}
1064 	}
1065 	else
1066 	{
1067 		nFontMetricCount	= mnFontMetricCount;
1068 		pFontMetrics		= mpFontMetrics;
1069 	}
1070 
1071 	// do we have to create the cached font list first?
1072 	if ( !pFontMetrics )
1073 	{
1074 		// query the number of fonts available
1075 		LONG nTemp = 0;
1076 		nFontMetricCount = Ft2QueryFonts( mhPS,
1077 										  QF_PUBLIC | QF_PRIVATE,
1078 										  NULL, &nTemp,
1079 										  sizeof( FONTMETRICS ), NULL );
1080 
1081 		// procede only if at least one is available!
1082 		if ( nFontMetricCount )
1083 		{
1084 			// allocate memory for font list
1085 			pFontMetrics = new FONTMETRICS[nFontMetricCount];
1086 
1087 			// query font list
1088 			Ft2QueryFonts( mhPS,
1089 						   QF_PUBLIC | QF_PRIVATE,
1090 						   NULL,
1091 						   (PLONG)&nFontMetricCount,
1092 						   (LONG) sizeof( FONTMETRICS ),
1093 						   pFontMetrics );
1094 		}
1095 
1096 		if ( !mbPrinter )
1097 		{
1098 			pSalData->mnFontMetricCount 		= nFontMetricCount;
1099 			pSalData->mpFontMetrics 			= pFontMetrics;
1100 		}
1101 		else
1102 		{
1103 			mnFontMetricCount	= nFontMetricCount;
1104 			mpFontMetrics		= pFontMetrics;
1105 		}
1106 	}
1107 
1108 	// copy data from the font list
1109 	for( ULONG i = 0; i < nFontMetricCount; i++ )
1110 	{
1111 		PFONTMETRICS pFontMetric = &pFontMetrics[i];
1112 
1113 		// skip font starting with '@', this is an alias internally
1114 		// used by truetype engine.
1115 		if (pFontMetric->szFacename[0] == '@')
1116 			continue;
1117 
1118 		// skip bitmap fonts (but keep WarpSans)
1119 		if ( (pFontMetric->fsDefn & FM_DEFN_OUTLINE) == 0
1120 			&& strncmp( pFontMetric->szFacename, "WarpSans", 8) )
1121 			// Font nicht aufnehmen
1122 			continue;
1123 
1124 		// replace '-' in facename with ' ' (for ft2lib)
1125 		char* dash = pFontMetric->szFacename;
1126 		while( (dash=strchr( dash, '-')))
1127 			*dash++ = ' ';
1128 
1129 		// create new font list element
1130 		ImplOs2FontData* pData 		= new ImplOs2FontData( pFontMetric, 0, 0 );
1131 
1132 		// add font list element to font list
1133 		pList->Add( pData );
1134 
1135 	}
1136 }
1137 
1138 // ----------------------------------------------------------------------------
1139 
1140 void Os2SalGraphics::GetDevFontSubstList( OutputDevice* pOutDev )
1141 {
1142 }
1143 
1144 // -----------------------------------------------------------------------
1145 
1146 BOOL Os2SalGraphics::GetGlyphBoundRect( long nIndex, Rectangle& rRect )
1147 {
1148     // use unity matrix
1149     MAT2 aMat;
1150     aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
1151     aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
1152 
1153     UINT nGGOFlags = GGO_METRICS;
1154     if( !(nIndex & GF_ISCHAR) )
1155         nGGOFlags |= GGO_GLYPH_INDEX;
1156     nIndex &= GF_IDXMASK;
1157 
1158     GLYPHMETRICS aGM;
1159     DWORD nSize = FT2_ERROR;
1160     nSize = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags, &aGM, 0, NULL, &aMat );
1161     if( nSize == FT2_ERROR )
1162         return false;
1163 
1164     rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
1165         Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
1166     rRect.Left()    = static_cast<int>( mfFontScale * rRect.Left() );
1167     rRect.Right()   = static_cast<int>( mfFontScale * rRect.Right() );
1168     rRect.Top()     = static_cast<int>( mfFontScale * rRect.Top() );
1169     rRect.Bottom()  = static_cast<int>( mfFontScale * rRect.Bottom() );
1170     return true;
1171 }
1172 
1173 // -----------------------------------------------------------------------
1174 
1175 BOOL Os2SalGraphics::GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
1176 {
1177 #if OSL_DEBUG_LEVEL>0
1178 	debug_printf("Os2SalGraphics::GetGlyphOutline\n");
1179 #endif
1180     rB2DPolyPoly.clear();
1181 
1182     BOOL bRet = FALSE;
1183 
1184     // use unity matrix
1185     MAT2 aMat;
1186     aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
1187     aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
1188 
1189     UINT nGGOFlags = GGO_NATIVE;
1190     if( !(nIndex & GF_ISCHAR) )
1191         nGGOFlags |= GGO_GLYPH_INDEX;
1192     nIndex &= GF_IDXMASK;
1193 
1194     GLYPHMETRICS aGlyphMetrics;
1195     DWORD nSize1 = FT2_ERROR;
1196     nSize1 = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
1197 
1198     if( !nSize1 )       // blank glyphs are ok
1199         bRet = TRUE;
1200     else if( nSize1 != FT2_ERROR )
1201     {
1202         BYTE*   pData = new BYTE[ nSize1 ];
1203         ULONG   nTotalCount = 0;
1204         DWORD   nSize2;
1205         nSize2 = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags,
1206                 &aGlyphMetrics, nSize1, pData, &aMat );
1207 
1208         if( nSize1 == nSize2 )
1209         {
1210             bRet = TRUE;
1211 
1212             int     nPtSize = 512;
1213             Point*  pPoints = new Point[ nPtSize ];
1214             BYTE*   pFlags = new BYTE[ nPtSize ];
1215 
1216             TTPOLYGONHEADER* pHeader = (TTPOLYGONHEADER*)pData;
1217             while( (BYTE*)pHeader < pData+nSize2 )
1218             {
1219                 // only outline data is interesting
1220                 if( pHeader->dwType != TT_POLYGON_TYPE )
1221                     break;
1222 
1223                 // get start point; next start points are end points
1224                 // of previous segment
1225                 int nPnt = 0;
1226 
1227                 long nX = IntTimes256FromFixed( pHeader->pfxStart.x );
1228                 long nY = IntTimes256FromFixed( pHeader->pfxStart.y );
1229                 pPoints[ nPnt ] = Point( nX, nY );
1230                 pFlags[ nPnt++ ] = POLY_NORMAL;
1231 
1232                 bool bHasOfflinePoints = false;
1233                 TTPOLYCURVE* pCurve = (TTPOLYCURVE*)( pHeader + 1 );
1234                 pHeader = (TTPOLYGONHEADER*)( (BYTE*)pHeader + pHeader->cb );
1235                 while( (BYTE*)pCurve < (BYTE*)pHeader )
1236                 {
1237                     int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx;
1238                     if( nPtSize < nNeededSize )
1239                     {
1240                         Point* pOldPoints = pPoints;
1241                         BYTE* pOldFlags = pFlags;
1242                         nPtSize = 2 * nNeededSize;
1243                         pPoints = new Point[ nPtSize ];
1244                         pFlags = new BYTE[ nPtSize ];
1245                         for( int i = 0; i < nPnt; ++i )
1246                         {
1247                             pPoints[ i ] = pOldPoints[ i ];
1248                             pFlags[ i ] = pOldFlags[ i ];
1249                         }
1250                         delete[] pOldPoints;
1251                         delete[] pOldFlags;
1252                     }
1253 
1254                     int i = 0;
1255                     if( TT_PRIM_LINE == pCurve->wType )
1256                     {
1257                         while( i < pCurve->cpfx )
1258                         {
1259                             nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1260                             nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1261                             ++i;
1262                             pPoints[ nPnt ] = Point( nX, nY );
1263                             pFlags[ nPnt ] = POLY_NORMAL;
1264                             ++nPnt;
1265                         }
1266                     }
1267                     else if( TT_PRIM_QSPLINE == pCurve->wType )
1268                     {
1269                         bHasOfflinePoints = true;
1270                         while( i < pCurve->cpfx )
1271                         {
1272                             // get control point of quadratic bezier spline
1273                             nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1274                             nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1275                             ++i;
1276                             Point aControlP( nX, nY );
1277 
1278                             // calculate first cubic control point
1279                             // P0 = 1/3 * (PBeg + 2 * PQControl)
1280                             nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X();
1281                             nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y();
1282                             pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
1283                             pFlags[ nPnt+0 ] = POLY_CONTROL;
1284 
1285                             // calculate endpoint of segment
1286                             nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1287                             nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1288 
1289                             if ( i+1 >= pCurve->cpfx )
1290                             {
1291                                 // endpoint is either last point in segment => advance
1292                                 ++i;
1293                             }
1294                             else
1295                             {
1296                                 // or endpoint is the middle of two control points
1297                                 nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x );
1298                                 nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y );
1299                                 nX = (nX + 1) / 2;
1300                                 nY = (nY + 1) / 2;
1301                                 // no need to advance, because the current point
1302                                 // is the control point in next bezier spline
1303                             }
1304 
1305                             pPoints[ nPnt+2 ] = Point( nX, nY );
1306                             pFlags[ nPnt+2 ] = POLY_NORMAL;
1307 
1308                             // calculate second cubic control point
1309                             // P1 = 1/3 * (PEnd + 2 * PQControl)
1310                             nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X();
1311                             nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y();
1312                             pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
1313                             pFlags[ nPnt+1 ] = POLY_CONTROL;
1314 
1315                             nPnt += 3;
1316                         }
1317                     }
1318 
1319                     // next curve segment
1320                     pCurve = (TTPOLYCURVE*)&pCurve->apfx[ i ];
1321                 }
1322 
1323                 // end point is start point for closed contour
1324                 // disabled, because Polygon class closes the contour itself
1325                 // pPoints[nPnt++] = pPoints[0];
1326 				// #i35928#
1327 				// Added again, but add only when not yet closed
1328 				if(pPoints[nPnt - 1] != pPoints[0])
1329 				{
1330                     if( bHasOfflinePoints )
1331                         pFlags[nPnt] = pFlags[0];
1332 
1333 					pPoints[nPnt++] = pPoints[0];
1334 				}
1335 
1336                 // convert y-coordinates W32 -> VCL
1337                 for( int i = 0; i < nPnt; ++i )
1338                     pPoints[i].Y() = -pPoints[i].Y();
1339 
1340                 // insert into polypolygon
1341                 Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : NULL) );
1342                 // convert to B2DPolyPolygon
1343                 // TODO: get rid of the intermediate PolyPolygon
1344                 rB2DPolyPoly.append( aPoly.getB2DPolygon() );
1345             }
1346 
1347             delete[] pPoints;
1348             delete[] pFlags;
1349         }
1350 
1351         delete[] pData;
1352     }
1353 
1354     // rescaling needed for the PolyPolygon conversion
1355     if( rB2DPolyPoly.count() )
1356     {
1357 		const double fFactor((1.0/256) * mfFontScale);
1358 		rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fFactor, fFactor));
1359     }
1360 
1361     return bRet;
1362 }
1363 
1364 // -----------------------------------------------------------------------
1365 
1366 // TODO:  Replace this class with boost::scoped_array
1367 class ScopedCharArray
1368 {
1369 public:
1370 	inline explicit ScopedCharArray(char * pArray): m_pArray(pArray) {}
1371 
1372 	inline ~ScopedCharArray() { delete[] m_pArray; }
1373 
1374 	inline char * get() const { return m_pArray; }
1375 
1376 private:
1377 	char * m_pArray;
1378 };
1379 
1380 class ScopedFont
1381 {
1382 public:
1383 	explicit ScopedFont(Os2SalGraphics & rData);
1384 
1385 	~ScopedFont();
1386 
1387 private:
1388 	Os2SalGraphics & m_rData;
1389 	ULONG m_hOrigFont;
1390 };
1391 
1392 ScopedFont::ScopedFont(Os2SalGraphics & rData): m_rData(rData)
1393 {
1394 #if 0
1395 	m_hOrigFont = m_rData.mhFonts[0];
1396 	m_rData.mhFonts[0] = 0; // avoid deletion of current font
1397 #endif
1398 }
1399 
1400 ScopedFont::~ScopedFont()
1401 {
1402 #if 0
1403 	if( m_hOrigFont )
1404 	{
1405 		// restore original font, destroy temporary font
1406 		HFONT hTempFont = m_rData.mhFonts[0];
1407 		m_rData.mhFonts[0] = m_hOrigFont;
1408 		SelectObject( m_rData.mhDC, m_hOrigFont );
1409 		DeleteObject( hTempFont );
1410 	}
1411 #endif
1412 }
1413 
1414 class ScopedTrueTypeFont
1415 {
1416 public:
1417 	inline ScopedTrueTypeFont(): m_pFont(0) {}
1418 
1419 	~ScopedTrueTypeFont();
1420 
1421 	int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum);
1422 
1423 	inline TrueTypeFont * get() const { return m_pFont; }
1424 
1425 private:
1426 	TrueTypeFont * m_pFont;
1427 };
1428 
1429 ScopedTrueTypeFont::~ScopedTrueTypeFont()
1430 {
1431 	if (m_pFont != 0)
1432 		CloseTTFont(m_pFont);
1433 }
1434 
1435 int ScopedTrueTypeFont::open(void * pBuffer, sal_uInt32 nLen,
1436 							 sal_uInt32 nFaceNum)
1437 {
1438 	OSL_ENSURE(m_pFont == 0, "already open");
1439     return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont);
1440 }
1441 
1442 BOOL Os2SalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
1443 	const ImplFontData* pFont, long* pGlyphIDs, sal_uInt8* pEncoding,
1444 	sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
1445 {
1446 	// create matching ImplFontSelectData
1447 	// we need just enough to get to the font file data
1448 	// use height=1000 for easier debugging (to match psprint's font units)
1449 	ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1450 
1451 	// TODO: much better solution: move SetFont and restoration of old font to caller
1452 	ScopedFont aOldFont(*this);
1453 	SetFont( &aIFSD, 0 );
1454 
1455 #if OSL_DEBUG_LEVEL > 100
1456 	// get font metrics
1457 	TEXTMETRICA aWinMetric;
1458 	if( !::GetTextMetricsA( mhDC, &aWinMetric ) )
1459 		return FALSE;
1460 
1461 	DBG_ASSERT( !(aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "cannot subset device font" );
1462 	DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" );
1463 #endif
1464 
1465 	// get raw font file data
1466 	DWORD nFontSize1 = Ft2GetFontData( mhPS, 0, 0, NULL, 0 );
1467 	if( nFontSize1 == FT2_ERROR )
1468 		return FALSE;
1469 	ScopedCharArray xRawFontData(new char[ nFontSize1 ]);
1470 	DWORD nFontSize2 = Ft2GetFontData( mhPS, 0, 0, (void*)xRawFontData.get(), nFontSize1 );
1471 	if( nFontSize1 != nFontSize2 )
1472 		return FALSE;
1473 
1474 	// open font file
1475 	sal_uInt32 nFaceNum = 0;
1476 	if( !*xRawFontData.get() )	// TTC candidate
1477 		nFaceNum = ~0U;	 // indicate "TTC font extracts only"
1478 
1479 	ScopedTrueTypeFont aSftTTF;
1480 	int nRC = aSftTTF.open( xRawFontData.get(), nFontSize1, nFaceNum );
1481 	if( nRC != SF_OK )
1482 		return FALSE;
1483 
1484 	TTGlobalFontInfo aTTInfo;
1485 	::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
1486 	rInfo.m_nFontType	= SAL_FONTSUBSETINFO_TYPE_TRUETYPE;
1487 	rInfo.m_aPSName		= ImplSalGetUniString( aTTInfo.psname );
1488 	rInfo.m_nAscent		= +aTTInfo.winAscent;
1489 	rInfo.m_nDescent	= -aTTInfo.winDescent;
1490 	rInfo.m_aFontBBox	= Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
1491 									Point( aTTInfo.xMax, aTTInfo.yMax ) );
1492 	rInfo.m_nCapHeight	= aTTInfo.yMax; // Well ...
1493 
1494 	// subset glyphs and get their properties
1495 	// take care that subset fonts require the NotDef glyph in pos 0
1496 	int nOrigCount = nGlyphCount;
1497 	USHORT	  aShortIDs[ 256 ];
1498 	sal_uInt8 aTempEncs[ 256 ];
1499 
1500 	int nNotDef=-1, i;
1501 	for( i = 0; i < nGlyphCount; ++i )
1502 	{
1503 		aTempEncs[i] = pEncoding[i];
1504 		sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
1505 		if( pGlyphIDs[i] & GF_ISCHAR )
1506 		{
1507 			bool bVertical = (pGlyphIDs[i] & GF_ROTMASK) != 0;
1508 			nGlyphIdx = ::MapChar( aSftTTF.get(), sal::static_int_cast<sal_uInt16>(nGlyphIdx), bVertical );
1509 			if( nGlyphIdx == 0 && pFont->IsSymbolFont() )
1510 			{
1511 				// #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
1512 				nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
1513 				nGlyphIdx = (nGlyphIdx & 0xF000) ? (nGlyphIdx & 0x00FF) : (nGlyphIdx | 0xF000 );
1514 				nGlyphIdx = ::MapChar( aSftTTF.get(), sal::static_int_cast<sal_uInt16>(nGlyphIdx), bVertical );
1515 			}
1516 		}
1517 		aShortIDs[i] = static_cast<USHORT>( nGlyphIdx );
1518 		if( !nGlyphIdx )
1519 			if( nNotDef < 0 )
1520 				nNotDef = i; // first NotDef glyph found
1521 	}
1522 
1523 	if( nNotDef != 0 )
1524 	{
1525 		// add fake NotDef glyph if needed
1526 		if( nNotDef < 0 )
1527 			nNotDef = nGlyphCount++;
1528 
1529 		// NotDef glyph must be in pos 0 => swap glyphids
1530 		aShortIDs[ nNotDef ] = aShortIDs[0];
1531 		aTempEncs[ nNotDef ] = aTempEncs[0];
1532 		aShortIDs[0] = 0;
1533 		aTempEncs[0] = 0;
1534 	}
1535 	DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
1536 
1537 	// fill pWidth array
1538 	TTSimpleGlyphMetrics* pMetrics =
1539 		::GetTTSimpleGlyphMetrics( aSftTTF.get(), aShortIDs, nGlyphCount, aIFSD.mbVertical );
1540 	if( !pMetrics )
1541 		return FALSE;
1542 	sal_uInt16 nNotDefAdv	= pMetrics[0].adv;
1543 	pMetrics[0].adv			= pMetrics[nNotDef].adv;
1544 	pMetrics[nNotDef].adv	= nNotDefAdv;
1545 	for( i = 0; i < nOrigCount; ++i )
1546 		pGlyphWidths[i] = pMetrics[i].adv;
1547 	free( pMetrics );
1548 
1549 	// write subset into destination file
1550 	rtl::OUString aSysPath;
1551 	if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
1552 		return FALSE;
1553 	rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
1554 	ByteString aToFile( rtl::OUStringToOString( aSysPath, aThreadEncoding ) );
1555 	nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.GetBuffer(), aShortIDs,
1556 			aTempEncs, nGlyphCount, 0, NULL, 0 );
1557 	return nRC == SF_OK;
1558 }
1559 
1560 //--------------------------------------------------------------------------
1561 
1562 const void* Os2SalGraphics::GetEmbedFontData( const ImplFontData* pFont,
1563 	const sal_Ucs* pUnicodes, sal_Int32* pCharWidths,
1564 	FontSubsetInfo& rInfo, long* pDataLen )
1565 {
1566 	// create matching ImplFontSelectData
1567 	// we need just enough to get to the font file data
1568 	ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1569 
1570 	// TODO: much better solution: move SetFont and restoration of old font to caller
1571 	ScopedFont aOldFont(*this);
1572 	SetFont( &aIFSD, 0 );
1573 
1574 	// get the raw font file data
1575 	DWORD nFontSize1 = Ft2GetFontData( mhPS, 0, 0, NULL, 0 );
1576 	if( nFontSize1 == FT2_ERROR || nFontSize1 <= 0 )
1577 	return NULL;
1578 	*pDataLen = nFontSize1;
1579 	void* pData = reinterpret_cast<void*>(new char[ nFontSize1 ]);
1580 	DWORD nFontSize2 = Ft2GetFontData( mhPS, 0, 0, pData, nFontSize1 );
1581 	if( nFontSize1 != nFontSize2 )
1582 		*pDataLen = 0;
1583 
1584 	// get important font properties
1585 	FONTMETRICS aOS2Metric;
1586 	if (Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric ) == GPI_ERROR)
1587 			*pDataLen = 0;
1588 	rInfo.m_nFontType	= SAL_FONTSUBSETINFO_TYPE_TYPE1;
1589 	rInfo.m_aPSName		= ImplSalGetUniString( aOS2Metric.szFacename );
1590 	rInfo.m_nAscent		= +aOS2Metric.lMaxAscender;
1591 	rInfo.m_nDescent	= -aOS2Metric.lMaxDescender;
1592 	rInfo.m_aFontBBox	= Rectangle( Point( 0, -aOS2Metric.lMaxDescender ),
1593 			  Point( aOS2Metric.lMaxCharInc, aOS2Metric.lMaxAscender+aOS2Metric.lExternalLeading ) );
1594 	rInfo.m_nCapHeight	= aOS2Metric.lMaxAscender; // Well ...
1595 
1596 	// get individual character widths
1597 	for( int i = 0; i < 256; ++i )
1598 	{
1599 		LONG nCharWidth = 0;
1600 		const sal_Ucs cChar = pUnicodes[i];
1601 		if( !Ft2QueryStringWidthW( mhPS, (LPWSTR)&cChar, 1, &nCharWidth ) )
1602 			*pDataLen = 0;
1603 		pCharWidths[i] = nCharWidth;
1604 	}
1605 
1606 	if( !*pDataLen )
1607 	{
1608 		FreeEmbedFontData( pData, nFontSize1 );
1609 		pData = NULL;
1610 	}
1611 
1612 	return pData;
1613 }
1614 
1615 //--------------------------------------------------------------------------
1616 
1617 void Os2SalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ )
1618 {
1619 	delete[] reinterpret_cast<char*>(const_cast<void*>(pData));
1620 }
1621 
1622 const Ucs2SIntMap* Os2SalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
1623 {
1624 	// TODO: even for builtin fonts we get here... why?
1625 	if( !pFont->IsEmbeddable() )
1626 		return NULL;
1627 
1628 	// fill the encoding vector
1629 	Ucs2SIntMap& rMap = *new Ucs2SIntMap;
1630 #if 0
1631 	// TODO: get correct encoding vector
1632 	ImplWinFontData* pWinFontData = reinterpret_cast<ImplWinFontData*>(pFont);
1633 
1634 	GLYPHSET aGlyphSet;
1635 	aGlyphSet.cbThis = sizeof(aGlyphSet);
1636 	DWORD aW = ::GetFontUnicodeRanges( mhDC, &aGlyphSet);
1637 #else
1638 	for( sal_Unicode i = 32; i < 256; ++i )
1639 		rMap[i] = i;
1640 	if( pNonEncoded )
1641 		*pNonEncoded = NULL;
1642 #endif
1643 
1644 	return &rMap;
1645 }
1646 
1647 //--------------------------------------------------------------------------
1648 
1649 void Os2SalGraphics::GetGlyphWidths( const ImplFontData* pFont,
1650                                      bool bVertical,
1651                                      Int32Vector& rWidths,
1652                                      Ucs2UIntMap& rUnicodeEnc )
1653 {
1654     // create matching ImplFontSelectData
1655     // we need just enough to get to the font file data
1656     ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1657 
1658     // TODO: much better solution: move SetFont and restoration of old font to caller
1659     ScopedFont aOldFont(*this);
1660 
1661     float fScale = 0.0;
1662     ImplDoSetFont( &aIFSD, fScale, 0);
1663 
1664     if( pFont->IsSubsettable() )
1665     {
1666         // get raw font file data
1667         DWORD nFontSize1 = ::Ft2GetFontData( mhPS, 0, 0, NULL, 0 );
1668         if( nFontSize1 == FT2_ERROR )
1669             return;
1670         ScopedCharArray xRawFontData(new char[ nFontSize1 ]);
1671         DWORD nFontSize2 = ::Ft2GetFontData( mhPS, 0, 0, (void*)xRawFontData.get(), nFontSize1 );
1672         if( nFontSize1 != nFontSize2 )
1673             return;
1674 
1675         // open font file
1676         sal_uInt32 nFaceNum = 0;
1677         if( !*xRawFontData.get() )  // TTC candidate
1678             nFaceNum = ~0U;  // indicate "TTC font extracts only"
1679 
1680         ScopedTrueTypeFont aSftTTF;
1681         int nRC = aSftTTF.open( xRawFontData.get(), nFontSize1, nFaceNum );
1682         if( nRC != SF_OK )
1683             return;
1684 
1685         int nGlyphs = GetTTGlyphCount( aSftTTF.get() );
1686         if( nGlyphs > 0 )
1687         {
1688             rWidths.resize(nGlyphs);
1689             std::vector<sal_uInt16> aGlyphIds(nGlyphs);
1690             for( int i = 0; i < nGlyphs; i++ )
1691                 aGlyphIds[i] = sal_uInt16(i);
1692             TTSimpleGlyphMetrics* pMetrics = ::GetTTSimpleGlyphMetrics( aSftTTF.get(),
1693                                                                         &aGlyphIds[0],
1694                                                                         nGlyphs,
1695                                                                         bVertical ? 1 : 0 );
1696             if( pMetrics )
1697             {
1698                 for( int i = 0; i< nGlyphs; i++ )
1699                     rWidths[i] = pMetrics[i].adv;
1700                 free( pMetrics );
1701                 rUnicodeEnc.clear();
1702             }
1703             const ImplOs2FontData* pWinFont = static_cast<const ImplOs2FontData*>(pFont);
1704             const ImplFontCharMap* pMap = pWinFont->GetImplFontCharMap();
1705 			DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" );
1706 
1707 			int nCharCount = pMap->GetCharCount();
1708             sal_uInt32 nChar = pMap->GetFirstChar();
1709 			for( int i = 0; i < nCharCount; i++ )
1710             {
1711                 if( nChar < 0x00010000 )
1712                 {
1713                     sal_uInt16 nGlyph = ::MapChar( aSftTTF.get(),
1714                                                    static_cast<sal_uInt16>(nChar),
1715                                                    bVertical ? 1 : 0 );
1716                     if( nGlyph )
1717                         rUnicodeEnc[ static_cast<sal_Unicode>(nChar) ] = nGlyph;
1718                 }
1719 				nChar = pMap->GetNextChar( nChar );
1720             }
1721         }
1722     }
1723     else if( pFont->IsEmbeddable() )
1724     {
1725         // get individual character widths
1726         rWidths.clear();
1727         rUnicodeEnc.clear();
1728         rWidths.reserve( 224 );
1729         for( sal_Unicode i = 32; i < 256; ++i )
1730         {
1731             int nCharWidth = 0;
1732             if( Ft2QueryStringWidthW( mhPS, (LPWSTR)&i, 1, (LONG*)&nCharWidth ) )
1733             {
1734                 rUnicodeEnc[ i ] = rWidths.size();
1735                 rWidths.push_back( nCharWidth );
1736             }
1737         }
1738     }
1739 }
1740 
1741 //--------------------------------------------------------------------------
1742 
1743 void Os2SalGraphics::DrawServerFontLayout( const ServerFontLayout& )
1744 {}
1745 
1746 //--------------------------------------------------------------------------
1747 
1748 SystemFontData Os2SalGraphics::GetSysFontData( int nFallbacklevel ) const
1749 {
1750     SystemFontData aSysFontData;
1751 
1752     if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
1753     if (nFallbacklevel < 0 ) nFallbacklevel = 0;
1754 
1755     aSysFontData.nSize = sizeof( SystemFontData );
1756     aSysFontData.hFont = mhFonts[nFallbacklevel];
1757     aSysFontData.bFakeBold = false;
1758     aSysFontData.bFakeItalic = false;
1759     aSysFontData.bAntialias = true;
1760     aSysFontData.bVerticalCharacterType = false;
1761 
1762     return aSysFontData;
1763 }
1764 
1765 //--------------------------------------------------------------------------
1766