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 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_vcl.hxx" 30 31 #ifdef WNT 32 #include <svsys.h> 33 #undef CreateFont 34 #endif 35 36 #include "gcach_ftyp.hxx" 37 38 #include "vcl/svapp.hxx" 39 40 #include "outfont.hxx" 41 #include "impfont.hxx" 42 43 #include "tools/poly.hxx" 44 #include "basegfx/matrix/b2dhommatrix.hxx" 45 #include "basegfx/matrix/b2dhommatrixtools.hxx" 46 #include "basegfx/polygon/b2dpolypolygon.hxx" 47 48 #include "osl/file.hxx" 49 #include "osl/thread.hxx" 50 51 #include <ft2build.h> 52 #include FT_FREETYPE_H 53 #include FT_GLYPH_H 54 #include FT_OUTLINE_H 55 #include FT_TRUETYPE_TABLES_H 56 #include FT_TRUETYPE_TAGS_H 57 #include FT_TRUETYPE_IDS_H 58 59 #ifndef FT_RENDER_MODE_MONO // happens in the MACOSX build 60 #define FT_RENDER_MODE_MONO ft_render_mode_mono 61 #endif 62 #include "rtl/instance.hxx" 63 64 #ifndef FREETYPE_PATCH 65 // VERSION_MINOR in freetype.h is too coarse 66 // if patch-level is not available we need to fine-tune the version ourselves 67 #define FTVERSION 2005 68 #else 69 #define FTVERSION (1000*FREETYPE_MAJOR + 100*FREETYPE_MINOR + FREETYPE_PATCH) 70 #endif 71 #if FTVERSION >= 2200 72 typedef const FT_Vector* FT_Vector_CPtr; 73 #else // FTVERSION < 2200 74 typedef FT_Vector* FT_Vector_CPtr; 75 #endif 76 77 #include <vector> 78 79 // TODO: move file mapping stuff to OSL 80 #if defined(UNX) 81 #if !defined(HPUX) 82 // PORTERS: dlfcn is used for getting symbols from FT versions newer than baseline 83 #include <dlfcn.h> 84 #endif 85 #include <unistd.h> 86 #include <fcntl.h> 87 #include <sys/stat.h> 88 #include <sys/mman.h> 89 #include "vcl/fontmanager.hxx" 90 #elif defined(WNT) 91 #include <io.h> 92 #define strncasecmp strnicmp 93 #endif 94 95 typedef const unsigned char* CPU8; 96 inline sal_uInt16 NEXT_U16( CPU8& p ) { p+=2; return (p[-2]<<8)|p[-1]; } 97 inline sal_Int16 NEXT_S16( CPU8& p ) { return (sal_Int16)NEXT_U16(p); } 98 inline sal_uInt32 NEXT_U32( CPU8& p ) { p+=4; return (p[-4]<<24)|(p[-3]<<16)|(p[-2]<<8)|p[-1]; } 99 //inline sal_Int32 NEXT_S32( U8*& p ) { return (sal_Int32)NEXT_U32(p); } 100 101 // ----------------------------------------------------------------------- 102 103 // the gamma table makes artificial bold look better for CJK glyphs 104 static unsigned char aGammaTable[257]; 105 106 static void InitGammaTable() 107 { 108 static const int M_MAX = 255; 109 static const int M_X = 128; 110 static const int M_Y = 208; 111 112 int x, a; 113 for( x = 0; x < 256; x++) 114 { 115 if ( x <= M_X ) 116 a = ( x * M_Y + M_X / 2) / M_X; 117 else 118 a = M_Y + ( ( x - M_X ) * ( M_MAX - M_Y ) + 119 ( M_MAX - M_X ) / 2 ) / ( M_MAX - M_X ); 120 121 aGammaTable[x] = (unsigned char)a; 122 } 123 } 124 125 // ----------------------------------------------------------------------- 126 127 static FT_Library aLibFT = 0; 128 129 // #110607# enable linking with old FT versions 130 static int nFTVERSION = 0; 131 static FT_Error (*pFTNewSize)(FT_Face,FT_Size*); 132 static FT_Error (*pFTActivateSize)(FT_Size); 133 static FT_Error (*pFTDoneSize)(FT_Size); 134 FT_Error (*pFTEmbolden)(FT_GlyphSlot); 135 FT_Error (*pFTOblique)(FT_GlyphSlot); 136 static bool bEnableSizeFT = false; 137 138 struct EqStr{ bool operator()(const char* a, const char* b) const { return !strcmp(a,b); } }; 139 typedef ::std::hash_map<const char*,FtFontFile*,::std::hash<const char*>, EqStr> FontFileList; 140 namespace { struct vclFontFileList : public rtl::Static< FontFileList, vclFontFileList > {}; } 141 142 // ----------------------------------------------------------------------- 143 144 // TODO: remove when the priorities are selected by UI 145 // if (AH==0) => disable autohinting 146 // if (AA==0) => disable antialiasing 147 // if (EB==0) => disable embedded bitmaps 148 // if (AA prio <= AH prio) => antialias + autohint 149 // if (AH<AA) => do not autohint when antialiasing 150 // if (EB<AH) => do not autohint for monochrome 151 static int nDefaultPrioEmbedded = 2; 152 static int nDefaultPrioAutoHint = 1; 153 static int nDefaultPrioAntiAlias = 1; 154 155 // ======================================================================= 156 // FreetypeManager 157 // ======================================================================= 158 159 FtFontFile::FtFontFile( const ::rtl::OString& rNativeFileName ) 160 : maNativeFileName( rNativeFileName ), 161 mpFileMap( NULL ), 162 mnFileSize( 0 ), 163 mnRefCount( 0 ), 164 mnLangBoost( 0 ) 165 { 166 // boost font preference if UI language is mentioned in filename 167 int nPos = maNativeFileName.lastIndexOf( '_' ); 168 if( nPos == -1 || maNativeFileName[nPos+1] == '.' ) 169 mnLangBoost += 0x1000; // no langinfo => good 170 else 171 { 172 static const char* pLangBoost = NULL; 173 static bool bOnce = true; 174 if( bOnce ) 175 { 176 bOnce = false; 177 LanguageType aLang = Application::GetSettings().GetUILanguage(); 178 switch( aLang ) 179 { 180 case LANGUAGE_JAPANESE: 181 pLangBoost = "jan"; 182 break; 183 case LANGUAGE_CHINESE: 184 case LANGUAGE_CHINESE_SIMPLIFIED: 185 case LANGUAGE_CHINESE_SINGAPORE: 186 pLangBoost = "zhs"; 187 break; 188 case LANGUAGE_CHINESE_TRADITIONAL: 189 case LANGUAGE_CHINESE_HONGKONG: 190 case LANGUAGE_CHINESE_MACAU: 191 pLangBoost = "zht"; 192 break; 193 case LANGUAGE_KOREAN: 194 case LANGUAGE_KOREAN_JOHAB: 195 pLangBoost = "kor"; 196 break; 197 } 198 } 199 200 if( pLangBoost && !strncasecmp( pLangBoost, &maNativeFileName.getStr()[nPos+1], 3 ) ) 201 mnLangBoost += 0x2000; // matching langinfo => better 202 } 203 } 204 205 // ----------------------------------------------------------------------- 206 207 FtFontFile* FtFontFile::FindFontFile( const ::rtl::OString& rNativeFileName ) 208 { 209 // font file already known? (e.g. for ttc, synthetic, aliased fonts) 210 const char* pFileName = rNativeFileName.getStr(); 211 FontFileList &rFontFileList = vclFontFileList::get(); 212 FontFileList::const_iterator it = rFontFileList.find( pFileName ); 213 if( it != rFontFileList.end() ) 214 return (*it).second; 215 216 // no => create new one 217 FtFontFile* pFontFile = new FtFontFile( rNativeFileName ); 218 pFileName = pFontFile->maNativeFileName.getStr(); 219 rFontFileList[ pFileName ] = pFontFile; 220 return pFontFile; 221 } 222 223 // ----------------------------------------------------------------------- 224 225 bool FtFontFile::Map() 226 { 227 if( mnRefCount++ <= 0 ) 228 { 229 const char* pFileName = maNativeFileName.getStr(); 230 #if defined(UNX) 231 int nFile = open( pFileName, O_RDONLY ); 232 if( nFile < 0 ) 233 return false; 234 235 struct stat aStat; 236 fstat( nFile, &aStat ); 237 mnFileSize = aStat.st_size; 238 mpFileMap = (const unsigned char*) 239 mmap( NULL, mnFileSize, PROT_READ, MAP_SHARED, nFile, 0 ); 240 if( mpFileMap == MAP_FAILED ) 241 mpFileMap = NULL; 242 close( nFile ); 243 #elif defined(WNT) 244 void* pFileDesc = ::CreateFile( pFileName, GENERIC_READ, FILE_SHARE_READ, 245 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); 246 if( pFileDesc == INVALID_HANDLE_VALUE) 247 return false; 248 249 mnFileSize = ::GetFileSize( pFileDesc, NULL ); 250 HANDLE aHandle = ::CreateFileMapping( pFileDesc, NULL, PAGE_READONLY, 0, mnFileSize, "TTF" ); 251 mpFileMap = (const unsigned char*)::MapViewOfFile( aHandle, FILE_MAP_READ, 0, 0, mnFileSize ); 252 ::CloseHandle( pFileDesc ); 253 #else 254 FILE* pFile = fopen( pFileName, "rb" ); 255 if( !pFile ) 256 return false; 257 258 struct stat aStat; 259 stat( pFileName, &aStat ); 260 mnFileSize = aStat.st_size; 261 mpFileMap = new unsigned char[ mnFileSize ]; 262 if( mnFileSize != fread( mpFileMap, 1, mnFileSize, pFile ) ) 263 { 264 delete[] mpFileMap; 265 mpFileMap = NULL; 266 } 267 fclose( pFile ); 268 #endif 269 } 270 271 return (mpFileMap != NULL); 272 } 273 274 // ----------------------------------------------------------------------- 275 276 void FtFontFile::Unmap() 277 { 278 if( (--mnRefCount > 0) || (mpFileMap == NULL) ) 279 return; 280 281 #if defined(UNX) 282 munmap( (char*)mpFileMap, mnFileSize ); 283 #elif defined(WNT) 284 UnmapViewOfFile( (LPCVOID)mpFileMap ); 285 #else 286 delete[] mpFileMap; 287 #endif 288 289 mpFileMap = NULL; 290 } 291 292 // ======================================================================= 293 294 FtFontInfo::FtFontInfo( const ImplDevFontAttributes& rDevFontAttributes, 295 const ::rtl::OString& rNativeFileName, int nFaceNum, sal_IntPtr nFontId, int nSynthetic, 296 const ExtraKernInfo* pExtraKernInfo ) 297 : 298 maFaceFT( NULL ), 299 mpFontFile( FtFontFile::FindFontFile( rNativeFileName ) ), 300 mnFaceNum( nFaceNum ), 301 mnRefCount( 0 ), 302 mnSynthetic( nSynthetic ), 303 mnFontId( nFontId ), 304 maDevFontAttributes( rDevFontAttributes ), 305 mpFontCharMap( NULL ), 306 mpChar2Glyph( NULL ), 307 mpGlyph2Char( NULL ), 308 mpExtraKernInfo( pExtraKernInfo ) 309 { 310 // prefer font with low ID 311 maDevFontAttributes.mnQuality += 10000 - nFontId; 312 // prefer font with matching file names 313 maDevFontAttributes.mnQuality += mpFontFile->GetLangBoost(); 314 // prefer font with more external info 315 if( pExtraKernInfo ) 316 maDevFontAttributes.mnQuality += 100; 317 } 318 319 // ----------------------------------------------------------------------- 320 321 FtFontInfo::~FtFontInfo() 322 { 323 if( mpFontCharMap ) 324 mpFontCharMap->DeReference(); 325 delete mpExtraKernInfo; 326 delete mpChar2Glyph; 327 delete mpGlyph2Char; 328 } 329 330 void FtFontInfo::InitHashes() const 331 { 332 // TODO: avoid pointers when empty stl::hash_* objects become cheap 333 mpChar2Glyph = new Int2IntMap(); 334 mpGlyph2Char = new Int2IntMap(); 335 } 336 337 // ----------------------------------------------------------------------- 338 339 FT_FaceRec_* FtFontInfo::GetFaceFT() 340 { 341 // get faceFT once/multiple depending on availability of SizeFT APIs 342 if( (mnRefCount++ <= 0) || !bEnableSizeFT ) 343 { 344 if( !mpFontFile->Map() ) 345 return NULL; 346 FT_Error rc = FT_New_Memory_Face( aLibFT, 347 (FT_Byte*)mpFontFile->GetBuffer(), 348 mpFontFile->GetFileSize(), mnFaceNum, &maFaceFT ); 349 if( (rc != FT_Err_Ok) || (maFaceFT->num_glyphs <= 0) ) 350 maFaceFT = NULL; 351 } 352 353 return maFaceFT; 354 } 355 356 // ----------------------------------------------------------------------- 357 358 void FtFontInfo::ReleaseFaceFT( FT_FaceRec_* pFaceFT ) 359 { 360 // release last/each depending on SizeFT availability 361 if( (--mnRefCount <= 0) || !bEnableSizeFT ) 362 { 363 FT_Done_Face( pFaceFT ); 364 maFaceFT = NULL; 365 mpFontFile->Unmap(); 366 } 367 } 368 369 // ----------------------------------------------------------------------- 370 371 bool FtFontInfo::HasExtraKerning() const 372 { 373 if( !mpExtraKernInfo ) 374 return false; 375 // TODO: how to enable the line below without getting #i29881# back? 376 // on the other hand being to optimistic doesn't cause problems 377 // return mpExtraKernInfo->HasKernPairs(); 378 return true; 379 } 380 381 // ----------------------------------------------------------------------- 382 383 int FtFontInfo::GetExtraKernPairs( ImplKernPairData** ppKernPairs ) const 384 { 385 if( !mpExtraKernInfo ) 386 return 0; 387 return mpExtraKernInfo->GetUnscaledKernPairs( ppKernPairs ); 388 } 389 390 // ----------------------------------------------------------------------- 391 392 int FtFontInfo::GetExtraGlyphKernValue( int nLeftGlyph, int nRightGlyph ) const 393 { 394 if( !mpExtraKernInfo ) 395 return 0; 396 if( !mpGlyph2Char ) 397 return 0; 398 sal_Unicode cLeftChar = (*mpGlyph2Char)[ nLeftGlyph ]; 399 sal_Unicode cRightChar = (*mpGlyph2Char)[ nRightGlyph ]; 400 return mpExtraKernInfo->GetUnscaledKernValue( cLeftChar, cRightChar ); 401 } 402 403 // ----------------------------------------------------------------------- 404 405 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);} 406 static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);} 407 //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));} 408 409 // ----------------------------------------------------------------------- 410 411 const unsigned char* FtFontInfo::GetTable( const char* pTag, sal_uLong* pLength ) const 412 { 413 const unsigned char* pBuffer = mpFontFile->GetBuffer(); 414 int nFileSize = mpFontFile->GetFileSize(); 415 if( !pBuffer || nFileSize<1024 ) 416 return NULL; 417 418 // we currently only handle TTF and TTC headers 419 unsigned nFormat = GetUInt( pBuffer ); 420 const unsigned char* p = pBuffer + 12; 421 if( nFormat == 0x74746366 ) // TTC_MAGIC 422 p += GetUInt( p + 4 * mnFaceNum ); 423 else if( (nFormat!=0x00010000) && (nFormat!=0x74727565) ) // TTF_MAGIC and Apple TTF Magic 424 return NULL; 425 426 // walk table directory until match 427 int nTables = GetUShort( p - 8 ); 428 if( nTables >= 64 ) // something fishy? 429 return NULL; 430 for( int i = 0; i < nTables; ++i, p+=16 ) 431 { 432 if( p[0]==pTag[0] && p[1]==pTag[1] && p[2]==pTag[2] && p[3]==pTag[3] ) 433 { 434 sal_uLong nLength = GetUInt( p + 12 ); 435 if( pLength != NULL ) 436 *pLength = nLength; 437 const unsigned char* pTable = pBuffer + GetUInt( p + 8 ); 438 if( (pTable + nLength) <= (mpFontFile->GetBuffer() + nFileSize) ) 439 return pTable; 440 } 441 } 442 443 return NULL; 444 } 445 446 // ----------------------------------------------------------------------- 447 448 void FtFontInfo::AnnounceFont( ImplDevFontList* pFontList ) 449 { 450 ImplFTSFontData* pFD = new ImplFTSFontData( this, maDevFontAttributes ); 451 pFontList->Add( pFD ); 452 } 453 454 // ======================================================================= 455 456 FreetypeManager::FreetypeManager() 457 : mnMaxFontId( 0 ), mnNextFontId( 0x1000 ) 458 { 459 /*FT_Error rcFT =*/ FT_Init_FreeType( &aLibFT ); 460 461 #ifdef RTLD_DEFAULT // true if a good dlfcn.h header was included 462 // Get version of freetype library to enable workarounds. 463 // Freetype <= 2.0.9 does not have FT_Library_Version(). 464 // Using dl_sym() instead of osl_getSymbol() because latter 465 // isn't designed to work with oslModule=NULL 466 void (*pFTLibraryVersion)(FT_Library library, 467 FT_Int *amajor, FT_Int *aminor, FT_Int *apatch); 468 pFTLibraryVersion = (void (*)(FT_Library library, 469 FT_Int *amajor, FT_Int *aminor, FT_Int *apatch))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Library_Version" ); 470 471 pFTNewSize = (FT_Error(*)(FT_Face,FT_Size*))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_New_Size" ); 472 pFTActivateSize = (FT_Error(*)(FT_Size))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Activate_Size" ); 473 pFTDoneSize = (FT_Error(*)(FT_Size))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Done_Size" ); 474 pFTEmbolden = (FT_Error(*)(FT_GlyphSlot))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_GlyphSlot_Embolden" ); 475 pFTOblique = (FT_Error(*)(FT_GlyphSlot))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_GlyphSlot_Oblique" ); 476 477 bEnableSizeFT = (pFTNewSize!=NULL) && (pFTActivateSize!=NULL) && (pFTDoneSize!=NULL); 478 479 FT_Int nMajor = 0, nMinor = 0, nPatch = 0; 480 if( pFTLibraryVersion ) 481 pFTLibraryVersion( aLibFT, &nMajor, &nMinor, &nPatch ); 482 nFTVERSION = nMajor * 1000 + nMinor * 100 + nPatch; 483 484 // disable embedded bitmaps for Freetype-2.1.3 unless explicitly 485 // requested by env var below because it crashes StarOffice on RH9 486 // reason: double free in freetype's embedded bitmap handling 487 if( nFTVERSION == 2103 ) 488 nDefaultPrioEmbedded = 0; 489 // disable artificial emboldening with the Freetype API for older versions 490 if( nFTVERSION < 2110 ) 491 pFTEmbolden = NULL; 492 493 #else // RTLD_DEFAULT 494 // assume systems where dlsym is not possible use supplied library 495 nFTVERSION = FTVERSION; 496 #endif 497 498 // TODO: remove when the priorities are selected by UI 499 char* pEnv; 500 pEnv = ::getenv( "SAL_EMBEDDED_BITMAP_PRIORITY" ); 501 if( pEnv ) 502 nDefaultPrioEmbedded = pEnv[0] - '0'; 503 pEnv = ::getenv( "SAL_ANTIALIASED_TEXT_PRIORITY" ); 504 if( pEnv ) 505 nDefaultPrioAntiAlias = pEnv[0] - '0'; 506 pEnv = ::getenv( "SAL_AUTOHINTING_PRIORITY" ); 507 if( pEnv ) 508 nDefaultPrioAutoHint = pEnv[0] - '0'; 509 510 InitGammaTable(); 511 } 512 513 // ----------------------------------------------------------------------- 514 515 void* FreetypeServerFont::GetFtFace() const 516 { 517 if( maSizeFT ) 518 pFTActivateSize( maSizeFT ); 519 520 return maFaceFT; 521 } 522 523 // ----------------------------------------------------------------------- 524 525 FreetypeManager::~FreetypeManager() 526 { 527 // an application about to exit can omit garbage collecting the heap 528 // since it makes things slower and introduces risks if the heap was not perfect 529 // for debugging, for memory grinding or leak checking the env allows to force GC 530 const char* pEnv = getenv( "SAL_FORCE_GC_ON_EXIT" ); 531 if( pEnv && (*pEnv != '0') ) 532 { 533 // cleanup container of fontinfos 534 for( FontList::const_iterator it = maFontList.begin(); it != maFontList.end(); ++it ) 535 { 536 FtFontInfo* pInfo = (*it).second; 537 delete pInfo; 538 } 539 maFontList.clear(); 540 541 #if 0 // FT_Done_FreeType crashes on Solaris 10 542 // TODO: check which versions have this problem 543 FT_Error rcFT = FT_Done_FreeType( aLibFT ); 544 #endif 545 } 546 } 547 548 // ----------------------------------------------------------------------- 549 550 void FreetypeManager::AddFontFile( const rtl::OString& rNormalizedName, 551 int nFaceNum, sal_IntPtr nFontId, const ImplDevFontAttributes& rDevFontAttr, 552 const ExtraKernInfo* pExtraKernInfo ) 553 { 554 if( !rNormalizedName.getLength() ) 555 return; 556 557 if( maFontList.find( nFontId ) != maFontList.end() ) 558 return; 559 560 FtFontInfo* pFontInfo = new FtFontInfo( rDevFontAttr, 561 rNormalizedName, nFaceNum, nFontId, 0, pExtraKernInfo ); 562 maFontList[ nFontId ] = pFontInfo; 563 if( mnMaxFontId < nFontId ) 564 mnMaxFontId = nFontId; 565 } 566 567 // ----------------------------------------------------------------------- 568 569 long FreetypeManager::AddFontDir( const String& rUrlName ) 570 { 571 osl::Directory aDir( rUrlName ); 572 osl::FileBase::RC rcOSL = aDir.open(); 573 if( rcOSL != osl::FileBase::E_None ) 574 return 0; 575 576 long nCount = 0; 577 578 osl::DirectoryItem aDirItem; 579 rtl_TextEncoding theEncoding = osl_getThreadTextEncoding(); 580 while( (rcOSL = aDir.getNextItem( aDirItem, 20 )) == osl::FileBase::E_None ) 581 { 582 osl::FileStatus aFileStatus( FileStatusMask_FileURL ); 583 rcOSL = aDirItem.getFileStatus( aFileStatus ); 584 585 ::rtl::OUString aUSytemPath; 586 OSL_VERIFY( osl::FileBase::E_None 587 == osl::FileBase::getSystemPathFromFileURL( aFileStatus.getFileURL(), aUSytemPath )); 588 ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding ); 589 const char* pszFontFileName = aCFileName.getStr(); 590 591 FT_FaceRec_* aFaceFT = NULL; 592 for( int nFaceNum = 0, nMaxFaces = 1; nFaceNum < nMaxFaces; ++nFaceNum ) 593 { 594 FT_Error rcFT = FT_New_Face( aLibFT, pszFontFileName, nFaceNum, &aFaceFT ); 595 if( (rcFT != FT_Err_Ok) || (aFaceFT == NULL) ) 596 break; 597 598 if( !FT_IS_SCALABLE( aFaceFT ) ) // ignore non-scalabale fonts 599 continue; 600 601 nMaxFaces = aFaceFT->num_faces; 602 603 ImplDevFontAttributes aDFA; 604 605 // TODO: prefer unicode names if available 606 // TODO: prefer locale specific names if available? 607 if ( aFaceFT->family_name ) 608 aDFA.maName = String::CreateFromAscii( aFaceFT->family_name ); 609 610 if ( aFaceFT->style_name ) 611 aDFA.maStyleName = String::CreateFromAscii( aFaceFT->style_name ); 612 613 aDFA.mbSymbolFlag = false; 614 for( int i = aFaceFT->num_charmaps; --i >= 0; ) 615 { 616 const FT_CharMap aCM = aFaceFT->charmaps[i]; 617 #if (FTVERSION < 2000) 618 if( aCM->encoding == FT_ENCODING_NONE ) 619 #else 620 if( (aCM->platform_id == TT_PLATFORM_MICROSOFT) 621 && (aCM->encoding_id == TT_MS_ID_SYMBOL_CS) ) 622 #endif 623 aDFA.mbSymbolFlag = true; 624 } 625 626 // TODO: extract better font characterization data from font 627 aDFA.meFamily = FAMILY_DONTKNOW; 628 aDFA.mePitch = FT_IS_FIXED_WIDTH( aFaceFT ) ? PITCH_FIXED : PITCH_VARIABLE; 629 aDFA.meWidthType = WIDTH_DONTKNOW; 630 aDFA.meWeight = FT_STYLE_FLAG_BOLD & aFaceFT->style_flags ? WEIGHT_BOLD : WEIGHT_NORMAL; 631 aDFA.meItalic = FT_STYLE_FLAG_ITALIC & aFaceFT->style_flags ? ITALIC_NORMAL : ITALIC_NONE; 632 633 aDFA.mnQuality = 0; 634 aDFA.mbOrientation= true; 635 aDFA.mbDevice = true; 636 aDFA.mbSubsettable= false; 637 aDFA.mbEmbeddable = false; 638 639 FT_Done_Face( aFaceFT ); 640 AddFontFile( aCFileName, nFaceNum, ++mnNextFontId, aDFA, NULL ); 641 ++nCount; 642 } 643 } 644 645 aDir.close(); 646 return nCount; 647 } 648 649 // ----------------------------------------------------------------------- 650 651 void FreetypeManager::AnnounceFonts( ImplDevFontList* pToAdd ) const 652 { 653 for( FontList::const_iterator it = maFontList.begin(); it != maFontList.end(); ++it ) 654 { 655 FtFontInfo* pFtFontInfo = it->second; 656 pFtFontInfo->AnnounceFont( pToAdd ); 657 } 658 } 659 660 // ----------------------------------------------------------------------- 661 662 void FreetypeManager::ClearFontList( ) 663 { 664 for( FontList::iterator it = maFontList.begin(); it != maFontList.end(); ++it ) 665 { 666 FtFontInfo* pFtFontInfo = it->second; 667 delete pFtFontInfo; 668 } 669 maFontList.clear(); 670 } 671 672 // ----------------------------------------------------------------------- 673 674 FreetypeServerFont* FreetypeManager::CreateFont( const ImplFontSelectData& rFSD ) 675 { 676 FtFontInfo* pFontInfo = NULL; 677 678 // find a FontInfo matching to the font id 679 sal_IntPtr nFontId = reinterpret_cast<sal_IntPtr>( rFSD.mpFontData ); 680 FontList::iterator it = maFontList.find( nFontId ); 681 if( it != maFontList.end() ) 682 pFontInfo = it->second; 683 684 if( !pFontInfo ) 685 return NULL; 686 687 FreetypeServerFont* pNew = new FreetypeServerFont( rFSD, pFontInfo ); 688 689 return pNew; 690 } 691 692 // ======================================================================= 693 694 ImplFTSFontData::ImplFTSFontData( FtFontInfo* pFI, const ImplDevFontAttributes& rDFA ) 695 : ImplFontData( rDFA, IFTSFONT_MAGIC ), 696 mpFtFontInfo( pFI ) 697 { 698 mbDevice = false; 699 mbOrientation = true; 700 } 701 702 // ----------------------------------------------------------------------- 703 704 ImplFontEntry* ImplFTSFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const 705 { 706 ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD ); 707 return pEntry; 708 } 709 710 // ======================================================================= 711 // FreetypeServerFont 712 // ======================================================================= 713 714 FreetypeServerFont::FreetypeServerFont( const ImplFontSelectData& rFSD, FtFontInfo* pFI ) 715 : ServerFont( rFSD ), 716 mnPrioEmbedded(nDefaultPrioEmbedded), 717 mnPrioAntiAlias(nDefaultPrioAntiAlias), 718 mnPrioAutoHint(nDefaultPrioAutoHint), 719 mpFontInfo( pFI ), 720 maFaceFT( NULL ), 721 maSizeFT( NULL ), 722 mbFaceOk( false ), 723 maRecodeConverter( NULL ), 724 mpLayoutEngine( NULL ) 725 { 726 maFaceFT = pFI->GetFaceFT(); 727 728 #ifdef HDU_DEBUG 729 fprintf( stderr, "FTSF::FTSF(\"%s\", h=%d, w=%d, sy=%d) => %d\n", 730 pFI->GetFontFileName()->getStr(), rFSD.mnHeight, rFSD.mnWidth, pFI->IsSymbolFont(), maFaceFT!=0 ); 731 #endif 732 733 if( !maFaceFT ) 734 return; 735 736 // set the pixel size of the font instance 737 mnWidth = rFSD.mnWidth; 738 if( !mnWidth ) 739 mnWidth = rFSD.mnHeight; 740 mfStretch = (double)mnWidth / rFSD.mnHeight; 741 // sanity check (e.g. #i66394#, #i66244#, #66537#) 742 if( (mnWidth < 0) || (mfStretch > +64.0) || (mfStretch < -64.0) ) 743 return; 744 745 // perf: use maSizeFT if available 746 if( bEnableSizeFT ) 747 { 748 pFTNewSize( maFaceFT, &maSizeFT ); 749 pFTActivateSize( maSizeFT ); 750 } 751 FT_Error rc = FT_Set_Pixel_Sizes( maFaceFT, mnWidth, rFSD.mnHeight ); 752 if( rc != FT_Err_Ok ) 753 return; 754 755 // prepare for font encodings other than unicode or symbol 756 FT_Encoding eEncoding = FT_ENCODING_UNICODE; 757 if( mpFontInfo->IsSymbolFont() ) 758 { 759 #if (FTVERSION < 2000) 760 eEncoding = FT_ENCODING_NONE; 761 #else 762 if( FT_IS_SFNT( maFaceFT ) ) 763 eEncoding = ft_encoding_symbol; 764 else 765 eEncoding = FT_ENCODING_ADOBE_CUSTOM; // freetype wants this for PS symbol fonts 766 #endif 767 } 768 rc = FT_Select_Charmap( maFaceFT, eEncoding ); 769 // no standard encoding applies => we need an encoding converter 770 if( rc != FT_Err_Ok ) 771 { 772 rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE; 773 for( int i = maFaceFT->num_charmaps; --i >= 0; ) 774 { 775 const FT_CharMap aCM = maFaceFT->charmaps[i]; 776 if( aCM->platform_id == TT_PLATFORM_MICROSOFT ) 777 { 778 switch( aCM->encoding_id ) 779 { 780 case TT_MS_ID_SJIS: 781 eEncoding = FT_ENCODING_SJIS; 782 eRecodeFrom = RTL_TEXTENCODING_SHIFT_JIS; 783 break; 784 case TT_MS_ID_GB2312: 785 eEncoding = FT_ENCODING_GB2312; 786 eRecodeFrom = RTL_TEXTENCODING_GB_2312; 787 break; 788 case TT_MS_ID_BIG_5: 789 eEncoding = FT_ENCODING_BIG5; 790 eRecodeFrom = RTL_TEXTENCODING_BIG5; 791 break; 792 case TT_MS_ID_WANSUNG: 793 eEncoding = FT_ENCODING_WANSUNG; 794 eRecodeFrom = RTL_TEXTENCODING_MS_949; 795 break; 796 case TT_MS_ID_JOHAB: 797 eEncoding = FT_ENCODING_JOHAB; 798 eRecodeFrom = RTL_TEXTENCODING_MS_1361; 799 break; 800 } 801 } 802 else if( aCM->platform_id == TT_PLATFORM_MACINTOSH ) 803 { 804 switch( aCM->encoding_id ) 805 { 806 case TT_MAC_ID_ROMAN: 807 eEncoding = FT_ENCODING_APPLE_ROMAN; 808 eRecodeFrom = RTL_TEXTENCODING_UNICODE; // TODO: use better match 809 break; 810 // TODO: add other encodings when Mac-only 811 // non-unicode fonts show up 812 } 813 } 814 else if( aCM->platform_id == TT_PLATFORM_ADOBE ) 815 { 816 switch( aCM->encoding_id ) 817 { 818 #ifdef TT_ADOBE_ID_LATIN1 819 case TT_ADOBE_ID_LATIN1: // better unicode than nothing 820 eEncoding = FT_ENCODING_ADOBE_LATIN_1; 821 eRecodeFrom = RTL_TEXTENCODING_ISO_8859_1; 822 break; 823 #endif // TT_ADOBE_ID_LATIN1 824 case TT_ADOBE_ID_STANDARD: // better unicode than nothing 825 eEncoding = FT_ENCODING_ADOBE_STANDARD; 826 eRecodeFrom = RTL_TEXTENCODING_UNICODE; // TODO: use better match 827 break; 828 } 829 } 830 } 831 832 if( FT_Err_Ok != FT_Select_Charmap( maFaceFT, eEncoding ) ) 833 return; 834 835 if( eRecodeFrom != RTL_TEXTENCODING_UNICODE ) 836 maRecodeConverter = rtl_createUnicodeToTextConverter( eRecodeFrom ); 837 } 838 839 mbFaceOk = true; 840 841 ApplyGSUB( rFSD ); 842 843 // TODO: query GASP table for load flags 844 mnLoadFlags = FT_LOAD_DEFAULT; 845 #if 1 // #i97326# cairo sometimes uses FT_Set_Transform() on our FT_FACE 846 // we are not using FT_Set_Transform() yet, so just ignore it for now 847 mnLoadFlags |= FT_LOAD_IGNORE_TRANSFORM; 848 #endif 849 850 mbArtItalic = (rFSD.meItalic != ITALIC_NONE && pFI->GetFontAttributes().GetSlant() == ITALIC_NONE); 851 mbArtBold = (rFSD.meWeight > WEIGHT_MEDIUM && pFI->GetFontAttributes().GetWeight() <= WEIGHT_MEDIUM); 852 mbUseGamma = false; 853 if( mbArtBold ) 854 { 855 //static const int TT_CODEPAGE_RANGE_874 = (1L << 16); // Thai 856 //static const int TT_CODEPAGE_RANGE_932 = (1L << 17); // JIS/Japan 857 //static const int TT_CODEPAGE_RANGE_936 = (1L << 18); // Chinese: Simplified 858 //static const int TT_CODEPAGE_RANGE_949 = (1L << 19); // Korean Wansung 859 //static const int TT_CODEPAGE_RANGE_950 = (1L << 20); // Chinese: Traditional 860 //static const int TT_CODEPAGE_RANGE_1361 = (1L << 21); // Korean Johab 861 static const int TT_CODEPAGE_RANGES1_CJKT = 0x3F0000; // all of the above 862 const TT_OS2* pOs2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 ); 863 if ((pOs2) && (pOs2->ulCodePageRange1 & TT_CODEPAGE_RANGES1_CJKT ) 864 && rFSD.mnHeight < 20) 865 mbUseGamma = true; 866 } 867 868 if( ((mnCos != 0) && (mnSin != 0)) || (mnPrioEmbedded <= 0) ) 869 mnLoadFlags |= FT_LOAD_NO_BITMAP; 870 } 871 872 void FreetypeServerFont::SetFontOptions( const ImplFontOptions& rFontOptions) 873 { 874 FontAutoHint eHint = rFontOptions.GetUseAutoHint(); 875 if( eHint == AUTOHINT_DONTKNOW ) 876 eHint = mbUseGamma ? AUTOHINT_TRUE : AUTOHINT_FALSE; 877 878 if( eHint == AUTOHINT_TRUE ) 879 mnLoadFlags |= FT_LOAD_FORCE_AUTOHINT; 880 881 if( (mnSin != 0) && (mnCos != 0) ) // hinting for 0/90/180/270 degrees only 882 mnLoadFlags |= FT_LOAD_NO_HINTING; 883 mnLoadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; //#88334# 884 885 if( rFontOptions.DontUseAntiAlias() ) 886 mnPrioAntiAlias = 0; 887 if( rFontOptions.DontUseEmbeddedBitmaps() ) 888 mnPrioEmbedded = 0; 889 if( rFontOptions.DontUseHinting() ) 890 mnPrioAutoHint = 0; 891 892 #if (FTVERSION >= 2005) || defined(TT_CONFIG_OPTION_BYTECODE_INTERPRETER) 893 if( mnPrioAutoHint <= 0 ) 894 #endif 895 mnLoadFlags |= FT_LOAD_NO_HINTING; 896 897 #if defined(FT_LOAD_TARGET_LIGHT) && defined(FT_LOAD_TARGET_NORMAL) 898 if( !(mnLoadFlags & FT_LOAD_NO_HINTING) && (nFTVERSION >= 2103)) 899 { 900 mnLoadFlags |= FT_LOAD_TARGET_NORMAL; 901 switch( rFontOptions.GetHintStyle() ) 902 { 903 case HINT_NONE: 904 mnLoadFlags |= FT_LOAD_NO_HINTING; 905 break; 906 case HINT_SLIGHT: 907 mnLoadFlags |= FT_LOAD_TARGET_LIGHT; 908 break; 909 case HINT_MEDIUM: 910 break; 911 case HINT_FULL: 912 default: 913 break; 914 } 915 } 916 #endif 917 918 if( mnPrioEmbedded <= 0 ) 919 mnLoadFlags |= FT_LOAD_NO_BITMAP; 920 } 921 922 // ----------------------------------------------------------------------- 923 924 bool FreetypeServerFont::TestFont() const 925 { 926 return mbFaceOk; 927 } 928 929 // ----------------------------------------------------------------------- 930 931 FreetypeServerFont::~FreetypeServerFont() 932 { 933 if( mpLayoutEngine ) 934 delete mpLayoutEngine; 935 936 if( maRecodeConverter ) 937 rtl_destroyUnicodeToTextConverter( maRecodeConverter ); 938 939 if( maSizeFT ) 940 pFTDoneSize( maSizeFT ); 941 942 mpFontInfo->ReleaseFaceFT( maFaceFT ); 943 } 944 945 // ----------------------------------------------------------------------- 946 947 int FreetypeServerFont::GetEmUnits() const 948 { 949 return maFaceFT->units_per_EM; 950 } 951 952 // ----------------------------------------------------------------------- 953 954 void FreetypeServerFont::FetchFontMetric( ImplFontMetricData& rTo, long& rFactor ) const 955 { 956 static_cast<ImplFontAttributes&>(rTo) = mpFontInfo->GetFontAttributes(); 957 958 rTo.mbScalableFont = true; 959 rTo.mbDevice = true; 960 rTo.mbKernableFont = (FT_HAS_KERNING( maFaceFT ) != 0) || mpFontInfo->HasExtraKerning(); 961 rTo.mnOrientation = GetFontSelData().mnOrientation; 962 963 //Always consider [star]symbol as symbol fonts 964 if ( 965 (rTo.GetFamilyName().EqualsAscii("OpenSymbol")) || 966 (rTo.GetFamilyName().EqualsAscii("StarSymbol")) 967 ) 968 { 969 rTo.mbSymbolFlag = true; 970 } 971 972 if( maSizeFT ) 973 pFTActivateSize( maSizeFT ); 974 975 rFactor = 0x100; 976 977 rTo.mnWidth = mnWidth; 978 979 const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics; 980 rTo.mnAscent = (+rMetrics.ascender + 32) >> 6; 981 #if (FTVERSION < 2000) 982 rTo.mnDescent = (+rMetrics.descender + 32) >> 6; 983 #else 984 rTo.mnDescent = (-rMetrics.descender + 32) >> 6; 985 #endif 986 rTo.mnIntLeading = ((rMetrics.height + 32) >> 6) - (rTo.mnAscent + rTo.mnDescent); 987 rTo.mnSlant = 0; 988 989 const TT_OS2* pOS2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 ); 990 const TT_HoriHeader* pHHEA = (const TT_HoriHeader*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_hhea ); 991 if( pOS2 && (pOS2->version != 0xFFFF) ) 992 { 993 // map the panose info from the OS2 table to their VCL counterparts 994 switch( pOS2->panose[0] ) 995 { 996 case 1: rTo.meFamily = FAMILY_ROMAN; break; 997 case 2: rTo.meFamily = FAMILY_SWISS; break; 998 case 3: rTo.meFamily = FAMILY_MODERN; break; 999 case 4: rTo.meFamily = FAMILY_SCRIPT; break; 1000 case 5: rTo.meFamily = FAMILY_DECORATIVE; break; 1001 // TODO: is it reasonable to override the attribute with DONTKNOW? 1002 case 0: // fall through 1003 default: rTo.meFamilyType = FAMILY_DONTKNOW; break; 1004 } 1005 1006 switch( pOS2->panose[3] ) 1007 { 1008 case 2: // fall through 1009 case 3: // fall through 1010 case 4: // fall through 1011 case 5: // fall through 1012 case 6: // fall through 1013 case 7: // fall through 1014 case 8: rTo.mePitch = PITCH_VARIABLE; break; 1015 case 9: rTo.mePitch = PITCH_FIXED; break; 1016 // TODO: is it reasonable to override the attribute with DONTKNOW? 1017 case 0: // fall through 1018 case 1: // fall through 1019 default: rTo.mePitch = PITCH_DONTKNOW; break; 1020 } 1021 1022 // #108862# sanity check, some fonts treat descent as signed !!! 1023 int nDescent = pOS2->usWinDescent; 1024 if( nDescent > 5*maFaceFT->units_per_EM ) 1025 nDescent = (short)pOS2->usWinDescent; // interpret it as signed! 1026 1027 const double fScale = (double)GetFontSelData().mnHeight / maFaceFT->units_per_EM; 1028 if( pOS2->usWinAscent || pOS2->usWinDescent ) // #i30551# 1029 { 1030 rTo.mnAscent = (long)( +pOS2->usWinAscent * fScale + 0.5 ); 1031 rTo.mnDescent = (long)( +nDescent * fScale + 0.5 ); 1032 rTo.mnIntLeading = (long)( (+pOS2->usWinAscent + pOS2->usWinDescent - maFaceFT->units_per_EM) * fScale + 0.5 ); 1033 } 1034 rTo.mnExtLeading = 0; 1035 if( (pHHEA != NULL) && (pOS2->usWinAscent || pOS2->usWinDescent) ) 1036 { 1037 int nExtLeading = pHHEA->Line_Gap; 1038 nExtLeading -= (pOS2->usWinAscent + pOS2->usWinDescent); 1039 nExtLeading += (pHHEA->Ascender - pHHEA->Descender); 1040 if( nExtLeading > 0 ) 1041 rTo.mnExtLeading = (long)(nExtLeading * fScale + 0.5); 1042 } 1043 1044 // Check for CJK capabilities of the current font 1045 // #107888# workaround for Asian... 1046 // TODO: remove when ExtLeading fully implemented 1047 sal_Bool bCJKCapable = ((pOS2->ulUnicodeRange2 & 0x2DF00000) != 0); 1048 1049 if ( bCJKCapable && (pOS2->usWinAscent || pOS2->usWinDescent) ) 1050 { 1051 rTo.mnIntLeading += rTo.mnExtLeading; 1052 1053 // #109280# The line height for Asian fonts is too small. 1054 // Therefore we add half of the external leading to the 1055 // ascent, the other half is added to the descent. 1056 const long nHalfTmpExtLeading = rTo.mnExtLeading / 2; 1057 const long nOtherHalfTmpExtLeading = rTo.mnExtLeading - 1058 nHalfTmpExtLeading; 1059 1060 // #110641# external leading for Asian fonts. 1061 // The factor 0.3 has been verified during experiments. 1062 const long nCJKExtLeading = (long)(0.30 * (rTo.mnAscent + rTo.mnDescent)); 1063 1064 if ( nCJKExtLeading > rTo.mnExtLeading ) 1065 rTo.mnExtLeading = nCJKExtLeading - rTo.mnExtLeading; 1066 else 1067 rTo.mnExtLeading = 0; 1068 1069 rTo.mnAscent += nHalfTmpExtLeading; 1070 rTo.mnDescent += nOtherHalfTmpExtLeading; 1071 } 1072 } 1073 1074 // initialize kashida width 1075 // TODO: what if there are different versions of this glyph available 1076 rTo.mnMinKashida = rTo.mnAscent / 4; // a reasonable default 1077 const int nKashidaGlyphId = GetRawGlyphIndex( 0x0640 ); 1078 if( nKashidaGlyphId ) 1079 { 1080 GlyphData aGlyphData; 1081 InitGlyphData( nKashidaGlyphId, aGlyphData ); 1082 rTo.mnMinKashida = aGlyphData.GetMetric().GetCharWidth(); 1083 } 1084 } 1085 1086 // ----------------------------------------------------------------------- 1087 1088 static inline void SplitGlyphFlags( const FreetypeServerFont& rFont, int& nGlyphIndex, int& nGlyphFlags ) 1089 { 1090 nGlyphFlags = nGlyphIndex & GF_FLAGMASK; 1091 nGlyphIndex &= GF_IDXMASK; 1092 1093 if( nGlyphIndex & GF_ISCHAR ) 1094 nGlyphIndex = rFont.GetRawGlyphIndex( nGlyphIndex ); 1095 } 1096 1097 // ----------------------------------------------------------------------- 1098 1099 int FreetypeServerFont::ApplyGlyphTransform( int nGlyphFlags, 1100 FT_Glyph pGlyphFT, bool bForBitmapProcessing ) const 1101 { 1102 int nAngle = GetFontSelData().mnOrientation; 1103 // shortcut most common case 1104 if( !nAngle && !nGlyphFlags ) 1105 return nAngle; 1106 1107 const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics; 1108 FT_Vector aVector; 1109 FT_Matrix aMatrix; 1110 1111 bool bStretched = false; 1112 1113 switch( nGlyphFlags & GF_ROTMASK ) 1114 { 1115 default: // straight 1116 aVector.x = 0; 1117 aVector.y = 0; 1118 aMatrix.xx = +mnCos; 1119 aMatrix.yy = +mnCos; 1120 aMatrix.xy = -mnSin; 1121 aMatrix.yx = +mnSin; 1122 break; 1123 case GF_ROTL: // left 1124 nAngle += 900; 1125 bStretched = (mfStretch != 1.0); 1126 aVector.x = (FT_Pos)(+rMetrics.descender * mfStretch); 1127 aVector.y = -rMetrics.ascender; 1128 aMatrix.xx = (FT_Pos)(-mnSin / mfStretch); 1129 aMatrix.yy = (FT_Pos)(-mnSin * mfStretch); 1130 aMatrix.xy = (FT_Pos)(-mnCos * mfStretch); 1131 aMatrix.yx = (FT_Pos)(+mnCos / mfStretch); 1132 break; 1133 case GF_ROTR: // right 1134 nAngle -= 900; 1135 bStretched = (mfStretch != 1.0); 1136 aVector.x = -maFaceFT->glyph->metrics.horiAdvance; 1137 aVector.x += (FT_Pos)(rMetrics.descender * mnSin/65536.0); 1138 aVector.y = (FT_Pos)(-rMetrics.descender * mfStretch * mnCos/65536.0); 1139 aMatrix.xx = (FT_Pos)(+mnSin / mfStretch); 1140 aMatrix.yy = (FT_Pos)(+mnSin * mfStretch); 1141 aMatrix.xy = (FT_Pos)(+mnCos * mfStretch); 1142 aMatrix.yx = (FT_Pos)(-mnCos / mfStretch); 1143 break; 1144 } 1145 1146 while( nAngle < 0 ) 1147 nAngle += 3600; 1148 1149 if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP ) 1150 { 1151 FT_Glyph_Transform( pGlyphFT, NULL, &aVector ); 1152 1153 // orthogonal transforms are better handled by bitmap operations 1154 if( bStretched || (bForBitmapProcessing && (nAngle % 900) != 0) ) 1155 { 1156 // workaround for compatibility with older FT versions 1157 if( nFTVERSION < 2102 ) 1158 { 1159 FT_Fixed t = aMatrix.xy; 1160 aMatrix.xy = aMatrix.yx; 1161 aMatrix.yx = t; 1162 } 1163 1164 // apply non-orthogonal or stretch transformations 1165 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL ); 1166 nAngle = 0; 1167 } 1168 } 1169 else 1170 { 1171 // FT<=2005 ignores transforms for bitmaps, so do it manually 1172 FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<FT_BitmapGlyph>(pGlyphFT); 1173 pBmpGlyphFT->left += (aVector.x + 32) >> 6; 1174 pBmpGlyphFT->top += (aVector.y + 32) >> 6; 1175 } 1176 1177 return nAngle; 1178 } 1179 1180 // ----------------------------------------------------------------------- 1181 1182 int FreetypeServerFont::GetRawGlyphIndex( sal_UCS4 aChar ) const 1183 { 1184 if( mpFontInfo->IsSymbolFont() ) 1185 { 1186 if( !FT_IS_SFNT( maFaceFT ) ) 1187 { 1188 if( (aChar & 0xFF00) == 0xF000 ) 1189 aChar &= 0xFF; // PS font symbol mapping 1190 else if( aChar > 0xFF ) 1191 return 0; 1192 } 1193 } 1194 1195 // if needed recode from unicode to font encoding 1196 if( maRecodeConverter ) 1197 { 1198 sal_Char aTempArray[8]; 1199 sal_Size nTempSize; 1200 sal_uInt32 nCvtInfo; 1201 1202 // assume that modern UCS4 fonts have unicode CMAPs 1203 // => no encoding remapping to unicode is needed 1204 if( aChar > 0xFFFF ) 1205 return 0; 1206 1207 sal_Unicode aUCS2Char = static_cast<sal_Unicode>(aChar); 1208 rtl_UnicodeToTextContext aContext = rtl_createUnicodeToTextContext( maRecodeConverter ); 1209 int nChars = rtl_convertUnicodeToText( maRecodeConverter, aContext, 1210 &aUCS2Char, 1, aTempArray, sizeof(aTempArray), 1211 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_QUESTIONMARK 1212 | RTL_UNICODETOTEXT_FLAGS_INVALID_QUESTIONMARK, 1213 &nCvtInfo, &nTempSize ); 1214 rtl_destroyUnicodeToTextContext( maRecodeConverter, aContext ); 1215 1216 aChar = 0; 1217 for( int i = 0; i < nChars; ++i ) 1218 aChar = aChar*256 + (aTempArray[i] & 0xFF); 1219 } 1220 1221 // cache glyph indexes in font info to share between different sizes 1222 int nGlyphIndex = mpFontInfo->GetGlyphIndex( aChar ); 1223 if( nGlyphIndex < 0 ) 1224 { 1225 nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar ); 1226 if( !nGlyphIndex) 1227 { 1228 // check if symbol aliasing helps 1229 if( (aChar <= 0x00FF) && mpFontInfo->IsSymbolFont() ) 1230 nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar | 0xF000 ); 1231 #if 0 // disabled for now because it introduced ae bad side-effect (#i88376#) 1232 // Finally try the postscript name table 1233 if (!nGlyphIndex) 1234 nGlyphIndex = psp::PrintFontManager::get().FreeTypeCharIndex( maFaceFT, aChar ); 1235 #endif 1236 } 1237 mpFontInfo->CacheGlyphIndex( aChar, nGlyphIndex ); 1238 } 1239 1240 return nGlyphIndex; 1241 } 1242 1243 // ----------------------------------------------------------------------- 1244 1245 int FreetypeServerFont::FixupGlyphIndex( int nGlyphIndex, sal_UCS4 aChar ) const 1246 { 1247 int nGlyphFlags = GF_NONE; 1248 1249 // do glyph substitution if necessary 1250 // CJK vertical writing needs special treatment 1251 if( GetFontSelData().mbVertical ) 1252 { 1253 // TODO: rethink when GSUB is used for non-vertical case 1254 GlyphSubstitution::const_iterator it = maGlyphSubstitution.find( nGlyphIndex ); 1255 if( it == maGlyphSubstitution.end() ) 1256 { 1257 int nTemp = GetVerticalChar( aChar ); 1258 if( nTemp ) // is substitution possible 1259 nTemp = GetRawGlyphIndex( nTemp ); 1260 if( nTemp ) // substitute manually if sensible 1261 nGlyphIndex = nTemp | (GF_GSUB | GF_ROTL); 1262 else 1263 nGlyphFlags |= GetVerticalFlags( aChar ); 1264 } 1265 else 1266 { 1267 // for vertical GSUB also compensate for nOrientation=2700 1268 nGlyphIndex = (*it).second; 1269 nGlyphFlags |= GF_GSUB | GF_ROTL; 1270 } 1271 } 1272 1273 #if 0 1274 // #95556# autohinting not yet optimized for non-western glyph styles 1275 if( !(mnLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_FORCE_AUTOHINT) ) 1276 && ( (aChar >= 0x0600 && aChar < 0x1E00) // south-east asian + arabic 1277 ||(aChar >= 0x2900 && aChar < 0xD800) // CJKV 1278 ||(aChar >= 0xF800) ) ) // presentation + symbols 1279 { 1280 nGlyphFlags |= GF_UNHINTED; 1281 } 1282 #endif 1283 1284 if( nGlyphIndex != 0 ) 1285 nGlyphIndex |= nGlyphFlags; 1286 1287 return nGlyphIndex; 1288 } 1289 1290 1291 // ----------------------------------------------------------------------- 1292 1293 int FreetypeServerFont::GetGlyphIndex( sal_UCS4 aChar ) const 1294 { 1295 int nGlyphIndex = GetRawGlyphIndex( aChar ); 1296 nGlyphIndex = FixupGlyphIndex( nGlyphIndex, aChar ); 1297 return nGlyphIndex; 1298 } 1299 1300 // ----------------------------------------------------------------------- 1301 1302 static int lcl_GetCharWidth( FT_FaceRec_* pFaceFT, double fStretch, int nGlyphFlags ) 1303 { 1304 int nCharWidth = pFaceFT->glyph->metrics.horiAdvance; 1305 1306 if( nGlyphFlags & GF_ROTMASK ) // for bVertical rotated glyphs 1307 { 1308 const FT_Size_Metrics& rMetrics = pFaceFT->size->metrics; 1309 #if (FTVERSION < 2000) 1310 nCharWidth = (int)((rMetrics.height - rMetrics.descender) * fStretch); 1311 #else 1312 nCharWidth = (int)((rMetrics.height + rMetrics.descender) * fStretch); 1313 #endif 1314 } 1315 1316 return (nCharWidth + 32) >> 6; 1317 } 1318 1319 // ----------------------------------------------------------------------- 1320 1321 void FreetypeServerFont::InitGlyphData( int nGlyphIndex, GlyphData& rGD ) const 1322 { 1323 if( maSizeFT ) 1324 pFTActivateSize( maSizeFT ); 1325 1326 int nGlyphFlags; 1327 SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags ); 1328 1329 int nLoadFlags = mnLoadFlags; 1330 1331 // if( mbArtItalic ) 1332 // nLoadFlags |= FT_LOAD_NO_BITMAP; 1333 1334 FT_Error rc = -1; 1335 #if (FTVERSION <= 2008) 1336 // #88364# freetype<=2005 prefers autohinting to embedded bitmaps 1337 // => first we have to try without hinting 1338 if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 ) 1339 { 1340 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags|FT_LOAD_NO_HINTING ); 1341 if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format!=FT_GLYPH_FORMAT_BITMAP) ) 1342 rc = -1; // mark as "loading embedded bitmap" was unsuccessful 1343 nLoadFlags |= FT_LOAD_NO_BITMAP; 1344 } 1345 1346 if( rc != FT_Err_Ok ) 1347 #endif 1348 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags ); 1349 1350 if( rc != FT_Err_Ok ) 1351 { 1352 // we get here e.g. when a PS font lacks the default glyph 1353 rGD.SetCharWidth( 0 ); 1354 rGD.SetDelta( 0, 0 ); 1355 rGD.SetOffset( 0, 0 ); 1356 rGD.SetSize( Size( 0, 0 ) ); 1357 return; 1358 } 1359 1360 const bool bOriginallyZeroWidth = (maFaceFT->glyph->metrics.horiAdvance == 0); 1361 if( mbArtBold && pFTEmbolden ) 1362 (*pFTEmbolden)( maFaceFT->glyph ); 1363 1364 const int nCharWidth = bOriginallyZeroWidth ? 0 : lcl_GetCharWidth( maFaceFT, mfStretch, nGlyphFlags ); 1365 rGD.SetCharWidth( nCharWidth ); 1366 1367 FT_Glyph pGlyphFT; 1368 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT ); 1369 1370 ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false ); 1371 if( mbArtBold && pFTEmbolden && (nFTVERSION < 2200) ) // #i71094# workaround staircase bug 1372 pGlyphFT->advance.y = 0; 1373 rGD.SetDelta( (pGlyphFT->advance.x + 0x8000) >> 16, -((pGlyphFT->advance.y + 0x8000) >> 16) ); 1374 1375 FT_BBox aBbox; 1376 FT_Glyph_Get_CBox( pGlyphFT, FT_GLYPH_BBOX_PIXELS, &aBbox ); 1377 if( aBbox.yMin > aBbox.yMax ) // circumvent freetype bug 1378 { 1379 int t=aBbox.yMin; aBbox.yMin=aBbox.yMax, aBbox.yMax=t; 1380 } 1381 1382 rGD.SetOffset( aBbox.xMin, -aBbox.yMax ); 1383 rGD.SetSize( Size( (aBbox.xMax-aBbox.xMin+1), (aBbox.yMax-aBbox.yMin) ) ); 1384 1385 FT_Done_Glyph( pGlyphFT ); 1386 } 1387 1388 // ----------------------------------------------------------------------- 1389 1390 bool FreetypeServerFont::GetAntialiasAdvice( void ) const 1391 { 1392 if( GetFontSelData().mbNonAntialiased || (mnPrioAntiAlias<=0) ) 1393 return false; 1394 bool bAdviseAA = true; 1395 // TODO: also use GASP info 1396 return bAdviseAA; 1397 } 1398 1399 // ----------------------------------------------------------------------- 1400 1401 bool FreetypeServerFont::GetGlyphBitmap1( int nGlyphIndex, RawBitmap& rRawBitmap ) const 1402 { 1403 if( maSizeFT ) 1404 pFTActivateSize( maSizeFT ); 1405 1406 int nGlyphFlags; 1407 SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags ); 1408 1409 FT_Int nLoadFlags = mnLoadFlags; 1410 // #i70930# force mono-hinting for monochrome text 1411 if( nFTVERSION >= 2110 ) //#i71947# unless it looks worse 1412 { 1413 nLoadFlags &= ~0xF0000; 1414 nLoadFlags |= FT_LOAD_TARGET_MONO; 1415 } 1416 1417 if( mbArtItalic ) 1418 nLoadFlags |= FT_LOAD_NO_BITMAP; 1419 1420 #if (FTVERSION >= 2002) 1421 // for 0/90/180/270 degree fonts enable hinting even if not advisable 1422 // non-hinted and non-antialiased bitmaps just look too ugly 1423 if( (mnCos==0 || mnSin==0) && (mnPrioAutoHint > 0) ) 1424 nLoadFlags &= ~FT_LOAD_NO_HINTING; 1425 #endif 1426 1427 if( mnPrioEmbedded <= mnPrioAutoHint ) 1428 nLoadFlags |= FT_LOAD_NO_BITMAP; 1429 1430 FT_Error rc = -1; 1431 #if (FTVERSION <= 2008) 1432 // #88364# freetype<=2005 prefers autohinting to embedded bitmaps 1433 // => first we have to try without hinting 1434 if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 ) 1435 { 1436 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags|FT_LOAD_NO_HINTING ); 1437 if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format != FT_GLYPH_FORMAT_BITMAP) ) 1438 rc = -1; // mark as "loading embedded bitmap" was unsuccessful 1439 nLoadFlags |= FT_LOAD_NO_BITMAP; 1440 } 1441 1442 if( rc != FT_Err_Ok ) 1443 #endif 1444 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags ); 1445 if( rc != FT_Err_Ok ) 1446 return false; 1447 1448 if( mbArtBold && pFTEmbolden ) 1449 (*pFTEmbolden)( maFaceFT->glyph ); 1450 1451 FT_Glyph pGlyphFT; 1452 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT ); 1453 if( rc != FT_Err_Ok ) 1454 return false; 1455 1456 int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true ); 1457 1458 if( mbArtItalic ) 1459 { 1460 FT_Matrix aMatrix; 1461 aMatrix.xx = aMatrix.yy = 0x10000L; 1462 if( nFTVERSION >= 2102 ) // Freetype 2.1.2 API swapped xy with yx 1463 aMatrix.xy = 0x6000L, aMatrix.yx = 0; 1464 else 1465 aMatrix.yx = 0x6000L, aMatrix.xy = 0; 1466 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL ); 1467 } 1468 1469 // Check for zero area bounding boxes as this crashes some versions of FT. 1470 // This also provides a handy short cut as much of the code following 1471 // becomes an expensive nop when a glyph covers no pixels. 1472 FT_BBox cbox; 1473 FT_Glyph_Get_CBox(pGlyphFT, ft_glyph_bbox_unscaled, &cbox); 1474 1475 if( (cbox.xMax - cbox.xMin) == 0 || (cbox.yMax - cbox.yMin == 0) ) 1476 { 1477 nAngle = 0; 1478 memset(&rRawBitmap, 0, sizeof rRawBitmap); 1479 FT_Done_Glyph( pGlyphFT ); 1480 return true; 1481 } 1482 1483 if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP ) 1484 { 1485 if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE ) 1486 ((FT_OutlineGlyphRec*)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION; 1487 // #i15743# freetype API 2.1.3 changed the FT_RENDER_MODE_MONO constant 1488 FT_Render_Mode nRenderMode = (FT_Render_Mode)((nFTVERSION<2103) ? 1 : FT_RENDER_MODE_MONO); 1489 1490 rc = FT_Glyph_To_Bitmap( &pGlyphFT, nRenderMode, NULL, sal_True ); 1491 if( rc != FT_Err_Ok ) 1492 { 1493 FT_Done_Glyph( pGlyphFT ); 1494 return false; 1495 } 1496 } 1497 1498 const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT); 1499 // NOTE: autohinting in FT<=2.0.2 miscalculates the offsets below by +-1 1500 rRawBitmap.mnXOffset = +pBmpGlyphFT->left; 1501 rRawBitmap.mnYOffset = -pBmpGlyphFT->top; 1502 1503 const FT_Bitmap& rBitmapFT = pBmpGlyphFT->bitmap; 1504 rRawBitmap.mnHeight = rBitmapFT.rows; 1505 rRawBitmap.mnBitCount = 1; 1506 if( mbArtBold && !pFTEmbolden ) 1507 { 1508 rRawBitmap.mnWidth = rBitmapFT.width + 1; 1509 int nLineBytes = (rRawBitmap.mnWidth + 7) >> 3; 1510 rRawBitmap.mnScanlineSize = (nLineBytes > rBitmapFT.pitch) ? nLineBytes : rBitmapFT.pitch; 1511 } 1512 else 1513 { 1514 rRawBitmap.mnWidth = rBitmapFT.width; 1515 rRawBitmap.mnScanlineSize = rBitmapFT.pitch; 1516 } 1517 1518 const sal_uLong nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight; 1519 1520 if( rRawBitmap.mnAllocated < nNeededSize ) 1521 { 1522 delete[] rRawBitmap.mpBits; 1523 rRawBitmap.mnAllocated = 2*nNeededSize; 1524 rRawBitmap.mpBits = new unsigned char[ rRawBitmap.mnAllocated ]; 1525 } 1526 1527 if( !mbArtBold || pFTEmbolden ) 1528 { 1529 memcpy( rRawBitmap.mpBits, rBitmapFT.buffer, nNeededSize ); 1530 } 1531 else 1532 { 1533 memset( rRawBitmap.mpBits, 0, nNeededSize ); 1534 const unsigned char* pSrcLine = rBitmapFT.buffer; 1535 unsigned char* pDstLine = rRawBitmap.mpBits; 1536 for( int h = rRawBitmap.mnHeight; --h >= 0; ) 1537 { 1538 memcpy( pDstLine, pSrcLine, rBitmapFT.pitch ); 1539 pDstLine += rRawBitmap.mnScanlineSize; 1540 pSrcLine += rBitmapFT.pitch; 1541 } 1542 1543 unsigned char* p = rRawBitmap.mpBits; 1544 for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ ) 1545 { 1546 unsigned char nLastByte = 0; 1547 for( sal_uLong x=0; x < rRawBitmap.mnScanlineSize; x++ ) 1548 { 1549 unsigned char nTmp = p[x] << 7; 1550 p[x] |= (p[x] >> 1) | nLastByte; 1551 nLastByte = nTmp; 1552 } 1553 p += rRawBitmap.mnScanlineSize; 1554 } 1555 } 1556 1557 FT_Done_Glyph( pGlyphFT ); 1558 1559 // special case for 0/90/180/270 degree orientation 1560 switch( nAngle ) 1561 { 1562 case -900: 1563 case +900: 1564 case +1800: 1565 case +2700: 1566 rRawBitmap.Rotate( nAngle ); 1567 break; 1568 } 1569 1570 return true; 1571 } 1572 1573 // ----------------------------------------------------------------------- 1574 1575 bool FreetypeServerFont::GetGlyphBitmap8( int nGlyphIndex, RawBitmap& rRawBitmap ) const 1576 { 1577 if( maSizeFT ) 1578 pFTActivateSize( maSizeFT ); 1579 1580 int nGlyphFlags; 1581 SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags ); 1582 1583 FT_Int nLoadFlags = mnLoadFlags; 1584 1585 if( mbArtItalic ) 1586 nLoadFlags |= FT_LOAD_NO_BITMAP; 1587 1588 #if (FTVERSION <= 2004) && !defined(TT_CONFIG_OPTION_BYTECODE_INTERPRETER) 1589 // autohinting in FT<=2.0.4 makes antialiased glyphs look worse 1590 nLoadFlags |= FT_LOAD_NO_HINTING; 1591 #else 1592 if( (nGlyphFlags & GF_UNHINTED) || (mnPrioAutoHint < mnPrioAntiAlias) ) 1593 nLoadFlags |= FT_LOAD_NO_HINTING; 1594 #endif 1595 1596 if( mnPrioEmbedded <= mnPrioAntiAlias ) 1597 nLoadFlags |= FT_LOAD_NO_BITMAP; 1598 1599 FT_Error rc = -1; 1600 #if (FTVERSION <= 2008) 1601 // #88364# freetype<=2005 prefers autohinting to embedded bitmaps 1602 // => first we have to try without hinting 1603 if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 ) 1604 { 1605 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags|FT_LOAD_NO_HINTING ); 1606 if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format != FT_GLYPH_FORMAT_BITMAP) ) 1607 rc = -1; // mark as "loading embedded bitmap" was unsuccessful 1608 nLoadFlags |= FT_LOAD_NO_BITMAP; 1609 } 1610 1611 if( rc != FT_Err_Ok ) 1612 #endif 1613 rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags ); 1614 1615 if( rc != FT_Err_Ok ) 1616 return false; 1617 1618 if( mbArtBold && pFTEmbolden ) 1619 (*pFTEmbolden)( maFaceFT->glyph ); 1620 1621 FT_Glyph pGlyphFT; 1622 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT ); 1623 if( rc != FT_Err_Ok ) 1624 return false; 1625 1626 int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true ); 1627 1628 if( mbArtItalic ) 1629 { 1630 FT_Matrix aMatrix; 1631 aMatrix.xx = aMatrix.yy = 0x10000L; 1632 if( nFTVERSION >= 2102 ) // Freetype 2.1.2 API swapped xy with yx 1633 aMatrix.xy = 0x6000L, aMatrix.yx = 0; 1634 else 1635 aMatrix.yx = 0x6000L, aMatrix.xy = 0; 1636 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL ); 1637 } 1638 1639 if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE ) 1640 ((FT_OutlineGlyph)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION; 1641 1642 bool bEmbedded = (pGlyphFT->format == FT_GLYPH_FORMAT_BITMAP); 1643 if( !bEmbedded ) 1644 { 1645 rc = FT_Glyph_To_Bitmap( &pGlyphFT, FT_RENDER_MODE_NORMAL, NULL, sal_True ); 1646 if( rc != FT_Err_Ok ) 1647 { 1648 FT_Done_Glyph( pGlyphFT ); 1649 return false; 1650 } 1651 } 1652 1653 const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT); 1654 rRawBitmap.mnXOffset = +pBmpGlyphFT->left; 1655 rRawBitmap.mnYOffset = -pBmpGlyphFT->top; 1656 1657 const FT_Bitmap& rBitmapFT = pBmpGlyphFT->bitmap; 1658 rRawBitmap.mnHeight = rBitmapFT.rows; 1659 rRawBitmap.mnWidth = rBitmapFT.width; 1660 rRawBitmap.mnBitCount = 8; 1661 rRawBitmap.mnScanlineSize = bEmbedded ? rBitmapFT.width : rBitmapFT.pitch; 1662 if( mbArtBold && !pFTEmbolden ) 1663 { 1664 ++rRawBitmap.mnWidth; 1665 ++rRawBitmap.mnScanlineSize; 1666 } 1667 rRawBitmap.mnScanlineSize = (rRawBitmap.mnScanlineSize + 3) & -4; 1668 1669 const sal_uLong nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight; 1670 if( rRawBitmap.mnAllocated < nNeededSize ) 1671 { 1672 delete[] rRawBitmap.mpBits; 1673 rRawBitmap.mnAllocated = 2*nNeededSize; 1674 rRawBitmap.mpBits = new unsigned char[ rRawBitmap.mnAllocated ]; 1675 } 1676 1677 const unsigned char* pSrc = rBitmapFT.buffer; 1678 unsigned char* pDest = rRawBitmap.mpBits; 1679 if( !bEmbedded ) 1680 { 1681 for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; ) 1682 { 1683 for( x = 0; x < rBitmapFT.width; ++x ) 1684 *(pDest++) = *(pSrc++); 1685 for(; x < int(rRawBitmap.mnScanlineSize); ++x ) 1686 *(pDest++) = 0; 1687 } 1688 } 1689 else 1690 { 1691 for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; ) 1692 { 1693 unsigned char nSrc = 0; 1694 for( x = 0; x < rBitmapFT.width; ++x, nSrc+=nSrc ) 1695 { 1696 if( (x & 7) == 0 ) 1697 nSrc = *(pSrc++); 1698 *(pDest++) = (0x7F - nSrc) >> 8; 1699 } 1700 for(; x < int(rRawBitmap.mnScanlineSize); ++x ) 1701 *(pDest++) = 0; 1702 } 1703 } 1704 1705 if( mbArtBold && !pFTEmbolden ) 1706 { 1707 // overlay with glyph image shifted by one left pixel 1708 unsigned char* p = rRawBitmap.mpBits; 1709 for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ ) 1710 { 1711 unsigned char nLastByte = 0; 1712 for( sal_uLong x=0; x < rRawBitmap.mnWidth; x++ ) 1713 { 1714 unsigned char nTmp = p[x]; 1715 p[x] |= p[x] | nLastByte; 1716 nLastByte = nTmp; 1717 } 1718 p += rRawBitmap.mnScanlineSize; 1719 } 1720 } 1721 1722 if( !bEmbedded && mbUseGamma ) 1723 { 1724 unsigned char* p = rRawBitmap.mpBits; 1725 for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ ) 1726 { 1727 for( sal_uLong x=0; x < rRawBitmap.mnWidth; x++ ) 1728 { 1729 p[x] = aGammaTable[ p[x] ]; 1730 } 1731 p += rRawBitmap.mnScanlineSize; 1732 } 1733 } 1734 1735 FT_Done_Glyph( pGlyphFT ); 1736 1737 // special case for 0/90/180/270 degree orientation 1738 switch( nAngle ) 1739 { 1740 case -900: 1741 case +900: 1742 case +1800: 1743 case +2700: 1744 rRawBitmap.Rotate( nAngle ); 1745 break; 1746 } 1747 1748 return true; 1749 } 1750 1751 // ----------------------------------------------------------------------- 1752 // determine unicode ranges in font 1753 // ----------------------------------------------------------------------- 1754 1755 const ImplFontCharMap* FreetypeServerFont::GetImplFontCharMap( void ) const 1756 { 1757 const ImplFontCharMap* pIFCMap = mpFontInfo->GetImplFontCharMap(); 1758 return pIFCMap; 1759 } 1760 1761 const ImplFontCharMap* FtFontInfo::GetImplFontCharMap( void ) 1762 { 1763 // check if the charmap is already cached 1764 if( mpFontCharMap ) 1765 return mpFontCharMap; 1766 1767 // get the charmap and cache it 1768 CmapResult aCmapResult; 1769 bool bOK = GetFontCodeRanges( aCmapResult ); 1770 if( bOK ) 1771 mpFontCharMap = new ImplFontCharMap( aCmapResult ); 1772 else 1773 mpFontCharMap = ImplFontCharMap::GetDefaultMap(); 1774 mpFontCharMap->AddReference(); 1775 return mpFontCharMap; 1776 } 1777 1778 // TODO: merge into method GetFontCharMap() 1779 bool FtFontInfo::GetFontCodeRanges( CmapResult& rResult ) const 1780 { 1781 rResult.mbSymbolic = IsSymbolFont(); 1782 1783 // TODO: is the full CmapResult needed on platforms calling this? 1784 if( FT_IS_SFNT( maFaceFT ) ) 1785 { 1786 sal_uLong nLength = 0; 1787 const unsigned char* pCmap = GetTable( "cmap", &nLength ); 1788 if( pCmap && (nLength > 0) ) 1789 if( ParseCMAP( pCmap, nLength, rResult ) ) 1790 return true; 1791 } 1792 1793 typedef std::vector<sal_uInt32> U32Vector; 1794 U32Vector aCodes; 1795 1796 // FT's coverage is available since FT>=2.1.0 (OOo-baseline>=2.1.4 => ok) 1797 aCodes.reserve( 0x1000 ); 1798 FT_UInt nGlyphIndex; 1799 for( sal_uInt32 cCode = FT_Get_First_Char( maFaceFT, &nGlyphIndex );; ) 1800 { 1801 if( !nGlyphIndex ) 1802 break; 1803 aCodes.push_back( cCode ); // first code inside range 1804 sal_uInt32 cNext = cCode; 1805 do cNext = FT_Get_Next_Char( maFaceFT, cCode, &nGlyphIndex ); while( cNext == ++cCode ); 1806 aCodes.push_back( cCode ); // first code outside range 1807 cCode = cNext; 1808 } 1809 1810 const int nCount = aCodes.size(); 1811 if( !nCount) { 1812 if( !rResult.mbSymbolic ) 1813 return false; 1814 1815 // we usually get here for Type1 symbol fonts 1816 aCodes.push_back( 0xF020 ); 1817 aCodes.push_back( 0xF100 ); 1818 } 1819 1820 sal_uInt32* pCodes = new sal_uInt32[ nCount ]; 1821 for( int i = 0; i < nCount; ++i ) 1822 pCodes[i] = aCodes[i]; 1823 rResult.mpRangeCodes = pCodes; 1824 rResult.mnRangeCount = nCount / 2; 1825 return true; 1826 } 1827 1828 // ----------------------------------------------------------------------- 1829 // kerning stuff 1830 // ----------------------------------------------------------------------- 1831 1832 int FreetypeServerFont::GetGlyphKernValue( int nGlyphLeft, int nGlyphRight ) const 1833 { 1834 // if no kerning info is available from Freetype 1835 // then we may have to use extra info provided by e.g. psprint 1836 if( !FT_HAS_KERNING( maFaceFT ) || !FT_IS_SFNT( maFaceFT ) ) 1837 { 1838 int nKernVal = mpFontInfo->GetExtraGlyphKernValue( nGlyphLeft, nGlyphRight ); 1839 if( !nKernVal ) 1840 return 0; 1841 // scale the kern value to match the font size 1842 const ImplFontSelectData& rFSD = GetFontSelData(); 1843 nKernVal *= rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight; 1844 return (nKernVal + 500) / 1000; 1845 } 1846 1847 // when font faces of different sizes share the same maFaceFT 1848 // then we have to make sure that it uses the correct maSizeFT 1849 if( maSizeFT ) 1850 pFTActivateSize( maSizeFT ); 1851 1852 // use Freetype's kerning info 1853 FT_Vector aKernVal; 1854 FT_Error rcFT = FT_Get_Kerning( maFaceFT, nGlyphLeft, nGlyphRight, 1855 FT_KERNING_DEFAULT, &aKernVal ); 1856 int nResult = (rcFT == FT_Err_Ok) ? (aKernVal.x + 32) >> 6 : 0; 1857 return nResult; 1858 } 1859 1860 // ----------------------------------------------------------------------- 1861 1862 sal_uLong FreetypeServerFont::GetKernPairs( ImplKernPairData** ppKernPairs ) const 1863 { 1864 // if no kerning info is available in the font file 1865 *ppKernPairs = NULL; 1866 if( !FT_HAS_KERNING( maFaceFT ) || !FT_IS_SFNT( maFaceFT ) ) 1867 { 1868 // then we have may have extra kerning info from e.g. psprint 1869 int nCount = mpFontInfo->GetExtraKernPairs( ppKernPairs ); 1870 // scale the kern values to match the font size 1871 const ImplFontSelectData& rFSD = GetFontSelData(); 1872 int nFontWidth = rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight; 1873 ImplKernPairData* pKernPair = *ppKernPairs; 1874 for( int i = nCount; --i >= 0; ++pKernPair ) 1875 { 1876 long& rVal = pKernPair->mnKern; 1877 rVal = ((rVal * nFontWidth) + 500) / 1000; 1878 } 1879 return nCount; 1880 } 1881 1882 // when font faces of different sizes share the same maFaceFT 1883 // then we have to make sure that it uses the correct maSizeFT 1884 if( maSizeFT ) 1885 pFTActivateSize( maSizeFT ); 1886 1887 // first figure out which glyph pairs are involved in kerning 1888 sal_uLong nKernLength = 0; 1889 const FT_Byte* const pKern = mpFontInfo->GetTable( "kern", &nKernLength ); 1890 if( !pKern ) 1891 return 0; 1892 1893 // combine TTF/OTF tables from the font file to build a vector of 1894 // unicode kerning pairs using Freetype's glyph kerning calculation 1895 // for the kerning value 1896 1897 // TODO: is it worth to share the glyph->unicode mapping between 1898 // different instances of the same font face? 1899 1900 typedef std::vector<ImplKernPairData> KernVector; 1901 KernVector aKernGlyphVector; 1902 ImplKernPairData aKernPair; 1903 aKernPair.mnKern = 0; // To prevent "is used uninitialized" warning... 1904 1905 const FT_Byte* pBuffer = pKern; 1906 sal_uLong nVersion = GetUShort( pBuffer+0 ); 1907 sal_uInt16 nTableCnt = GetUShort( pBuffer+2 ); 1908 1909 // Microsoft/Old TrueType style kern table 1910 if ( nVersion == 0 ) 1911 { 1912 pBuffer += 4; 1913 1914 for( sal_uInt16 nTableIdx = 0; nTableIdx < nTableCnt; ++nTableIdx ) 1915 { 1916 // sal_uInt16 nSubVersion = GetUShort( pBuffer+0 ); 1917 // sal_uInt16 nSubLength = GetUShort( pBuffer+2 ); 1918 sal_uInt16 nSubCoverage = GetUShort( pBuffer+4 ); 1919 pBuffer += 6; 1920 if( (nSubCoverage&0x03) != 0x01 ) // no interest in minimum info here 1921 continue; 1922 switch( nSubCoverage >> 8 ) 1923 { 1924 case 0: // version 0, kerning format 0 1925 { 1926 sal_uInt16 nPairs = GetUShort( pBuffer ); 1927 pBuffer += 8; // skip search hints 1928 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs ); 1929 for( int i = 0; i < nPairs; ++i ) 1930 { 1931 aKernPair.mnChar1 = GetUShort( pBuffer+0 ); 1932 aKernPair.mnChar2 = GetUShort( pBuffer+2 ); 1933 //long nUnscaledKern= GetSShort( pBuffer ); 1934 pBuffer += 6; 1935 aKernGlyphVector.push_back( aKernPair ); 1936 } 1937 } 1938 break; 1939 1940 case 2: // version 0, kerning format 2 1941 { 1942 const FT_Byte* pSubTable = pBuffer; 1943 //sal_uInt16 nRowWidth = GetUShort( pBuffer+0 ); 1944 sal_uInt16 nOfsLeft = GetUShort( pBuffer+2 ); 1945 sal_uInt16 nOfsRight = GetUShort( pBuffer+4 ); 1946 sal_uInt16 nOfsArray = GetUShort( pBuffer+6 ); 1947 pBuffer += 8; 1948 1949 const FT_Byte* pTmp = pSubTable + nOfsLeft; 1950 sal_uInt16 nFirstLeft = GetUShort( pTmp+0 ); 1951 sal_uInt16 nLastLeft = GetUShort( pTmp+2 ) + nFirstLeft - 1; 1952 1953 pTmp = pSubTable + nOfsRight; 1954 sal_uInt16 nFirstRight = GetUShort( pTmp+0 ); 1955 sal_uInt16 nLastRight = GetUShort( pTmp+2 ) + nFirstRight - 1; 1956 1957 sal_uLong nPairs = (sal_uLong)(nLastLeft - nFirstLeft + 1) * (nLastRight - nFirstRight + 1); 1958 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs ); 1959 1960 pTmp = pSubTable + nOfsArray; 1961 for( int nLeft = nFirstLeft; nLeft < nLastLeft; ++nLeft ) 1962 { 1963 aKernPair.mnChar1 = nLeft; 1964 for( int nRight = 0; nRight < nLastRight; ++nRight ) 1965 { 1966 if( GetUShort( pTmp ) != 0 ) 1967 { 1968 aKernPair.mnChar2 = nRight; 1969 aKernGlyphVector.push_back( aKernPair ); 1970 } 1971 pTmp += 2; 1972 } 1973 } 1974 } 1975 break; 1976 } 1977 } 1978 } 1979 1980 // Apple New style kern table 1981 pBuffer = pKern; 1982 nVersion = NEXT_U32( pBuffer ); 1983 nTableCnt = NEXT_U32( pBuffer ); 1984 if ( nVersion == 0x00010000 ) 1985 { 1986 for( sal_uInt16 nTableIdx = 0; nTableIdx < nTableCnt; ++nTableIdx ) 1987 { 1988 /*sal_uLong nLength =*/ NEXT_U32( pBuffer ); 1989 sal_uInt16 nCoverage = NEXT_U16( pBuffer ); 1990 /*sal_uInt16 nTupleIndex =*/ NEXT_U16( pBuffer ); 1991 1992 // Kerning sub-table format, 0 through 3 1993 sal_uInt8 nSubTableFormat = nCoverage & 0x00FF; 1994 1995 switch( nSubTableFormat ) 1996 { 1997 case 0: // version 0, kerning format 0 1998 { 1999 sal_uInt16 nPairs = NEXT_U16( pBuffer ); 2000 pBuffer += 6; // skip search hints 2001 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs ); 2002 for( int i = 0; i < nPairs; ++i ) 2003 { 2004 aKernPair.mnChar1 = NEXT_U16( pBuffer ); 2005 aKernPair.mnChar2 = NEXT_U16( pBuffer ); 2006 /*long nUnscaledKern=*/ NEXT_S16( pBuffer ); 2007 aKernGlyphVector.push_back( aKernPair ); 2008 } 2009 } 2010 break; 2011 2012 case 2: // version 0, kerning format 2 2013 { 2014 const FT_Byte* pSubTable = pBuffer; 2015 /*sal_uInt16 nRowWidth =*/ NEXT_U16( pBuffer ); 2016 sal_uInt16 nOfsLeft = NEXT_U16( pBuffer ); 2017 sal_uInt16 nOfsRight = NEXT_U16( pBuffer ); 2018 sal_uInt16 nOfsArray = NEXT_U16( pBuffer ); 2019 2020 const FT_Byte* pTmp = pSubTable + nOfsLeft; 2021 sal_uInt16 nFirstLeft = NEXT_U16( pTmp ); 2022 sal_uInt16 nLastLeft = NEXT_U16( pTmp ) + nFirstLeft - 1; 2023 2024 pTmp = pSubTable + nOfsRight; 2025 sal_uInt16 nFirstRight = NEXT_U16( pTmp ); 2026 sal_uInt16 nLastRight = NEXT_U16( pTmp ) + nFirstRight - 1; 2027 2028 sal_uLong nPairs = (sal_uLong)(nLastLeft - nFirstLeft + 1) * (nLastRight - nFirstRight + 1); 2029 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs ); 2030 2031 pTmp = pSubTable + nOfsArray; 2032 for( int nLeft = nFirstLeft; nLeft < nLastLeft; ++nLeft ) 2033 { 2034 aKernPair.mnChar1 = nLeft; 2035 for( int nRight = 0; nRight < nLastRight; ++nRight ) 2036 { 2037 if( NEXT_S16( pTmp ) != 0 ) 2038 { 2039 aKernPair.mnChar2 = nRight; 2040 aKernGlyphVector.push_back( aKernPair ); 2041 } 2042 } 2043 } 2044 } 2045 break; 2046 2047 default: 2048 fprintf( stderr, "gcach_ftyp.cxx: Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat ); 2049 break; 2050 } 2051 } 2052 } 2053 2054 // now create VCL's ImplKernPairData[] format for all glyph pairs 2055 sal_uLong nKernCount = aKernGlyphVector.size(); 2056 if( nKernCount ) 2057 { 2058 // prepare glyphindex to character mapping 2059 // TODO: this is needed to support VCL's existing kerning infrastructure, 2060 // eliminate it up by redesigning kerning infrastructure to work with glyph indizes 2061 typedef std::hash_multimap<sal_uInt16,sal_Unicode> Cmap; 2062 Cmap aCmap; 2063 for( sal_Unicode aChar = 0x0020; aChar < 0xFFFE; ++aChar ) 2064 { 2065 sal_uInt16 nGlyphIndex = GetGlyphIndex( aChar ); 2066 if( nGlyphIndex ) 2067 aCmap.insert( Cmap::value_type( nGlyphIndex, aChar ) ); 2068 } 2069 2070 // translate both glyph indizes in kerning pairs to characters 2071 // problem is that these are 1:n mappings... 2072 KernVector aKernCharVector; 2073 aKernCharVector.reserve( nKernCount ); 2074 KernVector::iterator it; 2075 for( it = aKernGlyphVector.begin(); it != aKernGlyphVector.end(); ++it ) 2076 { 2077 FT_Vector aKernVal; 2078 FT_Error rcFT = FT_Get_Kerning( maFaceFT, it->mnChar1, it->mnChar2, 2079 FT_KERNING_DEFAULT, &aKernVal ); 2080 aKernPair.mnKern = aKernVal.x >> 6; 2081 if( (aKernPair.mnKern == 0) || (rcFT != FT_Err_Ok) ) 2082 continue; 2083 2084 typedef std::pair<Cmap::iterator,Cmap::iterator> CPair; 2085 const CPair p1 = aCmap.equal_range( it->mnChar1 ); 2086 const CPair p2 = aCmap.equal_range( it->mnChar2 ); 2087 for( Cmap::const_iterator i1 = p1.first; i1 != p1.second; ++i1 ) 2088 { 2089 aKernPair.mnChar1 = (*i1).second; 2090 for( Cmap::const_iterator i2 = p2.first; i2 != p2.second; ++i2 ) 2091 { 2092 aKernPair.mnChar2 = (*i2).second; 2093 aKernCharVector.push_back( aKernPair ); 2094 } 2095 } 2096 } 2097 2098 // now move the resulting vector into VCL's ImplKernPairData[] format 2099 nKernCount = aKernCharVector.size(); 2100 ImplKernPairData* pTo = new ImplKernPairData[ nKernCount ]; 2101 *ppKernPairs = pTo; 2102 for( it = aKernCharVector.begin(); it != aKernCharVector.end(); ++it, ++pTo ) 2103 { 2104 pTo->mnChar1 = it->mnChar1; 2105 pTo->mnChar2 = it->mnChar2; 2106 pTo->mnKern = it->mnKern; 2107 } 2108 } 2109 2110 return nKernCount; 2111 } 2112 2113 // ----------------------------------------------------------------------- 2114 // outline stuff 2115 // ----------------------------------------------------------------------- 2116 2117 class PolyArgs 2118 { 2119 public: 2120 PolyArgs( PolyPolygon& rPolyPoly, sal_uInt16 nMaxPoints ); 2121 ~PolyArgs(); 2122 2123 void AddPoint( long nX, long nY, PolyFlags); 2124 void ClosePolygon(); 2125 2126 long GetPosX() const { return maPosition.x;} 2127 long GetPosY() const { return maPosition.y;} 2128 2129 private: 2130 PolyPolygon& mrPolyPoly; 2131 2132 Point* mpPointAry; 2133 sal_uInt8* mpFlagAry; 2134 2135 FT_Vector maPosition; 2136 sal_uInt16 mnMaxPoints; 2137 sal_uInt16 mnPoints; 2138 sal_uInt16 mnPoly; 2139 long mnHeight; 2140 bool bHasOffline; 2141 }; 2142 2143 // ----------------------------------------------------------------------- 2144 2145 PolyArgs::PolyArgs( PolyPolygon& rPolyPoly, sal_uInt16 nMaxPoints ) 2146 : mrPolyPoly(rPolyPoly), 2147 mnMaxPoints(nMaxPoints), 2148 mnPoints(0), 2149 mnPoly(0), 2150 bHasOffline(false) 2151 { 2152 mpPointAry = new Point[ mnMaxPoints ]; 2153 mpFlagAry = new sal_uInt8 [ mnMaxPoints ]; 2154 } 2155 2156 // ----------------------------------------------------------------------- 2157 2158 2159 PolyArgs::~PolyArgs() 2160 { 2161 delete[] mpFlagAry; 2162 delete[] mpPointAry; 2163 } 2164 2165 // ----------------------------------------------------------------------- 2166 2167 void PolyArgs::AddPoint( long nX, long nY, PolyFlags aFlag ) 2168 { 2169 DBG_ASSERT( (mnPoints < mnMaxPoints), "FTGlyphOutline: AddPoint overflow!" ); 2170 if( mnPoints >= mnMaxPoints ) 2171 return; 2172 2173 maPosition.x = nX; 2174 maPosition.y = nY; 2175 mpPointAry[ mnPoints ] = Point( nX, nY ); 2176 mpFlagAry[ mnPoints++ ]= aFlag; 2177 bHasOffline |= (aFlag != POLY_NORMAL); 2178 } 2179 2180 // ----------------------------------------------------------------------- 2181 2182 void PolyArgs::ClosePolygon() 2183 { 2184 if( !mnPoly++ ) 2185 return; 2186 2187 // freetype seems to always close the polygon with an ON_CURVE point 2188 // PolyPoly wants to close the polygon itself => remove last point 2189 DBG_ASSERT( (mnPoints >= 2), "FTGlyphOutline: PolyFinishNum failed!" ); 2190 --mnPoints; 2191 DBG_ASSERT( (mpPointAry[0]==mpPointAry[mnPoints]), "FTGlyphOutline: PolyFinishEq failed!" ); 2192 DBG_ASSERT( (mpFlagAry[0]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFE failed!" ); 2193 DBG_ASSERT( (mpFlagAry[mnPoints]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFS failed!" ); 2194 2195 Polygon aPoly( mnPoints, mpPointAry, (bHasOffline ? mpFlagAry : NULL) ); 2196 2197 // #i35928# 2198 // This may be a invalid polygons, e.g. the last point is a control point. 2199 // So close the polygon (and add the first point again) if the last point 2200 // is a control point or different from first. 2201 // #i48298# 2202 // Now really duplicating the first point, to close or correct the 2203 // polygon. Also no longer duplicating the flags, but enforcing 2204 // POLY_NORMAL for the newly added last point. 2205 const sal_uInt16 nPolySize(aPoly.GetSize()); 2206 if(nPolySize) 2207 { 2208 if((aPoly.HasFlags() && POLY_CONTROL == aPoly.GetFlags(nPolySize - 1)) 2209 || (aPoly.GetPoint(nPolySize - 1) != aPoly.GetPoint(0))) 2210 { 2211 aPoly.SetSize(nPolySize + 1); 2212 aPoly.SetPoint(aPoly.GetPoint(0), nPolySize); 2213 2214 if(aPoly.HasFlags()) 2215 { 2216 aPoly.SetFlags(nPolySize, POLY_NORMAL); 2217 } 2218 } 2219 } 2220 2221 mrPolyPoly.Insert( aPoly ); 2222 mnPoints = 0; 2223 bHasOffline = false; 2224 } 2225 2226 // ----------------------------------------------------------------------- 2227 2228 extern "C" { 2229 2230 // TODO: wait till all compilers accept that calling conventions 2231 // for functions are the same independent of implementation constness, 2232 // then uncomment the const-tokens in the function interfaces below 2233 static int FT_move_to( FT_Vector_CPtr p0, void* vpPolyArgs ) 2234 { 2235 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs); 2236 2237 // move_to implies a new polygon => finish old polygon first 2238 rA.ClosePolygon(); 2239 2240 rA.AddPoint( p0->x, p0->y, POLY_NORMAL ); 2241 return 0; 2242 } 2243 2244 static int FT_line_to( FT_Vector_CPtr p1, void* vpPolyArgs ) 2245 { 2246 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs); 2247 rA.AddPoint( p1->x, p1->y, POLY_NORMAL ); 2248 return 0; 2249 } 2250 2251 static int FT_conic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, void* vpPolyArgs ) 2252 { 2253 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs); 2254 2255 // VCL's Polygon only knows cubic beziers 2256 const long nX1 = (2 * rA.GetPosX() + 4 * p1->x + 3) / 6; 2257 const long nY1 = (2 * rA.GetPosY() + 4 * p1->y + 3) / 6; 2258 rA.AddPoint( nX1, nY1, POLY_CONTROL ); 2259 2260 const long nX2 = (2 * p2->x + 4 * p1->x + 3) / 6; 2261 const long nY2 = (2 * p2->y + 4 * p1->y + 3) / 6; 2262 rA.AddPoint( nX2, nY2, POLY_CONTROL ); 2263 2264 rA.AddPoint( p2->x, p2->y, POLY_NORMAL ); 2265 return 0; 2266 } 2267 2268 static int FT_cubic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, FT_Vector_CPtr p3, void* vpPolyArgs ) 2269 { 2270 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs); 2271 rA.AddPoint( p1->x, p1->y, POLY_CONTROL ); 2272 rA.AddPoint( p2->x, p2->y, POLY_CONTROL ); 2273 rA.AddPoint( p3->x, p3->y, POLY_NORMAL ); 2274 return 0; 2275 } 2276 2277 } // extern "C" 2278 2279 // ----------------------------------------------------------------------- 2280 2281 bool FreetypeServerFont::GetGlyphOutline( int nGlyphIndex, 2282 ::basegfx::B2DPolyPolygon& rB2DPolyPoly ) const 2283 { 2284 if( maSizeFT ) 2285 pFTActivateSize( maSizeFT ); 2286 2287 rB2DPolyPoly.clear(); 2288 2289 int nGlyphFlags; 2290 SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags ); 2291 2292 FT_Int nLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM; 2293 2294 #ifdef FT_LOAD_TARGET_LIGHT 2295 // enable "light hinting" if available 2296 if( nFTVERSION >= 2103 ) 2297 nLoadFlags |= FT_LOAD_TARGET_LIGHT; 2298 #endif 2299 2300 FT_Error rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags ); 2301 if( rc != FT_Err_Ok ) 2302 return false; 2303 2304 if( mbArtBold && pFTEmbolden ) 2305 (*pFTEmbolden)( maFaceFT->glyph ); 2306 2307 FT_Glyph pGlyphFT; 2308 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT ); 2309 if( rc != FT_Err_Ok ) 2310 return false; 2311 2312 if( pGlyphFT->format != FT_GLYPH_FORMAT_OUTLINE ) 2313 return false; 2314 2315 if( mbArtItalic ) 2316 { 2317 FT_Matrix aMatrix; 2318 aMatrix.xx = aMatrix.yy = 0x10000L; 2319 if( nFTVERSION >= 2102 ) // Freetype 2.1.2 API swapped xy with yx 2320 aMatrix.xy = 0x6000L, aMatrix.yx = 0; 2321 else 2322 aMatrix.yx = 0x6000L, aMatrix.xy = 0; 2323 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL ); 2324 } 2325 2326 FT_Outline& rOutline = reinterpret_cast<FT_OutlineGlyphRec*>(pGlyphFT)->outline; 2327 if( !rOutline.n_points ) // blank glyphs are ok 2328 return true; 2329 2330 long nMaxPoints = 1 + rOutline.n_points * 3; 2331 PolyPolygon aToolPolyPolygon; 2332 PolyArgs aPolyArg( aToolPolyPolygon, nMaxPoints ); 2333 2334 /*int nAngle =*/ ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false ); 2335 2336 FT_Outline_Funcs aFuncs; 2337 aFuncs.move_to = &FT_move_to; 2338 aFuncs.line_to = &FT_line_to; 2339 aFuncs.conic_to = &FT_conic_to; 2340 aFuncs.cubic_to = &FT_cubic_to; 2341 aFuncs.shift = 0; 2342 aFuncs.delta = 0; 2343 rc = FT_Outline_Decompose( &rOutline, &aFuncs, (void*)&aPolyArg ); 2344 aPolyArg.ClosePolygon(); // close last polygon 2345 FT_Done_Glyph( pGlyphFT ); 2346 2347 // convert to basegfx polypolygon 2348 // TODO: get rid of the intermediate tools polypolygon 2349 rB2DPolyPoly = aToolPolyPolygon.getB2DPolyPolygon(); 2350 rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix( +1.0/(1<<6), -1.0/(1<<6) )); 2351 2352 return true; 2353 } 2354 2355 // ----------------------------------------------------------------------- 2356 2357 bool FreetypeServerFont::ApplyGSUB( const ImplFontSelectData& rFSD ) 2358 { 2359 #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3]) 2360 2361 typedef std::vector<sal_uLong> ReqFeatureTagList; 2362 ReqFeatureTagList aReqFeatureTagList; 2363 if( rFSD.mbVertical ) 2364 aReqFeatureTagList.push_back( MKTAG("vert") ); 2365 sal_uLong nRequestedScript = 0; //MKTAG("hani");//### TODO: where to get script? 2366 sal_uLong nRequestedLangsys = 0; //MKTAG("ZHT"); //### TODO: where to get langsys? 2367 // TODO: request more features depending on script and language system 2368 2369 if( aReqFeatureTagList.size() == 0) // nothing to do 2370 return true; 2371 2372 // load GSUB table into memory 2373 sal_uLong nLength = 0; 2374 const FT_Byte* const pGsubBase = mpFontInfo->GetTable( "GSUB", &nLength ); 2375 if( !pGsubBase ) 2376 return false; 2377 2378 // parse GSUB header 2379 const FT_Byte* pGsubHeader = pGsubBase; 2380 const sal_uInt16 nOfsScriptList = GetUShort( pGsubHeader+4 ); 2381 const sal_uInt16 nOfsFeatureTable = GetUShort( pGsubHeader+6 ); 2382 const sal_uInt16 nOfsLookupList = GetUShort( pGsubHeader+8 ); 2383 pGsubHeader += 10; 2384 2385 typedef std::vector<sal_uInt16> UshortList; 2386 UshortList aFeatureIndexList; 2387 UshortList aFeatureOffsetList; 2388 2389 // parse Script Table 2390 const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList; 2391 const sal_uInt16 nCntScript = GetUShort( pScriptHeader+0 ); 2392 pScriptHeader += 2; 2393 for( sal_uInt16 nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex ) 2394 { 2395 const sal_uLong nScriptTag = GetUInt( pScriptHeader+0 ); // e.g. hani/arab/kana/hang 2396 const sal_uInt16 nOfsScriptTable= GetUShort( pScriptHeader+4 ); 2397 pScriptHeader += 6; //### 2398 if( (nScriptTag != nRequestedScript) && (nRequestedScript != 0) ) 2399 continue; 2400 2401 const FT_Byte* pScriptTable = pGsubBase + nOfsScriptList + nOfsScriptTable; 2402 const sal_uInt16 nDefaultLangsysOfs = GetUShort( pScriptTable+0 ); 2403 const sal_uInt16 nCntLangSystem = GetUShort( pScriptTable+2 ); 2404 pScriptTable += 4; 2405 sal_uInt16 nLangsysOffset = 0; 2406 2407 for( sal_uInt16 nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex ) 2408 { 2409 const sal_uLong nTag = GetUInt( pScriptTable+0 ); // e.g. KOR/ZHS/ZHT/JAN 2410 const sal_uInt16 nOffset= GetUShort( pScriptTable+4 ); 2411 pScriptTable += 6; 2412 if( (nTag != nRequestedLangsys) && (nRequestedLangsys != 0) ) 2413 continue; 2414 nLangsysOffset = nOffset; 2415 break; 2416 } 2417 2418 if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) ) 2419 { 2420 const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs; 2421 const sal_uInt16 nReqFeatureIdx = GetUShort( pLangSys+2 ); 2422 const sal_uInt16 nCntFeature = GetUShort( pLangSys+4 ); 2423 pLangSys += 6; 2424 aFeatureIndexList.push_back( nReqFeatureIdx ); 2425 for( sal_uInt16 i = 0; i < nCntFeature; ++i ) 2426 { 2427 const sal_uInt16 nFeatureIndex = GetUShort( pLangSys ); 2428 pLangSys += 2; 2429 aFeatureIndexList.push_back( nFeatureIndex ); 2430 } 2431 } 2432 2433 if( nLangsysOffset != 0 ) 2434 { 2435 const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset; 2436 const sal_uInt16 nReqFeatureIdx = GetUShort( pLangSys+2 ); 2437 const sal_uInt16 nCntFeature = GetUShort( pLangSys+4 ); 2438 pLangSys += 6; 2439 aFeatureIndexList.push_back( nReqFeatureIdx ); 2440 for( sal_uInt16 i = 0; i < nCntFeature; ++i ) 2441 { 2442 const sal_uInt16 nFeatureIndex = GetUShort( pLangSys ); 2443 pLangSys += 2; 2444 aFeatureIndexList.push_back( nFeatureIndex ); 2445 } 2446 } 2447 } 2448 2449 if( !aFeatureIndexList.size() ) 2450 return true; 2451 2452 UshortList aLookupIndexList; 2453 UshortList aLookupOffsetList; 2454 2455 // parse Feature Table 2456 const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable; 2457 const sal_uInt16 nCntFeature = GetUShort( pFeatureHeader ); 2458 pFeatureHeader += 2; 2459 for( sal_uInt16 nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex ) 2460 { 2461 const sal_uLong nTag = GetUInt( pFeatureHeader+0 ); // e.g. locl/vert/trad/smpl/liga/fina/... 2462 const sal_uInt16 nOffset= GetUShort( pFeatureHeader+4 ); 2463 pFeatureHeader += 6; 2464 2465 // short circuit some feature lookups 2466 if( aFeatureIndexList[0] != nFeatureIndex ) // required feature? 2467 { 2468 const int nRequested = std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex); 2469 if( !nRequested ) // ignore features that are not requested 2470 continue; 2471 const int nAvailable = std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag); 2472 if( !nAvailable ) // some fonts don't provide features they request! 2473 continue; 2474 } 2475 2476 const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset; 2477 const sal_uInt16 nCntLookups = GetUShort( pFeatureTable+0 ); 2478 pFeatureTable += 2; 2479 for( sal_uInt16 i = 0; i < nCntLookups; ++i ) 2480 { 2481 const sal_uInt16 nLookupIndex = GetUShort( pFeatureTable ); 2482 pFeatureTable += 2; 2483 aLookupIndexList.push_back( nLookupIndex ); 2484 } 2485 if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/... 2486 aLookupIndexList.push_back( 0 ); 2487 } 2488 2489 // parse Lookup List 2490 const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList; 2491 const sal_uInt16 nCntLookupTable = GetUShort( pLookupHeader ); 2492 pLookupHeader += 2; 2493 for( sal_uInt16 nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx ) 2494 { 2495 const sal_uInt16 nOffset = GetUShort( pLookupHeader ); 2496 pLookupHeader += 2; 2497 if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) ) 2498 aLookupOffsetList.push_back( nOffset ); 2499 } 2500 2501 UshortList::const_iterator lookup_it = aLookupOffsetList.begin(); 2502 for(; lookup_it != aLookupOffsetList.end(); ++lookup_it ) 2503 { 2504 const sal_uInt16 nOfsLookupTable = *lookup_it; 2505 const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable; 2506 const sal_uInt16 eLookupType = GetUShort( pLookupTable+0 ); 2507 const sal_uInt16 nCntLookupSubtable = GetUShort( pLookupTable+4 ); 2508 pLookupTable += 6; 2509 2510 // TODO: switch( eLookupType ) 2511 if( eLookupType != 1 ) // TODO: once we go beyond SingleSubst 2512 continue; 2513 2514 for( sal_uInt16 nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx ) 2515 { 2516 const sal_uInt16 nOfsSubLookupTable = GetUShort( pLookupTable ); 2517 pLookupTable += 2; 2518 const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable; 2519 2520 const sal_uInt16 nFmtSubstitution = GetUShort( pSubLookup+0 ); 2521 const sal_uInt16 nOfsCoverage = GetUShort( pSubLookup+2 ); 2522 pSubLookup += 4; 2523 2524 typedef std::pair<sal_uInt16,sal_uInt16> GlyphSubst; 2525 typedef std::vector<GlyphSubst> SubstVector; 2526 SubstVector aSubstVector; 2527 2528 const FT_Byte* pCoverage = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage; 2529 const sal_uInt16 nFmtCoverage = GetUShort( pCoverage+0 ); 2530 pCoverage += 2; 2531 switch( nFmtCoverage ) 2532 { 2533 case 1: // Coverage Format 1 2534 { 2535 const sal_uInt16 nCntGlyph = GetUShort( pCoverage ); 2536 pCoverage += 2; 2537 aSubstVector.reserve( nCntGlyph ); 2538 for( sal_uInt16 i = 0; i < nCntGlyph; ++i ) 2539 { 2540 const sal_uInt16 nGlyphId = GetUShort( pCoverage ); 2541 pCoverage += 2; 2542 aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) ); 2543 } 2544 } 2545 break; 2546 2547 case 2: // Coverage Format 2 2548 { 2549 const sal_uInt16 nCntRange = GetUShort( pCoverage ); 2550 pCoverage += 2; 2551 for( int i = nCntRange; --i >= 0; ) 2552 { 2553 const sal_uInt32 nGlyph0 = GetUShort( pCoverage+0 ); 2554 const sal_uInt32 nGlyph1 = GetUShort( pCoverage+2 ); 2555 const sal_uInt16 nCovIdx = GetUShort( pCoverage+4 ); 2556 pCoverage += 6; 2557 for( sal_uInt32 j = nGlyph0; j <= nGlyph1; ++j ) 2558 aSubstVector.push_back( GlyphSubst( static_cast<sal_uInt16>(j + nCovIdx), 0 ) ); 2559 } 2560 } 2561 break; 2562 } 2563 2564 SubstVector::iterator it( aSubstVector.begin() ); 2565 2566 switch( nFmtSubstitution ) 2567 { 2568 case 1: // Single Substitution Format 1 2569 { 2570 const sal_uInt16 nDeltaGlyphId = GetUShort( pSubLookup ); 2571 pSubLookup += 2; 2572 for(; it != aSubstVector.end(); ++it ) 2573 (*it).second = (*it).first + nDeltaGlyphId; 2574 } 2575 break; 2576 2577 case 2: // Single Substitution Format 2 2578 { 2579 const sal_uInt16 nCntGlyph = GetUShort( pSubLookup ); 2580 pSubLookup += 2; 2581 for( int i = nCntGlyph; (it != aSubstVector.end()) && (--i>=0); ++it ) 2582 { 2583 const sal_uInt16 nGlyphId = GetUShort( pSubLookup ); 2584 pSubLookup += 2; 2585 (*it).second = nGlyphId; 2586 } 2587 } 2588 break; 2589 } 2590 2591 DBG_ASSERT( (it == aSubstVector.end()), "lookup<->coverage table mismatch" ); 2592 // now apply the glyph substitutions that have been collected in this subtable 2593 for( it = aSubstVector.begin(); it != aSubstVector.end(); ++it ) 2594 maGlyphSubstitution[ (*it).first ] = (*it).second; 2595 } 2596 } 2597 2598 return true; 2599 } 2600 2601 // ======================================================================= 2602 2603