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®istry 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