xref: /trunk/main/vcl/os2/source/gdi/salgdi3.cxx (revision 3e2b3359)
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     mpUnicodeMap->AddReference();
605 }
606 
607 // =======================================================================
608 
609 void Os2SalGraphics::SetTextColor( SalColor nSalColor )
610 {
611 	CHARBUNDLE cb;
612 
613 	cb.lColor = MAKE_SALCOLOR( SALCOLOR_RED( nSalColor ),
614 						  SALCOLOR_GREEN( nSalColor ),
615 						  SALCOLOR_BLUE( nSalColor ) );
616 
617 	// set default color attributes
618 	Ft2SetAttrs( mhPS,
619 				 PRIM_CHAR,
620 				 CBB_COLOR,
621 				 0,
622 				 &cb );
623 }
624 
625 // -----------------------------------------------------------------------
626 
627 USHORT Os2SalGraphics::ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, int nFallbackLevel)
628 {
629 
630 #if OSL_DEBUG_LEVEL>10
631     debug_printf( "Os2SalGraphics::ImplDoSetFont mbPrinter=%d\n", mbPrinter);
632 #endif
633 
634 	ImplOs2FontData* pFontData = (ImplOs2FontData*)i_pFont->mpFontData;
635 	PFONTMETRICS 	pFontMetric = NULL;
636 	FATTRS		  	aFAttrs;
637 	PM_BOOL		  	bOutline = FALSE;
638 	APIRET			rc;
639 
640 	memset( &aFAttrs, 0, sizeof( FATTRS ) );
641 	aFAttrs.usRecordLength = sizeof( FATTRS );
642 
643 	aFAttrs.lMaxBaselineExt = i_pFont->mnHeight;
644 	aFAttrs.lAveCharWidth	= i_pFont->mnWidth;
645 
646 	// do we have a pointer to the FONTMETRICS of the selected font? -> use it!
647 	if ( pFontData )
648 	{
649 		pFontMetric = pFontData->GetFontMetrics();
650 
651 		bOutline = (pFontMetric->fsDefn & FM_DEFN_OUTLINE) != 0;
652 
653 		// use match&registry fields to get correct match
654 		aFAttrs.lMatch	     	= pFontMetric->lMatch;
655 		aFAttrs.idRegistry 		= pFontMetric->idRegistry;
656 		aFAttrs.usCodePage 		= pFontMetric->usCodePage;
657 
658 		if ( bOutline )
659 		{
660 			aFAttrs.fsFontUse |= FATTR_FONTUSE_OUTLINE;
661 			if ( i_pFont->mnOrientation )
662 				aFAttrs.fsFontUse |= FATTR_FONTUSE_TRANSFORMABLE;
663 		}
664 		else
665 		{
666 			aFAttrs.lMaxBaselineExt = pFontMetric->lMaxBaselineExt;
667 			aFAttrs.lAveCharWidth	= pFontMetric->lAveCharWidth;
668 		}
669 
670 	}
671 #if OSL_DEBUG_LEVEL>1
672 	if (pFontMetric->szFacename[0] == 'D') {
673 		rc = 0; // debugger breakpoint
674 	}
675 #endif
676 
677 	// use family name for outline fonts
678     if ( mbPrinter ) {
679 		// use font face name for printers because otherwise ft2lib will fail
680 		// to select the correct font for GPI (ticket#117)
681 		strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFacename, sizeof( aFAttrs.szFacename ) );
682 	} else if ( !pFontMetric) {
683 		// use OOo name if fontmetrics not available!
684 		ByteString aName( i_pFont->maName.GetToken( 0 ), gsl_getSystemTextEncoding());
685 		strncpy( (char*)(aFAttrs.szFacename), aName.GetBuffer(), sizeof( aFAttrs.szFacename ) );
686 	} else if ( bOutline) {
687 		// use fontmetric family name for outline fonts
688 		strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFamilyname, sizeof( aFAttrs.szFacename ) );
689 	} else {
690 		// use real font face name for bitmaps (WarpSans only)
691 		strncpy( (char*)(aFAttrs.szFacename), pFontMetric->szFacename, sizeof( aFAttrs.szFacename ) );
692 	}
693 
694 	if ( i_pFont->meItalic != ITALIC_NONE )
695 		aFAttrs.fsSelection |= FATTR_SEL_ITALIC;
696 	if ( i_pFont->meWeight > WEIGHT_MEDIUM )
697 		aFAttrs.fsSelection |= FATTR_SEL_BOLD;
698 
699 #if OSL_DEBUG_LEVEL>1
700 	if (pFontMetric->szFacename[0] == 'A') {
701 		debug_printf( "Os2SalGraphics::SetFont hps %x lMatch '%d'\n", mhPS, pFontMetric->lMatch);
702 		debug_printf( "Os2SalGraphics::SetFont hps %x fontmetrics facename '%s'\n", mhPS, pFontMetric->szFacename);
703 		debug_printf( "Os2SalGraphics::SetFont hps %x fattrs facename '%s'\n", mhPS, aFAttrs.szFacename);
704 		debug_printf( "Os2SalGraphics::SetFont hps %x fattrs height '%d'\n", mhPS, aFAttrs.lMaxBaselineExt);
705 		debug_printf( "Os2SalGraphics::SetFont hps %x fattrs width '%d'\n", mhPS, aFAttrs.lAveCharWidth);
706 	}
707 #endif
708 
709 	// set default font
710 	rc = Ft2SetCharSet( mhPS, LCID_DEFAULT);
711 	// delete selected font
712 	rc = Ft2DeleteSetId( mhPS, nFallbackLevel + LCID_BASE);
713 
714 	// create new logical font
715 	if ( (rc=Ft2CreateLogFont( mhPS, NULL, nFallbackLevel + LCID_BASE, &aFAttrs)) == GPI_ERROR ) {
716 #if OSL_DEBUG_LEVEL>1
717 		ERRORID nLastError = WinGetLastError( GetSalData()->mhAB );
718     	debug_printf( "Os2SalGraphics::SetFont hps %x Ft2CreateLogFont failed err %x\n", mhPS, nLastError );
719 #endif
720 		return SAL_SETFONT_REMOVEANDMATCHNEW;
721 	}
722 
723 #if OSL_DEBUG_LEVEL>1
724 	// select new font
725 	rc = Ft2SetCharSet( mhPS, nFallbackLevel + LCID_BASE);
726 
727 	// query fontmetric of new font
728 	FONTMETRICS aOS2Metric = {0};
729 	rc = Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
730 
731 	if (pFontMetric->szFacename[0] == 'D') {
732 		debug_printf( "Os2SalGraphics::SetFont Ft2QueryFontMetrics fattrs facename '%s'\n", aOS2Metric.szFacename);
733 		debug_printf( "Os2SalGraphics::SetFont Ft2QueryFontMetrics fattrs height '%d'\n", aOS2Metric.lMaxBaselineExt);
734 		debug_printf( "Os2SalGraphics::SetFont Ft2QueryFontMetrics fattrs width '%d'\n", aOS2Metric.lAveCharWidth);
735 	}
736 #endif
737 
738 	// apply font sizing, rotation
739 	CHARBUNDLE aBundle;
740 
741 	ULONG nAttrsDefault = 0;
742 	ULONG nAttrs = CBB_SET;
743 	aBundle.usSet = nFallbackLevel + LCID_BASE;
744 
745 	if ( bOutline )
746 	{
747 		nAttrs |= CBB_BOX;
748 		aBundle.sizfxCell.cy = MAKEFIXED( i_pFont->mnHeight, 0 );
749 
750 		if ( !i_pFont->mnWidth )
751 		{
752 			LONG nXFontRes;
753 			LONG nYFontRes;
754 			LONG nHeight;
755 
756 			// Auf die Aufloesung achten, damit das Ergebnis auch auf
757 			// Drucken mit 180*360 DPI stimmt. Ausserdem muss gerundet
758 			// werden, da auf meinem OS2 beispielsweise als
759 			// Bildschirmaufloesung 3618*3622 PixelPerMeter zurueck-
760 			// gegeben wird
761 			GetResolution( nXFontRes, nYFontRes );
762 			nHeight = i_pFont->mnHeight;
763 			nHeight *= nXFontRes;
764 			nHeight += nYFontRes/2;
765 			nHeight /= nYFontRes;
766 			aBundle.sizfxCell.cx = MAKEFIXED( nHeight, 0 );
767 		}
768 		else
769 			aBundle.sizfxCell.cx = MAKEFIXED( i_pFont->mnWidth, 0 );
770 	}
771 
772 	// set orientation for outlinefonts
773 	if ( i_pFont->mnOrientation )
774 	{
775 		if ( bOutline )
776 		{
777 			nAttrs |= CBB_ANGLE;
778 			double alpha = (double)(i_pFont->mnOrientation);
779 			alpha *= 0.0017453292;	 // *PI / 1800
780 			mnOrientationY = (long) (1000.0 * sin( alpha ));
781 			mnOrientationX = (long) (1000.0 * cos( alpha ));
782 			aBundle.ptlAngle.x = mnOrientationX;
783 			aBundle.ptlAngle.y = mnOrientationY;
784 		}
785 		else
786 		{
787 			mnOrientationX = 1;
788 			mnOrientationY = 0;
789 			nAttrs |= CBB_ANGLE;
790 			aBundle.ptlAngle.x = 1;
791 			aBundle.ptlAngle.y = 0;
792 		}
793 	}
794 	else
795 	{
796 		mnOrientationX = 1;
797 		mnOrientationY = 0;
798 		nAttrs |= CBB_ANGLE;
799 		aBundle.ptlAngle.x = 1;
800 		aBundle.ptlAngle.y = 0;
801 	}
802 
803 	rc = Ft2SetAttrs( mhPS, PRIM_CHAR, nAttrs, nAttrsDefault, &aBundle );
804 
805 #if OSL_DEBUG_LEVEL>1
806 	rc = Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
807 	if (pFontMetric->szFacename[0] == 'D') {
808 		debug_printf( "Os2SalGraphics::SetFont Ft2QueryFontMetrics fattrs facename '%s'\n", aOS2Metric.szFacename);
809 		debug_printf( "Os2SalGraphics::SetFont Ft2QueryFontMetrics fattrs height '%d'\n", aOS2Metric.lMaxBaselineExt);
810 		debug_printf( "Os2SalGraphics::SetFont Ft2QueryFontMetrics fattrs width '%d'\n", aOS2Metric.lAveCharWidth);
811 	}
812 #endif
813 
814 	return 0;
815 }
816 
817 
818 USHORT Os2SalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel )
819 {
820 
821     // return early if there is no new font
822     if( !pFont )
823     {
824 #if 0
825         // deselect still active font
826         if( mhDefFont )
827             Ft2SetCharSet( mhPS, mhDefFont );
828         // release no longer referenced font handles
829         for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
830         {
831             if( mhFonts[i] )
832                 Ft2DeleteSetId( mhPS, mhFonts[i] );
833             mhFonts[ i ] = 0;
834         }
835 #endif
836         mhDefFont = 0;
837         return 0;
838     }
839 
840 #if OSL_DEBUG_LEVEL>1
841     debug_printf( "Os2SalGraphics::SetFont\n");
842 #endif
843 
844     DBG_ASSERT( pFont->mpFontData, "WinSalGraphics mpFontData==NULL");
845     mpOs2FontEntry[ nFallbackLevel ] = reinterpret_cast<ImplOs2FontEntry*>( pFont->mpFontEntry );
846     mpOs2FontData[ nFallbackLevel ] = static_cast<const ImplOs2FontData*>( pFont->mpFontData );
847 
848 	ImplDoSetFont( pFont, mfFontScale, nFallbackLevel);
849 
850     if( !mhDefFont )
851     {
852         // keep default font
853         mhDefFont = nFallbackLevel + LCID_BASE;
854     }
855     else
856     {
857         // release no longer referenced font handles
858         for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
859         {
860             if( mhFonts[i] )
861             {
862 #if 0
863                 Ft2DeleteSetId( mhPS, mhFonts[i] );
864 #endif
865                 mhFonts[i] = 0;
866             }
867         }
868     }
869 
870     // store new font in correct layer
871     mhFonts[ nFallbackLevel ] = nFallbackLevel + LCID_BASE;
872 
873     // now the font is live => update font face
874     if( mpOs2FontData[ nFallbackLevel ] )
875         mpOs2FontData[ nFallbackLevel ]->UpdateFromHPS( mhPS );
876 
877     if( !nFallbackLevel )
878     {
879         mbFontKernInit = TRUE;
880         if ( mpFontKernPairs )
881         {
882             delete[] mpFontKernPairs;
883             mpFontKernPairs = NULL;
884         }
885         mnFontKernPairCount = 0;
886     }
887 
888     // some printers have higher internal resolution, so their
889     // text output would be different from what we calculated
890     // => suggest DrawTextArray to workaround this problem
891     if ( mbPrinter )
892         return SAL_SETFONT_USEDRAWTEXTARRAY;
893     else
894         return 0;
895 }
896 
897 // -----------------------------------------------------------------------
898 
899 void Os2SalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel )
900 {
901 	FONTMETRICS aOS2Metric;
902 	Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
903 
904 	// @TODO sync , int nFallbackLevel in 340
905 
906 #if OSL_DEBUG_LEVEL>1
907 	debug_printf( "Os2SalGraphics::GetFontMetric hps %x\n", mhPS);
908 	if (aOS2Metric.szFacename[0] == 'A') {
909 		debug_printf( "Os2SalGraphics::GetFontMetric hps %x fontmetrics facename '%s'\n", mhPS, aOS2Metric.szFacename);
910 		debug_printf( "Os2SalGraphics::GetFontMetric hps %x fontmetrics lMatch '%d'\n", mhPS, aOS2Metric.lMatch);
911 	}
912 #endif
913 
914 	pMetric->maName 			= UniString( aOS2Metric.szFamilyname, gsl_getSystemTextEncoding());
915 	pMetric->maStyleName		= ImpStyleNameToSal( aOS2Metric.szFamilyname,
916 													 aOS2Metric.szFacename,
917 													 strlen( aOS2Metric.szFamilyname ) );
918 
919     // device independent font attributes
920     pMetric->meFamily       = ImplFamilyToSal( aOS2Metric.panose.bFamilyType);
921     pMetric->mbSymbolFlag   = (aOS2Metric.usCodePage == SYMBOL_CHARSET);
922     pMetric->meWeight       = ImplWeightToSal( aOS2Metric.usWeightClass );
923     pMetric->mePitch        = ImplLogPitchToSal( aOS2Metric.fsType );
924     pMetric->meItalic       = (aOS2Metric.fsSelection & FM_SEL_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE;
925     pMetric->mnSlant        = 0;
926 
927     // device dependend font attributes
928     pMetric->mbDevice       = (aOS2Metric.fsDefn & FM_DEFN_GENERIC) ? FALSE : TRUE;
929     pMetric->mbScalableFont = (aOS2Metric.fsDefn & FM_DEFN_OUTLINE) ? true : false;
930     if( pMetric->mbScalableFont )
931     {
932         // check if there are kern pairs
933         // TODO: does this work with GPOS kerning?
934         pMetric->mbKernableFont = (aOS2Metric.sKerningPairs > 0);
935     }
936     else
937     {
938         // bitmap fonts cannot be rotated directly
939         pMetric->mnOrientation  = 0;
940         // bitmap fonts have no kerning
941         pMetric->mbKernableFont = false;
942     }
943 
944     // transformation dependend font metrics
945 	if ( aOS2Metric.fsDefn & FM_DEFN_OUTLINE )
946 	{
947 		pMetric->mnWidth	   = aOS2Metric.lEmInc;
948 	}
949 	else
950 	{
951 		pMetric->mnWidth	   = aOS2Metric.lAveCharWidth;
952 		pMetric->mnOrientation = 0;
953 	}
954 	pMetric->mnIntLeading		= aOS2Metric.lInternalLeading;
955 	pMetric->mnExtLeading		= aOS2Metric.lExternalLeading;
956 	pMetric->mnAscent			= aOS2Metric.lMaxAscender;
957 	pMetric->mnDescent			= aOS2Metric.lMaxDescender;
958 
959     // #107888# improved metric compatibility for Asian fonts...
960     // TODO: assess workaround below for CWS >= extleading
961     // TODO: evaluate use of aWinMetric.sTypo* members for CJK
962     if( mpOs2FontData[0] && mpOs2FontData[0]->SupportsCJK() )
963     {
964         pMetric->mnIntLeading += pMetric->mnExtLeading;
965 
966         // #109280# The line height for Asian fonts is too small.
967         // Therefore we add half of the external leading to the
968         // ascent, the other half is added to the descent.
969         const long nHalfTmpExtLeading = pMetric->mnExtLeading / 2;
970         const long nOtherHalfTmpExtLeading = pMetric->mnExtLeading - nHalfTmpExtLeading;
971 
972         // #110641# external leading for Asian fonts.
973         // The factor 0.3 has been confirmed with experiments.
974         long nCJKExtLeading = static_cast<long>(0.30 * (pMetric->mnAscent + pMetric->mnDescent));
975         nCJKExtLeading -= pMetric->mnExtLeading;
976         pMetric->mnExtLeading = (nCJKExtLeading > 0) ? nCJKExtLeading : 0;
977 
978         pMetric->mnAscent   += nHalfTmpExtLeading;
979         pMetric->mnDescent  += nOtherHalfTmpExtLeading;
980 
981         // #109280# HACK korean only: increase descent for wavelines and impr
982 		// YD win9x only
983     }
984 
985 }
986 
987 // -----------------------------------------------------------------------
988 
989 ULONG Os2SalGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs )
990 {
991 	DBG_ASSERT( sizeof( KERNINGPAIRS ) == sizeof( ImplKernPairData ),
992 				"Os2SalGraphics::GetKernPairs(): KERNINGPAIRS != ImplKernPairData" );
993 
994     if ( mbFontKernInit )
995     {
996         if( mpFontKernPairs )
997         {
998             delete[] mpFontKernPairs;
999             mpFontKernPairs = NULL;
1000         }
1001         mnFontKernPairCount = 0;
1002 
1003         {
1004             KERNINGPAIRS* pPairs = NULL;
1005 			FONTMETRICS aOS2Metric;
1006 			Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric );
1007             int nCount = aOS2Metric.sKerningPairs;
1008             if( nCount )
1009             {
1010 #ifdef GCP_KERN_HACK
1011                 pPairs = new KERNINGPAIRS[ nCount+1 ];
1012                 mpFontKernPairs = pPairs;
1013                 mnFontKernPairCount = nCount;
1014 				Ft2QueryKerningPairs( mhPS, nCount, (KERNINGPAIRS*)pPairs );
1015 #else // GCP_KERN_HACK
1016 				pPairs = (KERNINGPAIRS*)pKernPairs;
1017 				nCount = (nCount < nPairs) ? nCount : nPairs;
1018 				Ft2QueryKerningPairs( mhPS, nCount, (KERNINGPAIRS*)pPairs );
1019                 return nCount;
1020 #endif // GCP_KERN_HACK
1021             }
1022         }
1023 
1024         mbFontKernInit = FALSE;
1025 
1026         std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData );
1027     }
1028 
1029     if( !pKernPairs )
1030         return mnFontKernPairCount;
1031     else if( mpFontKernPairs )
1032     {
1033         if ( nPairs < mnFontKernPairCount )
1034             nPairs = mnFontKernPairCount;
1035         memcpy( pKernPairs, mpFontKernPairs,
1036                 nPairs*sizeof( ImplKernPairData ) );
1037         return nPairs;
1038     }
1039 
1040     return 0;
1041 }
1042 
1043 
1044 // -----------------------------------------------------------------------
1045 
1046 static const ImplFontCharMap* pOs2DefaultImplFontCharMap = NULL;
1047 static const sal_uInt32 pOs2DefaultRangeCodes[] = {0x0020,0x00FF};
1048 
1049 const ImplFontCharMap* Os2SalGraphics::GetImplFontCharMap() const
1050 {
1051     if( !mpOs2FontData[0] )
1052         return ImplFontCharMap::GetDefaultMap();
1053     return mpOs2FontData[0]->GetImplFontCharMap();
1054 }
1055 
1056 // -----------------------------------------------------------------------
1057 
1058 bool Os2SalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
1059     const String& rFontFileURL, const String& rFontName )
1060 {
1061 #if OSL_DEBUG_LEVEL>0
1062     debug_printf("Os2SalGraphics::AddTempDevFont\n");
1063 #endif
1064     return false;
1065 }
1066 
1067 // -----------------------------------------------------------------------
1068 
1069 void Os2SalGraphics::GetDevFontList( ImplDevFontList* pList )
1070 {
1071 	PFONTMETRICS	pFontMetrics;
1072 	ULONG			nFontMetricCount;
1073 	SalData*		pSalData;
1074 
1075 #if OSL_DEBUG_LEVEL>0
1076 	debug_printf("Os2SalGraphics::GetDevFontList mbPrinter=%d\n", mbPrinter);
1077 #endif
1078 
1079 	// install OpenSymbol
1080 	HMODULE hMod;
1081 	ULONG	ObjNum, Offset, rc;
1082 	CHAR	Buff[2*_MAX_PATH];
1083 	char 	drive[_MAX_DRIVE], dir[_MAX_DIR];
1084 	char 	fname[_MAX_FNAME], ext[_MAX_EXT];
1085 	// get module handle (and name)
1086 	rc = DosQueryModFromEIP( &hMod, &ObjNum, sizeof( Buff), Buff,
1087 							&Offset, (ULONG)ImplSalGetUniString);
1088 	DosQueryModuleName(hMod, sizeof(Buff), Buff);
1089 	// replace module path with font path
1090 	char* slash = strrchr( Buff, '\\');
1091 	*slash = '\0';
1092 	slash = strrchr( Buff, '\\');
1093 	*slash = '\0';
1094 	strcat( Buff, "\\FONTS\\OPENS___.TTF");
1095 	rc = GpiLoadPublicFonts( GetSalData()->mhAB, Buff);
1096 
1097 	if ( !mbPrinter )
1098 	{
1099 		// Bei Bildschirm-Devices cachen wir die Liste global, da
1100 		// dies im unabhaengigen Teil auch so gemacht wird und wir
1101 		// ansonsten auf geloeschten Systemdaten arbeiten koennten
1102 		pSalData = GetSalData();
1103 		nFontMetricCount	= pSalData->mnFontMetricCount;
1104 		pFontMetrics		= pSalData->mpFontMetrics;
1105 		// Bei Bildschirm-Devices holen wir uns die Fontliste jedesmal neu
1106 		if ( pFontMetrics )
1107 		{
1108 			delete pFontMetrics;
1109 			pFontMetrics		= NULL;
1110 			nFontMetricCount	= 0;
1111 		}
1112 	}
1113 	else
1114 	{
1115 		nFontMetricCount	= mnFontMetricCount;
1116 		pFontMetrics		= mpFontMetrics;
1117 	}
1118 
1119 	// do we have to create the cached font list first?
1120 	if ( !pFontMetrics )
1121 	{
1122 		// query the number of fonts available
1123 		LONG nTemp = 0;
1124 		nFontMetricCount = Ft2QueryFonts( mhPS,
1125 										  QF_PUBLIC | QF_PRIVATE | QF_NO_DEVICE,
1126 										  NULL, &nTemp,
1127 										  sizeof( FONTMETRICS ), NULL );
1128 
1129 		// procede only if at least one is available!
1130 		if ( nFontMetricCount )
1131 		{
1132 			// allocate memory for font list
1133 			pFontMetrics = new FONTMETRICS[nFontMetricCount];
1134 
1135 			// query font list
1136 			Ft2QueryFonts( mhPS,
1137 						   QF_PUBLIC | QF_PRIVATE | QF_NO_DEVICE,
1138 						   NULL,
1139 						   (PLONG)&nFontMetricCount,
1140 						   (LONG) sizeof( FONTMETRICS ),
1141 						   pFontMetrics );
1142 		}
1143 
1144 		if ( !mbPrinter )
1145 		{
1146 			pSalData->mnFontMetricCount 		= nFontMetricCount;
1147 			pSalData->mpFontMetrics 			= pFontMetrics;
1148 		}
1149 		else
1150 		{
1151 			mnFontMetricCount	= nFontMetricCount;
1152 			mpFontMetrics		= pFontMetrics;
1153 		}
1154 	}
1155 
1156 	// copy data from the font list
1157 	for( ULONG i = 0; i < nFontMetricCount; i++ )
1158 	{
1159 		PFONTMETRICS pFontMetric = &pFontMetrics[i];
1160 
1161 #if OSL_DEBUG_LEVEL>2
1162 		debug_printf("Os2SalGraphics::GetDevFontList #%d,'%s'\n", i, pFontMetric->szFacename);
1163 #endif
1164 
1165 		// skip font starting with '@', this is an alias internally
1166 		// used by truetype engine.
1167 		if (pFontMetric->szFacename[0] == '@')
1168 			continue;
1169 
1170 		// skip bitmap fonts (but keep WarpSans)
1171 		if ( (pFontMetric->fsDefn & FM_DEFN_OUTLINE) == 0
1172 			&& strncmp( pFontMetric->szFacename, "WarpSans", 8) )
1173 			// Font nicht aufnehmen
1174 			continue;
1175 
1176 		// replace '-' in facename with ' ' (for ft2lib)
1177 		char* dash = pFontMetric->szFacename;
1178 		while( (dash=strchr( dash, '-')))
1179 			*dash++ = ' ';
1180 
1181 		// create new font list element
1182 		ImplOs2FontData* pData 		= new ImplOs2FontData( pFontMetric, 0, 0 );
1183 
1184 		// ticket#80: font id field is used for pdf font cache code.
1185 		pData->SetFontId( i);
1186 
1187 		// add font list element to font list
1188 		pList->Add( pData );
1189 
1190 	}
1191 }
1192 
1193 // ----------------------------------------------------------------------------
1194 
1195 void Os2SalGraphics::GetDevFontSubstList( OutputDevice* pOutDev )
1196 {
1197 }
1198 
1199 // -----------------------------------------------------------------------
1200 
1201 sal_Bool Os2SalGraphics::GetGlyphBoundRect( long nIndex, Rectangle& rRect )
1202 {
1203     // use unity matrix
1204     MAT2 aMat;
1205     aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
1206     aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
1207 
1208     UINT nGGOFlags = GGO_METRICS;
1209     if( !(nIndex & GF_ISCHAR) )
1210         nGGOFlags |= GGO_GLYPH_INDEX;
1211     nIndex &= GF_IDXMASK;
1212 
1213     GLYPHMETRICS aGM;
1214     DWORD nSize = FT2_ERROR;
1215     nSize = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags, &aGM, 0, NULL, &aMat );
1216     if( nSize == FT2_ERROR )
1217         return false;
1218 
1219     rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
1220         Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
1221     rRect.Left()    = static_cast<int>( mfFontScale * rRect.Left() );
1222     rRect.Right()   = static_cast<int>( mfFontScale * rRect.Right() );
1223     rRect.Top()     = static_cast<int>( mfFontScale * rRect.Top() );
1224     rRect.Bottom()  = static_cast<int>( mfFontScale * rRect.Bottom() );
1225     return true;
1226 }
1227 
1228 // -----------------------------------------------------------------------
1229 
1230 sal_Bool Os2SalGraphics::GetGlyphOutline( long nIndex, ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
1231 {
1232 #if OSL_DEBUG_LEVEL>0
1233 	debug_printf("Os2SalGraphics::GetGlyphOutline\n");
1234 #endif
1235     rB2DPolyPoly.clear();
1236 
1237     PM_BOOL bRet = FALSE;
1238 
1239     // use unity matrix
1240     MAT2 aMat;
1241     aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
1242     aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
1243 
1244     UINT nGGOFlags = GGO_NATIVE;
1245     if( !(nIndex & GF_ISCHAR) )
1246         nGGOFlags |= GGO_GLYPH_INDEX;
1247     nIndex &= GF_IDXMASK;
1248 
1249     GLYPHMETRICS aGlyphMetrics;
1250     DWORD nSize1 = FT2_ERROR;
1251     nSize1 = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
1252 
1253     if( !nSize1 )       // blank glyphs are ok
1254         bRet = TRUE;
1255     else if( nSize1 != FT2_ERROR )
1256     {
1257         PM_BYTE*   pData = new PM_BYTE[ nSize1 ];
1258         ULONG   nTotalCount = 0;
1259         DWORD   nSize2;
1260         nSize2 = Ft2GetGlyphOutline( mhPS, nIndex, nGGOFlags,
1261                 &aGlyphMetrics, nSize1, pData, &aMat );
1262 
1263         if( nSize1 == nSize2 )
1264         {
1265             bRet = TRUE;
1266 
1267             int     nPtSize = 512;
1268             Point*  pPoints = new Point[ nPtSize ];
1269             sal_uInt8*   pFlags = new sal_uInt8[ nPtSize ];
1270 
1271             TTPOLYGONHEADER* pHeader = (TTPOLYGONHEADER*)pData;
1272             while( (PM_BYTE*)pHeader < pData+nSize2 )
1273             {
1274                 // only outline data is interesting
1275                 if( pHeader->dwType != TT_POLYGON_TYPE )
1276                     break;
1277 
1278                 // get start point; next start points are end points
1279                 // of previous segment
1280                 int nPnt = 0;
1281 
1282                 long nX = IntTimes256FromFixed( pHeader->pfxStart.x );
1283                 long nY = IntTimes256FromFixed( pHeader->pfxStart.y );
1284                 pPoints[ nPnt ] = Point( nX, nY );
1285                 pFlags[ nPnt++ ] = POLY_NORMAL;
1286 
1287                 bool bHasOfflinePoints = false;
1288                 TTPOLYCURVE* pCurve = (TTPOLYCURVE*)( pHeader + 1 );
1289                 pHeader = (TTPOLYGONHEADER*)( (PM_BYTE*)pHeader + pHeader->cb );
1290                 while( (PM_BYTE*)pCurve < (PM_BYTE*)pHeader )
1291                 {
1292                     int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx;
1293                     if( nPtSize < nNeededSize )
1294                     {
1295                         Point* pOldPoints = pPoints;
1296                         sal_uInt8* pOldFlags = pFlags;
1297                         nPtSize = 2 * nNeededSize;
1298                         pPoints = new Point[ nPtSize ];
1299                         pFlags = new sal_uInt8[ nPtSize ];
1300                         for( int i = 0; i < nPnt; ++i )
1301                         {
1302                             pPoints[ i ] = pOldPoints[ i ];
1303                             pFlags[ i ] = pOldFlags[ i ];
1304                         }
1305                         delete[] pOldPoints;
1306                         delete[] pOldFlags;
1307                     }
1308 
1309                     int i = 0;
1310                     if( TT_PRIM_LINE == pCurve->wType )
1311                     {
1312                         while( i < pCurve->cpfx )
1313                         {
1314                             nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1315                             nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1316                             ++i;
1317                             pPoints[ nPnt ] = Point( nX, nY );
1318                             pFlags[ nPnt ] = POLY_NORMAL;
1319                             ++nPnt;
1320                         }
1321                     }
1322                     else if( TT_PRIM_QSPLINE == pCurve->wType )
1323                     {
1324                         bHasOfflinePoints = true;
1325                         while( i < pCurve->cpfx )
1326                         {
1327                             // get control point of quadratic bezier spline
1328                             nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1329                             nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1330                             ++i;
1331                             Point aControlP( nX, nY );
1332 
1333                             // calculate first cubic control point
1334                             // P0 = 1/3 * (PBeg + 2 * PQControl)
1335                             nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X();
1336                             nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y();
1337                             pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
1338                             pFlags[ nPnt+0 ] = POLY_CONTROL;
1339 
1340                             // calculate endpoint of segment
1341                             nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1342                             nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1343 
1344                             if ( i+1 >= pCurve->cpfx )
1345                             {
1346                                 // endpoint is either last point in segment => advance
1347                                 ++i;
1348                             }
1349                             else
1350                             {
1351                                 // or endpoint is the middle of two control points
1352                                 nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x );
1353                                 nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y );
1354                                 nX = (nX + 1) / 2;
1355                                 nY = (nY + 1) / 2;
1356                                 // no need to advance, because the current point
1357                                 // is the control point in next bezier spline
1358                             }
1359 
1360                             pPoints[ nPnt+2 ] = Point( nX, nY );
1361                             pFlags[ nPnt+2 ] = POLY_NORMAL;
1362 
1363                             // calculate second cubic control point
1364                             // P1 = 1/3 * (PEnd + 2 * PQControl)
1365                             nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X();
1366                             nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y();
1367                             pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
1368                             pFlags[ nPnt+1 ] = POLY_CONTROL;
1369 
1370                             nPnt += 3;
1371                         }
1372                     }
1373 
1374                     // next curve segment
1375                     pCurve = (TTPOLYCURVE*)&pCurve->apfx[ i ];
1376                 }
1377 
1378                 // end point is start point for closed contour
1379                 // disabled, because Polygon class closes the contour itself
1380                 // pPoints[nPnt++] = pPoints[0];
1381 				// #i35928#
1382 				// Added again, but add only when not yet closed
1383 				if(pPoints[nPnt - 1] != pPoints[0])
1384 				{
1385                     if( bHasOfflinePoints )
1386                         pFlags[nPnt] = pFlags[0];
1387 
1388 					pPoints[nPnt++] = pPoints[0];
1389 				}
1390 
1391                 // convert y-coordinates W32 -> VCL
1392                 for( int i = 0; i < nPnt; ++i )
1393                     pPoints[i].Y() = -pPoints[i].Y();
1394 
1395                 // insert into polypolygon
1396                 Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : NULL) );
1397                 // convert to B2DPolyPolygon
1398                 // TODO: get rid of the intermediate PolyPolygon
1399                 rB2DPolyPoly.append( aPoly.getB2DPolygon() );
1400             }
1401 
1402             delete[] pPoints;
1403             delete[] pFlags;
1404         }
1405 
1406         delete[] pData;
1407     }
1408 
1409     // rescaling needed for the PolyPolygon conversion
1410     if( rB2DPolyPoly.count() )
1411     {
1412         ::basegfx::B2DHomMatrix aMatrix;
1413         aMatrix.scale( 1.0/256, 1.0/256 );
1414         aMatrix.scale( mfFontScale, mfFontScale );
1415         rB2DPolyPoly.transform( aMatrix );
1416     }
1417 
1418     return bRet;
1419 }
1420 
1421 // -----------------------------------------------------------------------
1422 
1423 // TODO:  Replace this class with boost::scoped_array
1424 class ScopedCharArray
1425 {
1426 public:
1427 	inline explicit ScopedCharArray(char * pArray): m_pArray(pArray) {}
1428 
1429 	inline ~ScopedCharArray() { delete[] m_pArray; }
1430 
1431 	inline char * get() const { return m_pArray; }
1432 
1433 private:
1434 	char * m_pArray;
1435 };
1436 
1437 class ScopedFont
1438 {
1439 public:
1440 	explicit ScopedFont(Os2SalGraphics & rData);
1441 
1442 	~ScopedFont();
1443 
1444 private:
1445 	Os2SalGraphics & m_rData;
1446 	ULONG m_hOrigFont;
1447 };
1448 
1449 ScopedFont::ScopedFont(Os2SalGraphics & rData): m_rData(rData)
1450 {
1451 #if 0
1452 	m_hOrigFont = m_rData.mhFonts[0];
1453 	m_rData.mhFonts[0] = 0; // avoid deletion of current font
1454 #endif
1455 }
1456 
1457 ScopedFont::~ScopedFont()
1458 {
1459 #if 0
1460 	if( m_hOrigFont )
1461 	{
1462 		// restore original font, destroy temporary font
1463 		HFONT hTempFont = m_rData.mhFonts[0];
1464 		m_rData.mhFonts[0] = m_hOrigFont;
1465 		SelectObject( m_rData.mhDC, m_hOrigFont );
1466 		DeleteObject( hTempFont );
1467 	}
1468 #endif
1469 }
1470 
1471 class ScopedTrueTypeFont
1472 {
1473 public:
1474 	inline ScopedTrueTypeFont(): m_pFont(0) {}
1475 
1476 	~ScopedTrueTypeFont();
1477 
1478 	int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum);
1479 
1480 	inline TrueTypeFont * get() const { return m_pFont; }
1481 
1482 private:
1483 	TrueTypeFont * m_pFont;
1484 };
1485 
1486 ScopedTrueTypeFont::~ScopedTrueTypeFont()
1487 {
1488 	if (m_pFont != 0)
1489 		CloseTTFont(m_pFont);
1490 }
1491 
1492 int ScopedTrueTypeFont::open(void * pBuffer, sal_uInt32 nLen,
1493 							 sal_uInt32 nFaceNum)
1494 {
1495 	OSL_ENSURE(m_pFont == 0, "already open");
1496     return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont);
1497 }
1498 
1499 sal_Bool Os2SalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
1500 	const ImplFontData* pFont, long* pGlyphIDs, sal_uInt8* pEncoding,
1501 	sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
1502 {
1503 	// TODO: use more of the central font-subsetting code, move stuff there if needed
1504 
1505 	// create matching ImplFontSelectData
1506 	// we need just enough to get to the font file data
1507 	// use height=1000 for easier debugging (to match psprint's font units)
1508 	ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1509 
1510 	// TODO: much better solution: move SetFont and restoration of old font to caller
1511 	ScopedFont aOldFont(*this);
1512 	SetFont( &aIFSD, 0 );
1513 
1514     ImplOs2FontData* pWinFontData = (ImplOs2FontData*)aIFSD.mpFontData;
1515     pWinFontData->UpdateFromHPS( mhPS );
1516     const ImplFontCharMap* pImplFontCharMap = pWinFontData->GetImplFontCharMap();
1517 
1518 #if OSL_DEBUG_LEVEL > 100
1519 	// get font metrics
1520 	TEXTMETRICA aWinMetric;
1521 	if( !::GetTextMetricsA( mhDC, &aWinMetric ) )
1522 		return FALSE;
1523 
1524 	DBG_ASSERT( !(aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "cannot subset device font" );
1525 	DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" );
1526 #endif
1527 
1528     rtl::OUString aSysPath;
1529     if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
1530         return FALSE;
1531     const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
1532     const ByteString aToFile( aSysPath.getStr(), (xub_StrLen)aSysPath.getLength(), aThreadEncoding );
1533 
1534 	// check if the font has a CFF-table
1535 	const DWORD nCffTag = CalcTag( "CFF " );
1536 	const RawFontData aRawCffData( mhPS, nCffTag );
1537 	if( aRawCffData.get() )
1538 	{
1539 		long nRealGlyphIds[ 256 ];
1540 		for( int i = 0; i < nGlyphCount; ++i )
1541 		{
1542 			// TODO: remap notdef glyph if needed
1543 			// TODO: use GDI's GetGlyphIndices instead? Does it handle GSUB properly?
1544 			sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
1545 			if( pGlyphIDs[i] & GF_ISCHAR ) // remaining pseudo-glyphs need to be translated
1546 				nGlyphIdx = pImplFontCharMap->GetGlyphIndex( nGlyphIdx );
1547 			if( (pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0)	// TODO: vertical substitution
1548 				{/*####*/}
1549 
1550 			nRealGlyphIds[i] = nGlyphIdx;
1551 		}
1552 
1553 		// provide a font subset from the CFF-table
1554 		FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
1555 		rInfo.LoadFont( FontSubsetInfo::CFF_FONT, aRawCffData.get(), aRawCffData.size() );
1556 		bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL,
1557 				nRealGlyphIds, pEncoding, nGlyphCount, pGlyphWidths );
1558 		fclose( pOutFile );
1559 		return bRC;
1560 	}
1561 
1562     // get raw font file data
1563     const RawFontData xRawFontData( mhPS, NULL );
1564     if( !xRawFontData.get() )
1565 		return FALSE;
1566 
1567 	// open font file
1568 	sal_uInt32 nFaceNum = 0;
1569 	if( !*xRawFontData.get() )	// TTC candidate
1570 		nFaceNum = ~0U;	 // indicate "TTC font extracts only"
1571 
1572 	ScopedTrueTypeFont aSftTTF;
1573 	int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
1574 	if( nRC != SF_OK )
1575 		return FALSE;
1576 
1577 	TTGlobalFontInfo aTTInfo;
1578 	::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
1579 	rInfo.m_nFontType   = FontSubsetInfo::SFNT_TTF;
1580 	rInfo.m_aPSName		= ImplSalGetUniString( aTTInfo.psname );
1581 	rInfo.m_nAscent		= +aTTInfo.winAscent;
1582 	rInfo.m_nDescent	= -aTTInfo.winDescent;
1583 	rInfo.m_aFontBBox	= Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
1584 									Point( aTTInfo.xMax, aTTInfo.yMax ) );
1585 	rInfo.m_nCapHeight	= aTTInfo.yMax; // Well ...
1586 
1587 	// subset TTF-glyphs and get their properties
1588 	// take care that subset fonts require the NotDef glyph in pos 0
1589 	int nOrigCount = nGlyphCount;
1590 	USHORT	  aShortIDs[ 256 ];
1591 	sal_uInt8 aTempEncs[ 256 ];
1592 
1593 	int nNotDef=-1, i;
1594 	for( i = 0; i < nGlyphCount; ++i )
1595 	{
1596 		aTempEncs[i] = pEncoding[i];
1597 		sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
1598 		if( pGlyphIDs[i] & GF_ISCHAR )
1599 		{
1600 			sal_Unicode cChar = static_cast<sal_Unicode>(nGlyphIdx); // TODO: sal_UCS4
1601 			const bool bVertical = ((pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0);
1602 			nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical );
1603 			if( (nGlyphIdx == 0) && pFont->IsSymbolFont() )
1604 			{
1605 				// #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
1606 				cChar = (cChar & 0xF000) ? (cChar & 0x00FF) : (cChar | 0xF000);
1607 				nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical );
1608 			}
1609 		}
1610 		aShortIDs[i] = static_cast<USHORT>( nGlyphIdx );
1611 		if( !nGlyphIdx )
1612 			if( nNotDef < 0 )
1613 				nNotDef = i; // first NotDef glyph found
1614 	}
1615 
1616 	if( nNotDef != 0 )
1617 	{
1618 		// add fake NotDef glyph if needed
1619 		if( nNotDef < 0 )
1620 			nNotDef = nGlyphCount++;
1621 
1622 		// NotDef glyph must be in pos 0 => swap glyphids
1623 		aShortIDs[ nNotDef ] = aShortIDs[0];
1624 		aTempEncs[ nNotDef ] = aTempEncs[0];
1625 		aShortIDs[0] = 0;
1626 		aTempEncs[0] = 0;
1627 	}
1628 	DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
1629 
1630 	// fill pWidth array
1631 	TTSimpleGlyphMetrics* pMetrics =
1632 		::GetTTSimpleGlyphMetrics( aSftTTF.get(), aShortIDs, nGlyphCount, aIFSD.mbVertical );
1633 	if( !pMetrics )
1634 		return FALSE;
1635 	sal_uInt16 nNotDefAdv	= pMetrics[0].adv;
1636 	pMetrics[0].adv			= pMetrics[nNotDef].adv;
1637 	pMetrics[nNotDef].adv	= nNotDefAdv;
1638 	for( i = 0; i < nOrigCount; ++i )
1639 		pGlyphWidths[i] = pMetrics[i].adv;
1640 	free( pMetrics );
1641 
1642 	// write subset into destination file
1643 	nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.GetBuffer(), aShortIDs,
1644 			aTempEncs, nGlyphCount, 0, NULL, 0 );
1645 	return (nRC == SF_OK);
1646 }
1647 
1648 //--------------------------------------------------------------------------
1649 
1650 const void* Os2SalGraphics::GetEmbedFontData( const ImplFontData* pFont,
1651 	const sal_Ucs* pUnicodes, sal_Int32* pCharWidths,
1652 	FontSubsetInfo& rInfo, long* pDataLen )
1653 {
1654 	// create matching ImplFontSelectData
1655 	// we need just enough to get to the font file data
1656 	ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1657 
1658 	// TODO: much better solution: move SetFont and restoration of old font to caller
1659 	ScopedFont aOldFont(*this);
1660 	SetFont( &aIFSD, 0 );
1661 
1662 	// get the raw font file data
1663 	RawFontData aRawFontData( mhPS );
1664 	*pDataLen = aRawFontData.size();
1665 	if( !aRawFontData.get() )
1666 		return NULL;
1667 
1668 	// get important font properties
1669 	FONTMETRICS aOS2Metric;
1670 	if (Ft2QueryFontMetrics( mhPS, sizeof( aOS2Metric ), &aOS2Metric ) == GPI_ERROR)
1671 			*pDataLen = 0;
1672 	rInfo.m_nFontType	= FontSubsetInfo::ANY_TYPE1;
1673 	rInfo.m_aPSName		= ImplSalGetUniString( aOS2Metric.szFacename );
1674 	rInfo.m_nAscent		= +aOS2Metric.lMaxAscender;
1675 	rInfo.m_nDescent	= -aOS2Metric.lMaxDescender;
1676 	rInfo.m_aFontBBox	= Rectangle( Point( 0, -aOS2Metric.lMaxDescender ),
1677 			  Point( aOS2Metric.lMaxCharInc, aOS2Metric.lMaxAscender+aOS2Metric.lExternalLeading ) );
1678 	rInfo.m_nCapHeight	= aOS2Metric.lMaxAscender; // Well ...
1679 
1680 	// get individual character widths
1681 	for( int i = 0; i < 256; ++i )
1682 	{
1683 		LONG nCharWidth = 0;
1684 		const sal_Ucs cChar = pUnicodes[i];
1685 		if( !Ft2QueryStringWidthW( mhPS, (LPWSTR)&cChar, 1, &nCharWidth ) )
1686 			*pDataLen = 0;
1687 		pCharWidths[i] = nCharWidth;
1688 	}
1689 
1690 	if( !*pDataLen )
1691 		return NULL;
1692 
1693 	const unsigned char* pData = aRawFontData.steal();
1694 	return (void*)pData;
1695 }
1696 
1697 //--------------------------------------------------------------------------
1698 
1699 void Os2SalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ )
1700 {
1701 	delete[] reinterpret_cast<char*>(const_cast<void*>(pData));
1702 }
1703 
1704 const Ucs2SIntMap* Os2SalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
1705 {
1706     // TODO: even for builtin fonts we get here... why?
1707     if( !pFont->IsEmbeddable() )
1708         return NULL;
1709 
1710     // fill the encoding vector
1711     // currently no nonencoded vector
1712     if( pNonEncoded )
1713         *pNonEncoded = NULL;
1714 
1715     const ImplOs2FontData* pWinFontData = static_cast<const ImplOs2FontData*>(pFont);
1716     const Ucs2SIntMap* pEncoding = pWinFontData->GetEncodingVector();
1717     if( pEncoding == NULL )
1718     {
1719         Ucs2SIntMap* pNewEncoding = new Ucs2SIntMap;
1720         #if 0
1721         // TODO: get correct encoding vector
1722         GLYPHSET aGlyphSet;
1723         aGlyphSet.cbThis = sizeof(aGlyphSet);
1724         DWORD aW = ::GetFontUnicodeRanges( mhPS, &aGlyphSet);
1725         #else
1726         for( sal_Unicode i = 32; i < 256; ++i )
1727             (*pNewEncoding)[i] = i;
1728         #endif
1729         pWinFontData->SetEncodingVector( pNewEncoding );
1730 	pEncoding = pNewEncoding;
1731     }
1732 
1733     return pEncoding;
1734 }
1735 
1736 //--------------------------------------------------------------------------
1737 
1738 void Os2SalGraphics::GetGlyphWidths( const ImplFontData* pFont,
1739                                      bool bVertical,
1740                                      Int32Vector& rWidths,
1741                                      Ucs2UIntMap& rUnicodeEnc )
1742 {
1743     // create matching ImplFontSelectData
1744     // we need just enough to get to the font file data
1745     ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1746 
1747     // TODO: much better solution: move SetFont and restoration of old font to caller
1748     ScopedFont aOldFont(*this);
1749 
1750     float fScale = 0.0;
1751     ImplDoSetFont( &aIFSD, fScale, 0);
1752 
1753     if( pFont->IsSubsettable() )
1754     {
1755         // get raw font file data
1756 	const RawFontData xRawFontData( mhPS );
1757 	if( !xRawFontData.get() )
1758 		return;
1759 
1760         // open font file
1761         sal_uInt32 nFaceNum = 0;
1762         if( !*xRawFontData.get() )  // TTC candidate
1763             nFaceNum = ~0U;  // indicate "TTC font extracts only"
1764 
1765         ScopedTrueTypeFont aSftTTF;
1766         int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
1767         if( nRC != SF_OK )
1768             return;
1769 
1770         int nGlyphs = GetTTGlyphCount( aSftTTF.get() );
1771         if( nGlyphs > 0 )
1772         {
1773             rWidths.resize(nGlyphs);
1774             std::vector<sal_uInt16> aGlyphIds(nGlyphs);
1775             for( int i = 0; i < nGlyphs; i++ )
1776                 aGlyphIds[i] = sal_uInt16(i);
1777             TTSimpleGlyphMetrics* pMetrics = ::GetTTSimpleGlyphMetrics( aSftTTF.get(),
1778                                                                         &aGlyphIds[0],
1779                                                                         nGlyphs,
1780                                                                         bVertical ? 1 : 0 );
1781             if( pMetrics )
1782             {
1783                 for( int i = 0; i< nGlyphs; i++ )
1784                     rWidths[i] = pMetrics[i].adv;
1785                 free( pMetrics );
1786                 rUnicodeEnc.clear();
1787             }
1788             const ImplOs2FontData* pWinFont = static_cast<const ImplOs2FontData*>(pFont);
1789             const ImplFontCharMap* pMap = pWinFont->GetImplFontCharMap();
1790 			DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" );
1791 
1792 			int nCharCount = pMap->GetCharCount();
1793             sal_uInt32 nChar = pMap->GetFirstChar();
1794 			for( int i = 0; i < nCharCount; i++ )
1795             {
1796                 if( nChar < 0x00010000 )
1797                 {
1798                     sal_uInt16 nGlyph = ::MapChar( aSftTTF.get(),
1799                                                    static_cast<sal_uInt16>(nChar),
1800                                                    bVertical ? 1 : 0 );
1801                     if( nGlyph )
1802                         rUnicodeEnc[ static_cast<sal_Unicode>(nChar) ] = nGlyph;
1803                 }
1804 				nChar = pMap->GetNextChar( nChar );
1805             }
1806         }
1807     }
1808     else if( pFont->IsEmbeddable() )
1809     {
1810         // get individual character widths
1811         rWidths.clear();
1812         rUnicodeEnc.clear();
1813         rWidths.reserve( 224 );
1814         for( sal_Unicode i = 32; i < 256; ++i )
1815         {
1816             int nCharWidth = 0;
1817             if( Ft2QueryStringWidthW( mhPS, (LPWSTR)&i, 1, (LONG*)&nCharWidth ) )
1818             {
1819                 rUnicodeEnc[ i ] = rWidths.size();
1820                 rWidths.push_back( nCharWidth );
1821             }
1822         }
1823     }
1824 }
1825 
1826 //--------------------------------------------------------------------------
1827 
1828 void Os2SalGraphics::DrawServerFontLayout( const ServerFontLayout& )
1829 {}
1830 
1831 //--------------------------------------------------------------------------
1832 
1833 SystemFontData Os2SalGraphics::GetSysFontData( int nFallbacklevel ) const
1834 {
1835     SystemFontData aSysFontData;
1836 
1837     if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
1838     if (nFallbacklevel < 0 ) nFallbacklevel = 0;
1839 
1840     aSysFontData.nSize = sizeof( SystemFontData );
1841     aSysFontData.hFont = mhFonts[nFallbacklevel];
1842     aSysFontData.bFakeBold = false;
1843     aSysFontData.bFakeItalic = false;
1844     aSysFontData.bAntialias = true;
1845     aSysFontData.bVerticalCharacterType = false;
1846 
1847     return aSysFontData;
1848 }
1849 
1850 //--------------------------------------------------------------------------
1851