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