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