xref: /AOO41X/main/vcl/os2/source/gdi/salgdi3.cxx (revision 0663c327582f968e1750ac5ec4436c7b80d65a36)
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 
FixedFromDouble(double d)82 inline W32FIXED FixedFromDouble( double d )
83 {
84     const long l = (long) ( d * 65536. );
85     return *(W32FIXED*) &l;
86 }
87 
88 // -----------------------------------------------------------------------
89 
IntTimes256FromFixed(W32FIXED f)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 
ImplSalGetUniString(const sal_Char * pStr,xub_StrLen nLen=STRING_LEN)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 
ImplSalToCharSet(CharSet eCharSet)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 
ImplCharSetToSal(USHORT usCodePage)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 
ImplFamilyToSal(PM_BYTE bFamilyType)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 
ImplWeightToSal(USHORT nWeight)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 
ImpStyleNameToSal(const char * pFamilyName,const char * pFaceName,USHORT nLen)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 
ImplLogPitchToSal(PM_BYTE fsType)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 
ImplPitchToWin(FontPitch ePitch)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 
Os2Font2DevFontAttributes(const PFONTMETRICS pFontMetric)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 );
~RawFontData()356                 ~RawFontData() { delete[] mpRawBytes; }
get() const357     const unsigned char*    get() const { return mpRawBytes; }
steal()358     const unsigned char*    steal() { unsigned char* p = mpRawBytes; mpRawBytes = NULL; return p; }
size() const359     const int               size() const { return mnByteCount; }
360 
361 private:
362     unsigned char*  mpRawBytes;
363     int             mnByteCount;
364 };
365 
RawFontData(HPS hPS,DWORD nTableTag)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 
ImplOs2FontData(PFONTMETRICS _pFontMetric,int nHeight,PM_BYTE nPitchAndFamily)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 
~ImplOs2FontData()439 ImplOs2FontData::~ImplOs2FontData()
440 {
441     delete[] mpFontCharSets;
442 
443     if( mpUnicodeMap )
444         mpUnicodeMap->DeReference();
445 }
446 
447 // -----------------------------------------------------------------------
448 
GetFontId() const449 sal_IntPtr ImplOs2FontData::GetFontId() const
450 {
451     return mnId;
452 }
453 
454 // -----------------------------------------------------------------------
455 
UpdateFromHPS(HPS hPS) const456 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 
HasGSUBstitutions(HPS hPS) const475 bool ImplOs2FontData::HasGSUBstitutions( HPS hPS ) const
476 {
477     if( !mbGsubRead )
478         ReadGsubTable( hPS );
479     return !maGsubTable.empty();
480 }
481 
482 // -----------------------------------------------------------------------
483 
IsGSUBstituted(sal_Ucs cChar) const484 bool ImplOs2FontData::IsGSUBstituted( sal_Ucs cChar ) const
485 {
486     return( maGsubTable.find( cChar ) != maGsubTable.end() );
487 }
488 
489 // -----------------------------------------------------------------------
490 
GetImplFontCharMap() const491 const ImplFontCharMap* ImplOs2FontData::GetImplFontCharMap() const
492 {
493     mpUnicodeMap->AddReference();
494     return mpUnicodeMap;
495 }
496 
497 // -----------------------------------------------------------------------
498 
GetUInt(const unsigned char * p)499 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
GetUShort(const unsigned char * p)500 static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
GetSShort(const unsigned char * p)501 static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
CalcTag(const char p[4])502 static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); }
503 
ReadOs2Table(HPS hPS) const504 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 
ReadGsubTable(HPS hPS) const536 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 
ReadCmapTable(HPS hPS) const583 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 
SetTextColor(SalColor nSalColor)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 
ImplDoSetFont(ImplFontSelectData * i_pFont,float & o_rFontScale,int nFallbackLevel)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 
SetFont(ImplFontSelectData * pFont,int nFallbackLevel)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>10
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 
GetFontMetric(ImplFontMetricData * pMetric,int nFallbackLevel)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 
GetKernPairs(ULONG nPairs,ImplKernPairData * pKernPairs)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 
GetImplFontCharMap() const1049 const ImplFontCharMap* Os2SalGraphics::GetImplFontCharMap() const
1050 {
1051     if( !mpOs2FontData[0] )
1052         return ImplFontCharMap::GetDefaultMap();
1053     return mpOs2FontData[0]->GetImplFontCharMap();
1054 }
1055 
1056 // -----------------------------------------------------------------------
1057 
AddTempDevFont(ImplDevFontList * pFontList,const String & rFontFileURL,const String & rFontName)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 
GetDevFontList(ImplDevFontList * pList)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 
GetDevFontSubstList(OutputDevice * pOutDev)1195 void Os2SalGraphics::GetDevFontSubstList( OutputDevice* pOutDev )
1196 {
1197 }
1198 
1199 // -----------------------------------------------------------------------
1200 
GetGlyphBoundRect(sal_GlyphId aGlyphId,Rectangle & rRect)1201 bool Os2SalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, 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( !(aGlyphId & GF_ISCHAR) )
1210         nGGOFlags |= GGO_GLYPH_INDEX;
1211     aGlyphId &= GF_IDXMASK;
1212 
1213     GLYPHMETRICS aGM;
1214     DWORD nSize = FT2_ERROR;
1215     nSize = Ft2GetGlyphOutline( mhPS, aGlyphId, 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 
GetGlyphOutline(sal_GlyphId aGlyphId,::basegfx::B2DPolyPolygon & rB2DPolyPoly)1230 bool Os2SalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId, ::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( !(aGlyphId & GF_ISCHAR) )
1246         nGGOFlags |= GGO_GLYPH_INDEX;
1247     aGlyphId &= GF_IDXMASK;
1248 
1249     GLYPHMETRICS aGlyphMetrics;
1250     DWORD nSize1 = FT2_ERROR;
1251     nSize1 = Ft2GetGlyphOutline( mhPS, aGlyphId, 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, aGlyphId, 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:
ScopedCharArray(char * pArray)1427     inline explicit ScopedCharArray(char * pArray): m_pArray(pArray) {}
1428 
~ScopedCharArray()1429     inline ~ScopedCharArray() { delete[] m_pArray; }
1430 
get() const1431     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 
ScopedFont(Os2SalGraphics & rData)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 
~ScopedFont()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:
ScopedTrueTypeFont()1474     inline ScopedTrueTypeFont(): m_pFont(0) {}
1475 
1476     ~ScopedTrueTypeFont();
1477 
1478     int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum);
1479 
get() const1480     inline TrueTypeFont * get() const { return m_pFont; }
1481 
1482 private:
1483     TrueTypeFont * m_pFont;
1484 };
1485 
~ScopedTrueTypeFont()1486 ScopedTrueTypeFont::~ScopedTrueTypeFont()
1487 {
1488     if (m_pFont != 0)
1489         CloseTTFont(m_pFont);
1490 }
1491 
open(void * pBuffer,sal_uInt32 nLen,sal_uInt32 nFaceNum)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 
CreateFontSubset(const rtl::OUString & rToFile,const ImplFontData * pFont,sal_GlyphId * pGlyphIds,sal_uInt8 * pEncoding,sal_Int32 * pGlyphWidths,int nGlyphCount,FontSubsetInfo & rInfo)1499 sal_Bool Os2SalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
1500     const ImplFontData* pFont, sal_GlyphId* 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         sal_GlyphId aRealGlyphIds[ 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 aGlyphId = pGlyphIds[i] & GF_IDXMASK;
1545             if( pGlyphIds[i] & GF_ISCHAR ) // remaining pseudo-glyphs need to be translated
1546                 aGlyphId = pImplFontCharMap->GetGlyphIndex( aGlyphId );
1547             if( (pGlyphIds[i] & (GF_ROTMASK|GF_GSUB)) != 0) // TODO: vertical substitution
1548                 {/*####*/}
1549 
1550             aRealGlyphIds[i] = aGlyphId;
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                 aRealGlyphIds, 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_GlyphId aGlyphId = pGlyphIds[i] & GF_IDXMASK;
1598         if( pGlyphIds[i] & GF_ISCHAR )
1599         {
1600             sal_Unicode cChar = static_cast<sal_Unicode>(aGlyphId); // TODO: sal_UCS4
1601             const bool bVertical = ((pGlyphIds[i] & (GF_ROTMASK|GF_GSUB)) != 0);
1602             aGlyphId = ::MapChar( aSftTTF.get(), cChar, bVertical );
1603             if( (aGlyphId == 0) && pFont->IsSymbolFont() )
1604             {
1605                 // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
1606                 cChar = (cChar & 0xF000) ? (cChar & 0x00FF) : (cChar | 0xF000);
1607                 aGlyphId = ::MapChar( aSftTTF.get(), cChar, bVertical );
1608             }
1609         }
1610         aShortIDs[i] = static_cast<USHORT>( aGlyphId );
1611         if( !aGlyphId )
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 
GetEmbedFontData(const ImplFontData * pFont,const sal_Ucs * pUnicodes,sal_Int32 * pCharWidths,FontSubsetInfo & rInfo,long * pDataLen)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 
FreeEmbedFontData(const void * pData,long)1699 void Os2SalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ )
1700 {
1701     delete[] reinterpret_cast<char*>(const_cast<void*>(pData));
1702 }
1703 
GetFontEncodingVector(const ImplFontData * pFont,const Ucs2OStrMap ** pNonEncoded)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 
GetGlyphWidths(const ImplFontData * pFont,bool bVertical,Int32Vector & rWidths,Ucs2UIntMap & rUnicodeEnc)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 
DrawServerFontLayout(const ServerFontLayout &)1828 void Os2SalGraphics::DrawServerFontLayout( const ServerFontLayout& )
1829 {}
1830 
1831 //--------------------------------------------------------------------------
1832 
GetSysFontData(int nFallbacklevel) const1833 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