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