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