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