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