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