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