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, vt=%d, sy=%d) => %d\n", 725 pFI->GetFontFileName()->getStr(), rFSD.mnHeight, rFSD.mnWidth, rFSD.mbVertical, 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 if( rc != FT_Err_Ok ) 1365 { 1366 // we get here e.g. when a PS font lacks the default glyph 1367 rGD.SetCharWidth( 0 ); 1368 rGD.SetDelta( 0, 0 ); 1369 rGD.SetOffset( 0, 0 ); 1370 rGD.SetSize( Size( 0, 0 ) ); 1371 return; 1372 } 1373 1374 ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false ); 1375 if( mbArtBold && pFTEmbolden && (nFTVERSION < 2200) ) // #i71094# workaround staircase bug 1376 pGlyphFT->advance.y = 0; 1377 rGD.SetDelta( (pGlyphFT->advance.x + 0x8000) >> 16, -((pGlyphFT->advance.y + 0x8000) >> 16) ); 1378 1379 FT_BBox aBbox; 1380 FT_Glyph_Get_CBox( pGlyphFT, FT_GLYPH_BBOX_PIXELS, &aBbox ); 1381 if( aBbox.yMin > aBbox.yMax ) // circumvent freetype bug 1382 { 1383 int t=aBbox.yMin; aBbox.yMin=aBbox.yMax, aBbox.yMax=t; 1384 } 1385 1386 rGD.SetOffset( aBbox.xMin, -aBbox.yMax ); 1387 rGD.SetSize( Size( (aBbox.xMax-aBbox.xMin+1), (aBbox.yMax-aBbox.yMin) ) ); 1388 1389 FT_Done_Glyph( pGlyphFT ); 1390 } 1391 1392 // ----------------------------------------------------------------------- 1393 1394 bool FreetypeServerFont::GetAntialiasAdvice( void ) const 1395 { 1396 if( GetFontSelData().mbNonAntialiased || (mnPrioAntiAlias<=0) ) 1397 return false; 1398 bool bAdviseAA = true; 1399 // TODO: also use GASP info 1400 return bAdviseAA; 1401 } 1402 1403 // ----------------------------------------------------------------------- 1404 1405 bool FreetypeServerFont::GetGlyphBitmap1( sal_GlyphId aGlyphId, RawBitmap& rRawBitmap ) const 1406 { 1407 if( maSizeFT ) 1408 pFTActivateSize( maSizeFT ); 1409 1410 int nGlyphFlags; 1411 SplitGlyphFlags( *this, aGlyphId, nGlyphFlags ); 1412 1413 FT_Int nLoadFlags = mnLoadFlags; 1414 // #i70930# force mono-hinting for monochrome text 1415 if( nFTVERSION >= 2110 ) //#i71947# unless it looks worse 1416 { 1417 nLoadFlags &= ~0xF0000; 1418 nLoadFlags |= FT_LOAD_TARGET_MONO; 1419 } 1420 1421 if( mbArtItalic ) 1422 nLoadFlags |= FT_LOAD_NO_BITMAP; 1423 1424 #if (FTVERSION >= 2002) 1425 // for 0/90/180/270 degree fonts enable hinting even if not advisable 1426 // non-hinted and non-antialiased bitmaps just look too ugly 1427 if( (mnCos==0 || mnSin==0) && (mnPrioAutoHint > 0) ) 1428 nLoadFlags &= ~FT_LOAD_NO_HINTING; 1429 #endif 1430 1431 if( mnPrioEmbedded <= mnPrioAutoHint ) 1432 nLoadFlags |= FT_LOAD_NO_BITMAP; 1433 1434 FT_Error rc = -1; 1435 #if (FTVERSION <= 2008) 1436 // #88364# freetype<=2005 prefers autohinting to embedded bitmaps 1437 // => first we have to try without hinting 1438 if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 ) 1439 { 1440 rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags|FT_LOAD_NO_HINTING ); 1441 if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format != FT_GLYPH_FORMAT_BITMAP) ) 1442 rc = -1; // mark as "loading embedded bitmap" was unsuccessful 1443 nLoadFlags |= FT_LOAD_NO_BITMAP; 1444 } 1445 1446 if( rc != FT_Err_Ok ) 1447 #endif 1448 rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags ); 1449 if( rc != FT_Err_Ok ) 1450 return false; 1451 1452 if( mbArtBold && pFTEmbolden ) 1453 (*pFTEmbolden)( maFaceFT->glyph ); 1454 1455 FT_Glyph pGlyphFT; 1456 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT ); 1457 if( rc != FT_Err_Ok ) 1458 return false; 1459 1460 int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true ); 1461 1462 if( mbArtItalic ) 1463 { 1464 FT_Matrix aMatrix; 1465 aMatrix.xx = aMatrix.yy = 0x10000L; 1466 if( nFTVERSION >= 2102 ) // Freetype 2.1.2 API swapped xy with yx 1467 aMatrix.xy = 0x6000L, aMatrix.yx = 0; 1468 else 1469 aMatrix.yx = 0x6000L, aMatrix.xy = 0; 1470 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL ); 1471 } 1472 1473 // Check for zero area bounding boxes as this crashes some versions of FT. 1474 // This also provides a handy short cut as much of the code following 1475 // becomes an expensive nop when a glyph covers no pixels. 1476 FT_BBox cbox; 1477 FT_Glyph_Get_CBox(pGlyphFT, ft_glyph_bbox_unscaled, &cbox); 1478 1479 if( (cbox.xMax - cbox.xMin) == 0 || (cbox.yMax - cbox.yMin == 0) ) 1480 { 1481 nAngle = 0; 1482 memset(&rRawBitmap, 0, sizeof rRawBitmap); 1483 FT_Done_Glyph( pGlyphFT ); 1484 return true; 1485 } 1486 1487 if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP ) 1488 { 1489 if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE ) 1490 ((FT_OutlineGlyphRec*)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION; 1491 // #i15743# freetype API 2.1.3 changed the FT_RENDER_MODE_MONO constant 1492 FT_Render_Mode nRenderMode = (FT_Render_Mode)((nFTVERSION<2103) ? 1 : FT_RENDER_MODE_MONO); 1493 1494 rc = FT_Glyph_To_Bitmap( &pGlyphFT, nRenderMode, NULL, sal_True ); 1495 if( rc != FT_Err_Ok ) 1496 { 1497 FT_Done_Glyph( pGlyphFT ); 1498 return false; 1499 } 1500 } 1501 1502 const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT); 1503 // NOTE: autohinting in FT<=2.0.2 miscalculates the offsets below by +-1 1504 rRawBitmap.mnXOffset = +pBmpGlyphFT->left; 1505 rRawBitmap.mnYOffset = -pBmpGlyphFT->top; 1506 1507 const FT_Bitmap& rBitmapFT = pBmpGlyphFT->bitmap; 1508 rRawBitmap.mnHeight = rBitmapFT.rows; 1509 rRawBitmap.mnBitCount = 1; 1510 if( mbArtBold && !pFTEmbolden ) 1511 { 1512 rRawBitmap.mnWidth = rBitmapFT.width + 1; 1513 int nLineBytes = (rRawBitmap.mnWidth + 7) >> 3; 1514 rRawBitmap.mnScanlineSize = (nLineBytes > rBitmapFT.pitch) ? nLineBytes : rBitmapFT.pitch; 1515 } 1516 else 1517 { 1518 rRawBitmap.mnWidth = rBitmapFT.width; 1519 rRawBitmap.mnScanlineSize = rBitmapFT.pitch; 1520 } 1521 1522 const sal_uLong nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight; 1523 1524 if( rRawBitmap.mnAllocated < nNeededSize ) 1525 { 1526 delete[] rRawBitmap.mpBits; 1527 rRawBitmap.mnAllocated = 2*nNeededSize; 1528 rRawBitmap.mpBits = new unsigned char[ rRawBitmap.mnAllocated ]; 1529 } 1530 1531 if( !mbArtBold || pFTEmbolden ) 1532 { 1533 memcpy( rRawBitmap.mpBits, rBitmapFT.buffer, nNeededSize ); 1534 } 1535 else 1536 { 1537 memset( rRawBitmap.mpBits, 0, nNeededSize ); 1538 const unsigned char* pSrcLine = rBitmapFT.buffer; 1539 unsigned char* pDstLine = rRawBitmap.mpBits; 1540 for( int h = rRawBitmap.mnHeight; --h >= 0; ) 1541 { 1542 memcpy( pDstLine, pSrcLine, rBitmapFT.pitch ); 1543 pDstLine += rRawBitmap.mnScanlineSize; 1544 pSrcLine += rBitmapFT.pitch; 1545 } 1546 1547 unsigned char* p = rRawBitmap.mpBits; 1548 for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ ) 1549 { 1550 unsigned char nLastByte = 0; 1551 for( sal_uLong x=0; x < rRawBitmap.mnScanlineSize; x++ ) 1552 { 1553 unsigned char nTmp = p[x] << 7; 1554 p[x] |= (p[x] >> 1) | nLastByte; 1555 nLastByte = nTmp; 1556 } 1557 p += rRawBitmap.mnScanlineSize; 1558 } 1559 } 1560 1561 FT_Done_Glyph( pGlyphFT ); 1562 1563 // special case for 0/90/180/270 degree orientation 1564 switch( nAngle ) 1565 { 1566 case -900: 1567 case +900: 1568 case +1800: 1569 case +2700: 1570 rRawBitmap.Rotate( nAngle ); 1571 break; 1572 } 1573 1574 return true; 1575 } 1576 1577 // ----------------------------------------------------------------------- 1578 1579 bool FreetypeServerFont::GetGlyphBitmap8( sal_GlyphId aGlyphId, RawBitmap& rRawBitmap ) const 1580 { 1581 if( maSizeFT ) 1582 pFTActivateSize( maSizeFT ); 1583 1584 int nGlyphFlags; 1585 SplitGlyphFlags( *this, aGlyphId, nGlyphFlags ); 1586 1587 FT_Int nLoadFlags = mnLoadFlags; 1588 1589 if( mbArtItalic ) 1590 nLoadFlags |= FT_LOAD_NO_BITMAP; 1591 1592 #if (FTVERSION <= 2004) && !defined(TT_CONFIG_OPTION_BYTECODE_INTERPRETER) 1593 // autohinting in FT<=2.0.4 makes antialiased glyphs look worse 1594 nLoadFlags |= FT_LOAD_NO_HINTING; 1595 #else 1596 if( (nGlyphFlags & GF_UNHINTED) || (mnPrioAutoHint < mnPrioAntiAlias) ) 1597 nLoadFlags |= FT_LOAD_NO_HINTING; 1598 #endif 1599 1600 if( mnPrioEmbedded <= mnPrioAntiAlias ) 1601 nLoadFlags |= FT_LOAD_NO_BITMAP; 1602 1603 FT_Error rc = -1; 1604 #if (FTVERSION <= 2008) 1605 // #88364# freetype<=2005 prefers autohinting to embedded bitmaps 1606 // => first we have to try without hinting 1607 if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 ) 1608 { 1609 rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags|FT_LOAD_NO_HINTING ); 1610 if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format != FT_GLYPH_FORMAT_BITMAP) ) 1611 rc = -1; // mark as "loading embedded bitmap" was unsuccessful 1612 nLoadFlags |= FT_LOAD_NO_BITMAP; 1613 } 1614 1615 if( rc != FT_Err_Ok ) 1616 #endif 1617 rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags ); 1618 1619 if( rc != FT_Err_Ok ) 1620 return false; 1621 1622 if( mbArtBold && pFTEmbolden ) 1623 (*pFTEmbolden)( maFaceFT->glyph ); 1624 1625 FT_Glyph pGlyphFT; 1626 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT ); 1627 if( rc != FT_Err_Ok ) 1628 return false; 1629 1630 int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true ); 1631 1632 if( mbArtItalic ) 1633 { 1634 FT_Matrix aMatrix; 1635 aMatrix.xx = aMatrix.yy = 0x10000L; 1636 if( nFTVERSION >= 2102 ) // Freetype 2.1.2 API swapped xy with yx 1637 aMatrix.xy = 0x6000L, aMatrix.yx = 0; 1638 else 1639 aMatrix.yx = 0x6000L, aMatrix.xy = 0; 1640 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL ); 1641 } 1642 1643 if( pGlyphFT->format == FT_GLYPH_FORMAT_OUTLINE ) 1644 ((FT_OutlineGlyph)pGlyphFT)->outline.flags |= FT_OUTLINE_HIGH_PRECISION; 1645 1646 bool bEmbedded = (pGlyphFT->format == FT_GLYPH_FORMAT_BITMAP); 1647 if( !bEmbedded ) 1648 { 1649 rc = FT_Glyph_To_Bitmap( &pGlyphFT, FT_RENDER_MODE_NORMAL, NULL, sal_True ); 1650 if( rc != FT_Err_Ok ) 1651 { 1652 FT_Done_Glyph( pGlyphFT ); 1653 return false; 1654 } 1655 } 1656 1657 const FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<const FT_BitmapGlyph>(pGlyphFT); 1658 rRawBitmap.mnXOffset = +pBmpGlyphFT->left; 1659 rRawBitmap.mnYOffset = -pBmpGlyphFT->top; 1660 1661 const FT_Bitmap& rBitmapFT = pBmpGlyphFT->bitmap; 1662 rRawBitmap.mnHeight = rBitmapFT.rows; 1663 rRawBitmap.mnWidth = rBitmapFT.width; 1664 rRawBitmap.mnBitCount = 8; 1665 rRawBitmap.mnScanlineSize = bEmbedded ? rBitmapFT.width : rBitmapFT.pitch; 1666 if( mbArtBold && !pFTEmbolden ) 1667 { 1668 ++rRawBitmap.mnWidth; 1669 ++rRawBitmap.mnScanlineSize; 1670 } 1671 rRawBitmap.mnScanlineSize = (rRawBitmap.mnScanlineSize + 3) & -4; 1672 1673 const sal_uLong nNeededSize = rRawBitmap.mnScanlineSize * rRawBitmap.mnHeight; 1674 if( rRawBitmap.mnAllocated < nNeededSize ) 1675 { 1676 delete[] rRawBitmap.mpBits; 1677 rRawBitmap.mnAllocated = 2*nNeededSize; 1678 rRawBitmap.mpBits = new unsigned char[ rRawBitmap.mnAllocated ]; 1679 } 1680 1681 const unsigned char* pSrc = rBitmapFT.buffer; 1682 unsigned char* pDest = rRawBitmap.mpBits; 1683 if( !bEmbedded ) 1684 { 1685 for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; ) 1686 { 1687 for( x = 0; x < rBitmapFT.width; ++x ) 1688 *(pDest++) = *(pSrc++); 1689 for(; x < int(rRawBitmap.mnScanlineSize); ++x ) 1690 *(pDest++) = 0; 1691 } 1692 } 1693 else 1694 { 1695 for( int y = rRawBitmap.mnHeight, x; --y >= 0 ; ) 1696 { 1697 unsigned char nSrc = 0; 1698 for( x = 0; x < rBitmapFT.width; ++x, nSrc+=nSrc ) 1699 { 1700 if( (x & 7) == 0 ) 1701 nSrc = *(pSrc++); 1702 *(pDest++) = (0x7F - nSrc) >> 8; 1703 } 1704 for(; x < int(rRawBitmap.mnScanlineSize); ++x ) 1705 *(pDest++) = 0; 1706 } 1707 } 1708 1709 if( mbArtBold && !pFTEmbolden ) 1710 { 1711 // overlay with glyph image shifted by one left pixel 1712 unsigned char* p = rRawBitmap.mpBits; 1713 for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ ) 1714 { 1715 unsigned char nLastByte = 0; 1716 for( sal_uLong x=0; x < rRawBitmap.mnWidth; x++ ) 1717 { 1718 unsigned char nTmp = p[x]; 1719 p[x] |= p[x] | nLastByte; 1720 nLastByte = nTmp; 1721 } 1722 p += rRawBitmap.mnScanlineSize; 1723 } 1724 } 1725 1726 if( !bEmbedded && mbUseGamma ) 1727 { 1728 unsigned char* p = rRawBitmap.mpBits; 1729 for( sal_uLong y=0; y < rRawBitmap.mnHeight; y++ ) 1730 { 1731 for( sal_uLong x=0; x < rRawBitmap.mnWidth; x++ ) 1732 { 1733 p[x] = aGammaTable[ p[x] ]; 1734 } 1735 p += rRawBitmap.mnScanlineSize; 1736 } 1737 } 1738 1739 FT_Done_Glyph( pGlyphFT ); 1740 1741 // special case for 0/90/180/270 degree orientation 1742 switch( nAngle ) 1743 { 1744 case -900: 1745 case +900: 1746 case +1800: 1747 case +2700: 1748 rRawBitmap.Rotate( nAngle ); 1749 break; 1750 } 1751 1752 return true; 1753 } 1754 1755 // ----------------------------------------------------------------------- 1756 // determine unicode ranges in font 1757 // ----------------------------------------------------------------------- 1758 1759 const ImplFontCharMap* FreetypeServerFont::GetImplFontCharMap( void ) const 1760 { 1761 const ImplFontCharMap* pIFCMap = mpFontInfo->GetImplFontCharMap(); 1762 return pIFCMap; 1763 } 1764 1765 const ImplFontCharMap* FtFontInfo::GetImplFontCharMap( void ) 1766 { 1767 // check if the charmap is already cached 1768 if( mpFontCharMap ) 1769 return mpFontCharMap; 1770 1771 // get the charmap and cache it 1772 CmapResult aCmapResult; 1773 bool bOK = GetFontCodeRanges( aCmapResult ); 1774 if( bOK ) 1775 mpFontCharMap = new ImplFontCharMap( aCmapResult ); 1776 else 1777 mpFontCharMap = ImplFontCharMap::GetDefaultMap(); 1778 mpFontCharMap->AddReference(); 1779 return mpFontCharMap; 1780 } 1781 1782 // TODO: merge into method GetFontCharMap() 1783 bool FtFontInfo::GetFontCodeRanges( CmapResult& rResult ) const 1784 { 1785 rResult.mbSymbolic = IsSymbolFont(); 1786 1787 // TODO: is the full CmapResult needed on platforms calling this? 1788 if( FT_IS_SFNT( maFaceFT ) ) 1789 { 1790 sal_uLong nLength = 0; 1791 const unsigned char* pCmap = GetTable( "cmap", &nLength ); 1792 if( pCmap && (nLength > 0) ) 1793 if( ParseCMAP( pCmap, nLength, rResult ) ) 1794 return true; 1795 } 1796 1797 typedef std::vector<sal_uInt32> U32Vector; 1798 U32Vector aCodes; 1799 1800 // FT's coverage is available since FT>=2.1.0 (OOo-baseline>=2.1.4 => ok) 1801 aCodes.reserve( 0x1000 ); 1802 FT_UInt nGlyphIndex; 1803 for( sal_uInt32 cCode = FT_Get_First_Char( maFaceFT, &nGlyphIndex );; ) 1804 { 1805 if( !nGlyphIndex ) 1806 break; 1807 aCodes.push_back( cCode ); // first code inside range 1808 sal_uInt32 cNext = cCode; 1809 do cNext = FT_Get_Next_Char( maFaceFT, cCode, &nGlyphIndex ); while( cNext == ++cCode ); 1810 aCodes.push_back( cCode ); // first code outside range 1811 cCode = cNext; 1812 } 1813 1814 const int nCount = aCodes.size(); 1815 if( !nCount) { 1816 if( !rResult.mbSymbolic ) 1817 return false; 1818 1819 // we usually get here for Type1 symbol fonts 1820 aCodes.push_back( 0xF020 ); 1821 aCodes.push_back( 0xF100 ); 1822 } 1823 1824 sal_uInt32* pCodes = new sal_uInt32[ nCount ]; 1825 for( int i = 0; i < nCount; ++i ) 1826 pCodes[i] = aCodes[i]; 1827 rResult.mpRangeCodes = pCodes; 1828 rResult.mnRangeCount = nCount / 2; 1829 return true; 1830 } 1831 1832 // ----------------------------------------------------------------------- 1833 // kerning stuff 1834 // ----------------------------------------------------------------------- 1835 1836 int FreetypeServerFont::GetGlyphKernValue( int nGlyphLeft, int nGlyphRight ) const 1837 { 1838 // if no kerning info is available from Freetype 1839 // then we may have to use extra info provided by e.g. psprint 1840 if( !FT_HAS_KERNING( maFaceFT ) || !FT_IS_SFNT( maFaceFT ) ) 1841 { 1842 int nKernVal = mpFontInfo->GetExtraGlyphKernValue( nGlyphLeft, nGlyphRight ); 1843 if( !nKernVal ) 1844 return 0; 1845 // scale the kern value to match the font size 1846 const ImplFontSelectData& rFSD = GetFontSelData(); 1847 nKernVal *= rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight; 1848 return (nKernVal + 500) / 1000; 1849 } 1850 1851 // when font faces of different sizes share the same maFaceFT 1852 // then we have to make sure that it uses the correct maSizeFT 1853 if( maSizeFT ) 1854 pFTActivateSize( maSizeFT ); 1855 1856 // use Freetype's kerning info 1857 FT_Vector aKernVal; 1858 FT_Error rcFT = FT_Get_Kerning( maFaceFT, nGlyphLeft, nGlyphRight, 1859 FT_KERNING_DEFAULT, &aKernVal ); 1860 int nResult = (rcFT == FT_Err_Ok) ? (aKernVal.x + 32) >> 6 : 0; 1861 return nResult; 1862 } 1863 1864 // ----------------------------------------------------------------------- 1865 1866 sal_uLong FreetypeServerFont::GetKernPairs( ImplKernPairData** ppKernPairs ) const 1867 { 1868 // if no kerning info is available in the font file 1869 *ppKernPairs = NULL; 1870 if( !FT_HAS_KERNING( maFaceFT ) || !FT_IS_SFNT( maFaceFT ) ) 1871 { 1872 // then we have may have extra kerning info from e.g. psprint 1873 int nCount = mpFontInfo->GetExtraKernPairs( ppKernPairs ); 1874 // scale the kern values to match the font size 1875 const ImplFontSelectData& rFSD = GetFontSelData(); 1876 int nFontWidth = rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight; 1877 ImplKernPairData* pKernPair = *ppKernPairs; 1878 for( int i = nCount; --i >= 0; ++pKernPair ) 1879 { 1880 long& rVal = pKernPair->mnKern; 1881 rVal = ((rVal * nFontWidth) + 500) / 1000; 1882 } 1883 return nCount; 1884 } 1885 1886 // when font faces of different sizes share the same maFaceFT 1887 // then we have to make sure that it uses the correct maSizeFT 1888 if( maSizeFT ) 1889 pFTActivateSize( maSizeFT ); 1890 1891 // first figure out which glyph pairs are involved in kerning 1892 sal_uLong nKernLength = 0; 1893 const FT_Byte* const pKern = mpFontInfo->GetTable( "kern", &nKernLength ); 1894 if( !pKern ) 1895 return 0; 1896 1897 // combine TTF/OTF tables from the font file to build a vector of 1898 // unicode kerning pairs using Freetype's glyph kerning calculation 1899 // for the kerning value 1900 1901 // TODO: is it worth to share the glyph->unicode mapping between 1902 // different instances of the same font face? 1903 1904 typedef std::vector<ImplKernPairData> KernVector; 1905 KernVector aKernGlyphVector; 1906 ImplKernPairData aKernPair; 1907 aKernPair.mnKern = 0; // To prevent "is used uninitialized" warning... 1908 1909 const FT_Byte* pBuffer = pKern; 1910 sal_uLong nVersion = GetUShort( pBuffer+0 ); 1911 sal_uInt16 nTableCnt = GetUShort( pBuffer+2 ); 1912 1913 // Microsoft/Old TrueType style kern table 1914 if ( nVersion == 0 ) 1915 { 1916 pBuffer += 4; 1917 1918 for( sal_uInt16 nTableIdx = 0; nTableIdx < nTableCnt; ++nTableIdx ) 1919 { 1920 // sal_uInt16 nSubVersion = GetUShort( pBuffer+0 ); 1921 // sal_uInt16 nSubLength = GetUShort( pBuffer+2 ); 1922 sal_uInt16 nSubCoverage = GetUShort( pBuffer+4 ); 1923 pBuffer += 6; 1924 if( (nSubCoverage&0x03) != 0x01 ) // no interest in minimum info here 1925 continue; 1926 switch( nSubCoverage >> 8 ) 1927 { 1928 case 0: // version 0, kerning format 0 1929 { 1930 sal_uInt16 nPairs = GetUShort( pBuffer ); 1931 pBuffer += 8; // skip search hints 1932 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs ); 1933 for( int i = 0; i < nPairs; ++i ) 1934 { 1935 aKernPair.mnChar1 = GetUShort( pBuffer+0 ); 1936 aKernPair.mnChar2 = GetUShort( pBuffer+2 ); 1937 //long nUnscaledKern= GetSShort( pBuffer ); 1938 pBuffer += 6; 1939 aKernGlyphVector.push_back( aKernPair ); 1940 } 1941 } 1942 break; 1943 1944 case 2: // version 0, kerning format 2 1945 { 1946 const FT_Byte* pSubTable = pBuffer; 1947 //sal_uInt16 nRowWidth = GetUShort( pBuffer+0 ); 1948 sal_uInt16 nOfsLeft = GetUShort( pBuffer+2 ); 1949 sal_uInt16 nOfsRight = GetUShort( pBuffer+4 ); 1950 sal_uInt16 nOfsArray = GetUShort( pBuffer+6 ); 1951 pBuffer += 8; 1952 1953 const FT_Byte* pTmp = pSubTable + nOfsLeft; 1954 sal_uInt16 nFirstLeft = GetUShort( pTmp+0 ); 1955 sal_uInt16 nLastLeft = GetUShort( pTmp+2 ) + nFirstLeft - 1; 1956 1957 pTmp = pSubTable + nOfsRight; 1958 sal_uInt16 nFirstRight = GetUShort( pTmp+0 ); 1959 sal_uInt16 nLastRight = GetUShort( pTmp+2 ) + nFirstRight - 1; 1960 1961 sal_uLong nPairs = (sal_uLong)(nLastLeft - nFirstLeft + 1) * (nLastRight - nFirstRight + 1); 1962 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs ); 1963 1964 pTmp = pSubTable + nOfsArray; 1965 for( int nLeft = nFirstLeft; nLeft < nLastLeft; ++nLeft ) 1966 { 1967 aKernPair.mnChar1 = nLeft; 1968 for( int nRight = 0; nRight < nLastRight; ++nRight ) 1969 { 1970 if( GetUShort( pTmp ) != 0 ) 1971 { 1972 aKernPair.mnChar2 = nRight; 1973 aKernGlyphVector.push_back( aKernPair ); 1974 } 1975 pTmp += 2; 1976 } 1977 } 1978 } 1979 break; 1980 } 1981 } 1982 } 1983 1984 // Apple New style kern table 1985 pBuffer = pKern; 1986 nVersion = NEXT_U32( pBuffer ); 1987 nTableCnt = NEXT_U32( pBuffer ); 1988 if ( nVersion == 0x00010000 ) 1989 { 1990 for( sal_uInt16 nTableIdx = 0; nTableIdx < nTableCnt; ++nTableIdx ) 1991 { 1992 /*sal_uLong nLength =*/ NEXT_U32( pBuffer ); 1993 sal_uInt16 nCoverage = NEXT_U16( pBuffer ); 1994 /*sal_uInt16 nTupleIndex =*/ NEXT_U16( pBuffer ); 1995 1996 // Kerning sub-table format, 0 through 3 1997 sal_uInt8 nSubTableFormat = nCoverage & 0x00FF; 1998 1999 switch( nSubTableFormat ) 2000 { 2001 case 0: // version 0, kerning format 0 2002 { 2003 sal_uInt16 nPairs = NEXT_U16( pBuffer ); 2004 pBuffer += 6; // skip search hints 2005 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs ); 2006 for( int i = 0; i < nPairs; ++i ) 2007 { 2008 aKernPair.mnChar1 = NEXT_U16( pBuffer ); 2009 aKernPair.mnChar2 = NEXT_U16( pBuffer ); 2010 /*long nUnscaledKern=*/ NEXT_S16( pBuffer ); 2011 aKernGlyphVector.push_back( aKernPair ); 2012 } 2013 } 2014 break; 2015 2016 case 2: // version 0, kerning format 2 2017 { 2018 const FT_Byte* pSubTable = pBuffer; 2019 /*sal_uInt16 nRowWidth =*/ NEXT_U16( pBuffer ); 2020 sal_uInt16 nOfsLeft = NEXT_U16( pBuffer ); 2021 sal_uInt16 nOfsRight = NEXT_U16( pBuffer ); 2022 sal_uInt16 nOfsArray = NEXT_U16( pBuffer ); 2023 2024 const FT_Byte* pTmp = pSubTable + nOfsLeft; 2025 sal_uInt16 nFirstLeft = NEXT_U16( pTmp ); 2026 sal_uInt16 nLastLeft = NEXT_U16( pTmp ) + nFirstLeft - 1; 2027 2028 pTmp = pSubTable + nOfsRight; 2029 sal_uInt16 nFirstRight = NEXT_U16( pTmp ); 2030 sal_uInt16 nLastRight = NEXT_U16( pTmp ) + nFirstRight - 1; 2031 2032 sal_uLong nPairs = (sal_uLong)(nLastLeft - nFirstLeft + 1) * (nLastRight - nFirstRight + 1); 2033 aKernGlyphVector.reserve( aKernGlyphVector.size() + nPairs ); 2034 2035 pTmp = pSubTable + nOfsArray; 2036 for( int nLeft = nFirstLeft; nLeft < nLastLeft; ++nLeft ) 2037 { 2038 aKernPair.mnChar1 = nLeft; 2039 for( int nRight = 0; nRight < nLastRight; ++nRight ) 2040 { 2041 if( NEXT_S16( pTmp ) != 0 ) 2042 { 2043 aKernPair.mnChar2 = nRight; 2044 aKernGlyphVector.push_back( aKernPair ); 2045 } 2046 } 2047 } 2048 } 2049 break; 2050 2051 default: 2052 fprintf( stderr, "gcach_ftyp.cxx: Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat ); 2053 break; 2054 } 2055 } 2056 } 2057 2058 // now create VCL's ImplKernPairData[] format for all glyph pairs 2059 sal_uLong nKernCount = aKernGlyphVector.size(); 2060 if( nKernCount ) 2061 { 2062 // prepare glyphindex to character mapping 2063 // TODO: this is needed to support VCL's existing kerning infrastructure, 2064 // eliminate it up by redesigning kerning infrastructure to work with glyph indizes 2065 typedef std::hash_multimap<sal_uInt16,sal_Unicode> Cmap; 2066 Cmap aCmap; 2067 for( sal_Unicode aChar = 0x0020; aChar < 0xFFFE; ++aChar ) 2068 { 2069 sal_uInt16 nGlyphIndex = GetGlyphIndex( aChar ); 2070 if( nGlyphIndex ) 2071 aCmap.insert( Cmap::value_type( nGlyphIndex, aChar ) ); 2072 } 2073 2074 // translate both glyph indizes in kerning pairs to characters 2075 // problem is that these are 1:n mappings... 2076 KernVector aKernCharVector; 2077 aKernCharVector.reserve( nKernCount ); 2078 KernVector::iterator it; 2079 for( it = aKernGlyphVector.begin(); it != aKernGlyphVector.end(); ++it ) 2080 { 2081 FT_Vector aKernVal; 2082 FT_Error rcFT = FT_Get_Kerning( maFaceFT, it->mnChar1, it->mnChar2, 2083 FT_KERNING_DEFAULT, &aKernVal ); 2084 aKernPair.mnKern = aKernVal.x >> 6; 2085 if( (aKernPair.mnKern == 0) || (rcFT != FT_Err_Ok) ) 2086 continue; 2087 2088 typedef std::pair<Cmap::iterator,Cmap::iterator> CPair; 2089 const CPair p1 = aCmap.equal_range( it->mnChar1 ); 2090 const CPair p2 = aCmap.equal_range( it->mnChar2 ); 2091 for( Cmap::const_iterator i1 = p1.first; i1 != p1.second; ++i1 ) 2092 { 2093 aKernPair.mnChar1 = (*i1).second; 2094 for( Cmap::const_iterator i2 = p2.first; i2 != p2.second; ++i2 ) 2095 { 2096 aKernPair.mnChar2 = (*i2).second; 2097 aKernCharVector.push_back( aKernPair ); 2098 } 2099 } 2100 } 2101 2102 // now move the resulting vector into VCL's ImplKernPairData[] format 2103 nKernCount = aKernCharVector.size(); 2104 ImplKernPairData* pTo = new ImplKernPairData[ nKernCount ]; 2105 *ppKernPairs = pTo; 2106 for( it = aKernCharVector.begin(); it != aKernCharVector.end(); ++it, ++pTo ) 2107 { 2108 pTo->mnChar1 = it->mnChar1; 2109 pTo->mnChar2 = it->mnChar2; 2110 pTo->mnKern = it->mnKern; 2111 } 2112 } 2113 2114 return nKernCount; 2115 } 2116 2117 // ----------------------------------------------------------------------- 2118 // outline stuff 2119 // ----------------------------------------------------------------------- 2120 2121 class PolyArgs 2122 { 2123 public: 2124 PolyArgs( PolyPolygon& rPolyPoly, sal_uInt16 nMaxPoints ); 2125 ~PolyArgs(); 2126 2127 void AddPoint( long nX, long nY, PolyFlags); 2128 void ClosePolygon(); 2129 2130 long GetPosX() const { return maPosition.x;} 2131 long GetPosY() const { return maPosition.y;} 2132 2133 private: 2134 PolyPolygon& mrPolyPoly; 2135 2136 Point* mpPointAry; 2137 sal_uInt8* mpFlagAry; 2138 2139 FT_Vector maPosition; 2140 sal_uInt16 mnMaxPoints; 2141 sal_uInt16 mnPoints; 2142 sal_uInt16 mnPoly; 2143 long mnHeight; 2144 bool bHasOffline; 2145 }; 2146 2147 // ----------------------------------------------------------------------- 2148 2149 PolyArgs::PolyArgs( PolyPolygon& rPolyPoly, sal_uInt16 nMaxPoints ) 2150 : mrPolyPoly(rPolyPoly), 2151 mnMaxPoints(nMaxPoints), 2152 mnPoints(0), 2153 mnPoly(0), 2154 bHasOffline(false) 2155 { 2156 mpPointAry = new Point[ mnMaxPoints ]; 2157 mpFlagAry = new sal_uInt8 [ mnMaxPoints ]; 2158 } 2159 2160 // ----------------------------------------------------------------------- 2161 2162 2163 PolyArgs::~PolyArgs() 2164 { 2165 delete[] mpFlagAry; 2166 delete[] mpPointAry; 2167 } 2168 2169 // ----------------------------------------------------------------------- 2170 2171 void PolyArgs::AddPoint( long nX, long nY, PolyFlags aFlag ) 2172 { 2173 DBG_ASSERT( (mnPoints < mnMaxPoints), "FTGlyphOutline: AddPoint overflow!" ); 2174 if( mnPoints >= mnMaxPoints ) 2175 return; 2176 2177 maPosition.x = nX; 2178 maPosition.y = nY; 2179 mpPointAry[ mnPoints ] = Point( nX, nY ); 2180 mpFlagAry[ mnPoints++ ]= aFlag; 2181 bHasOffline |= (aFlag != POLY_NORMAL); 2182 } 2183 2184 // ----------------------------------------------------------------------- 2185 2186 void PolyArgs::ClosePolygon() 2187 { 2188 if( !mnPoly++ ) 2189 return; 2190 2191 // freetype seems to always close the polygon with an ON_CURVE point 2192 // PolyPoly wants to close the polygon itself => remove last point 2193 DBG_ASSERT( (mnPoints >= 2), "FTGlyphOutline: PolyFinishNum failed!" ); 2194 --mnPoints; 2195 DBG_ASSERT( (mpPointAry[0]==mpPointAry[mnPoints]), "FTGlyphOutline: PolyFinishEq failed!" ); 2196 DBG_ASSERT( (mpFlagAry[0]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFE failed!" ); 2197 DBG_ASSERT( (mpFlagAry[mnPoints]==POLY_NORMAL), "FTGlyphOutline: PolyFinishFS failed!" ); 2198 2199 Polygon aPoly( mnPoints, mpPointAry, (bHasOffline ? mpFlagAry : NULL) ); 2200 2201 // #i35928# 2202 // This may be a invalid polygons, e.g. the last point is a control point. 2203 // So close the polygon (and add the first point again) if the last point 2204 // is a control point or different from first. 2205 // #i48298# 2206 // Now really duplicating the first point, to close or correct the 2207 // polygon. Also no longer duplicating the flags, but enforcing 2208 // POLY_NORMAL for the newly added last point. 2209 const sal_uInt16 nPolySize(aPoly.GetSize()); 2210 if(nPolySize) 2211 { 2212 if((aPoly.HasFlags() && POLY_CONTROL == aPoly.GetFlags(nPolySize - 1)) 2213 || (aPoly.GetPoint(nPolySize - 1) != aPoly.GetPoint(0))) 2214 { 2215 aPoly.SetSize(nPolySize + 1); 2216 aPoly.SetPoint(aPoly.GetPoint(0), nPolySize); 2217 2218 if(aPoly.HasFlags()) 2219 { 2220 aPoly.SetFlags(nPolySize, POLY_NORMAL); 2221 } 2222 } 2223 } 2224 2225 mrPolyPoly.Insert( aPoly ); 2226 mnPoints = 0; 2227 bHasOffline = false; 2228 } 2229 2230 // ----------------------------------------------------------------------- 2231 2232 extern "C" { 2233 2234 // TODO: wait till all compilers accept that calling conventions 2235 // for functions are the same independent of implementation constness, 2236 // then uncomment the const-tokens in the function interfaces below 2237 static int FT_move_to( FT_Vector_CPtr p0, void* vpPolyArgs ) 2238 { 2239 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs); 2240 2241 // move_to implies a new polygon => finish old polygon first 2242 rA.ClosePolygon(); 2243 2244 rA.AddPoint( p0->x, p0->y, POLY_NORMAL ); 2245 return 0; 2246 } 2247 2248 static int FT_line_to( FT_Vector_CPtr p1, void* vpPolyArgs ) 2249 { 2250 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs); 2251 rA.AddPoint( p1->x, p1->y, POLY_NORMAL ); 2252 return 0; 2253 } 2254 2255 static int FT_conic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, void* vpPolyArgs ) 2256 { 2257 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs); 2258 2259 // VCL's Polygon only knows cubic beziers 2260 const long nX1 = (2 * rA.GetPosX() + 4 * p1->x + 3) / 6; 2261 const long nY1 = (2 * rA.GetPosY() + 4 * p1->y + 3) / 6; 2262 rA.AddPoint( nX1, nY1, POLY_CONTROL ); 2263 2264 const long nX2 = (2 * p2->x + 4 * p1->x + 3) / 6; 2265 const long nY2 = (2 * p2->y + 4 * p1->y + 3) / 6; 2266 rA.AddPoint( nX2, nY2, POLY_CONTROL ); 2267 2268 rA.AddPoint( p2->x, p2->y, POLY_NORMAL ); 2269 return 0; 2270 } 2271 2272 static int FT_cubic_to( FT_Vector_CPtr p1, FT_Vector_CPtr p2, FT_Vector_CPtr p3, void* vpPolyArgs ) 2273 { 2274 PolyArgs& rA = *reinterpret_cast<PolyArgs*>(vpPolyArgs); 2275 rA.AddPoint( p1->x, p1->y, POLY_CONTROL ); 2276 rA.AddPoint( p2->x, p2->y, POLY_CONTROL ); 2277 rA.AddPoint( p3->x, p3->y, POLY_NORMAL ); 2278 return 0; 2279 } 2280 2281 } // extern "C" 2282 2283 // ----------------------------------------------------------------------- 2284 2285 bool FreetypeServerFont::GetGlyphOutline( sal_GlyphId aGlyphId, 2286 ::basegfx::B2DPolyPolygon& rB2DPolyPoly ) const 2287 { 2288 if( maSizeFT ) 2289 pFTActivateSize( maSizeFT ); 2290 2291 rB2DPolyPoly.clear(); 2292 2293 int nGlyphFlags; 2294 SplitGlyphFlags( *this, aGlyphId, nGlyphFlags ); 2295 2296 FT_Int nLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM; 2297 2298 #ifdef FT_LOAD_TARGET_LIGHT 2299 // enable "light hinting" if available 2300 if( nFTVERSION >= 2103 ) 2301 nLoadFlags |= FT_LOAD_TARGET_LIGHT; 2302 #endif 2303 2304 FT_Error rc = FT_Load_Glyph( maFaceFT, aGlyphId, nLoadFlags ); 2305 if( rc != FT_Err_Ok ) 2306 return false; 2307 2308 if( mbArtBold && pFTEmbolden ) 2309 (*pFTEmbolden)( maFaceFT->glyph ); 2310 2311 FT_Glyph pGlyphFT; 2312 rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT ); 2313 if( rc != FT_Err_Ok ) 2314 return false; 2315 2316 if( pGlyphFT->format != FT_GLYPH_FORMAT_OUTLINE ) 2317 return false; 2318 2319 if( mbArtItalic ) 2320 { 2321 FT_Matrix aMatrix; 2322 aMatrix.xx = aMatrix.yy = 0x10000L; 2323 if( nFTVERSION >= 2102 ) // Freetype 2.1.2 API swapped xy with yx 2324 aMatrix.xy = 0x6000L, aMatrix.yx = 0; 2325 else 2326 aMatrix.yx = 0x6000L, aMatrix.xy = 0; 2327 FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL ); 2328 } 2329 2330 FT_Outline& rOutline = reinterpret_cast<FT_OutlineGlyphRec*>(pGlyphFT)->outline; 2331 if( !rOutline.n_points ) // blank glyphs are ok 2332 return true; 2333 2334 long nMaxPoints = 1 + rOutline.n_points * 3; 2335 PolyPolygon aToolPolyPolygon; 2336 PolyArgs aPolyArg( aToolPolyPolygon, nMaxPoints ); 2337 2338 /*int nAngle =*/ ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false ); 2339 2340 FT_Outline_Funcs aFuncs; 2341 aFuncs.move_to = &FT_move_to; 2342 aFuncs.line_to = &FT_line_to; 2343 aFuncs.conic_to = &FT_conic_to; 2344 aFuncs.cubic_to = &FT_cubic_to; 2345 aFuncs.shift = 0; 2346 aFuncs.delta = 0; 2347 rc = FT_Outline_Decompose( &rOutline, &aFuncs, (void*)&aPolyArg ); 2348 aPolyArg.ClosePolygon(); // close last polygon 2349 FT_Done_Glyph( pGlyphFT ); 2350 2351 // convert to basegfx polypolygon 2352 // TODO: get rid of the intermediate tools polypolygon 2353 rB2DPolyPoly = aToolPolyPolygon.getB2DPolyPolygon(); 2354 rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix( +1.0/(1<<6), -1.0/(1<<6) )); 2355 2356 return true; 2357 } 2358 2359 // ----------------------------------------------------------------------- 2360 2361 bool FreetypeServerFont::ApplyGSUB( const ImplFontSelectData& rFSD ) 2362 { 2363 #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3]) 2364 2365 typedef std::vector<sal_uLong> ReqFeatureTagList; 2366 ReqFeatureTagList aReqFeatureTagList; 2367 if( rFSD.mbVertical ) 2368 aReqFeatureTagList.push_back( MKTAG("vert") ); 2369 sal_uLong nRequestedScript = 0; //MKTAG("hani");//### TODO: where to get script? 2370 sal_uLong nRequestedLangsys = 0; //MKTAG("ZHT"); //### TODO: where to get langsys? 2371 // TODO: request more features depending on script and language system 2372 2373 if( aReqFeatureTagList.size() == 0) // nothing to do 2374 return true; 2375 2376 // load GSUB table into memory 2377 sal_uLong nLength = 0; 2378 const FT_Byte* const pGsubBase = mpFontInfo->GetTable( "GSUB", &nLength ); 2379 if( !pGsubBase ) 2380 return false; 2381 2382 // parse GSUB header 2383 const FT_Byte* pGsubHeader = pGsubBase; 2384 const sal_uInt16 nOfsScriptList = GetUShort( pGsubHeader+4 ); 2385 const sal_uInt16 nOfsFeatureTable = GetUShort( pGsubHeader+6 ); 2386 const sal_uInt16 nOfsLookupList = GetUShort( pGsubHeader+8 ); 2387 pGsubHeader += 10; 2388 2389 typedef std::vector<sal_uInt16> UshortList; 2390 UshortList aFeatureIndexList; 2391 UshortList aFeatureOffsetList; 2392 2393 // parse Script Table 2394 const FT_Byte* pScriptHeader = pGsubBase + nOfsScriptList; 2395 const sal_uInt16 nCntScript = GetUShort( pScriptHeader+0 ); 2396 pScriptHeader += 2; 2397 for( sal_uInt16 nScriptIndex = 0; nScriptIndex < nCntScript; ++nScriptIndex ) 2398 { 2399 const sal_uLong nScriptTag = GetUInt( pScriptHeader+0 ); // e.g. hani/arab/kana/hang 2400 const sal_uInt16 nOfsScriptTable= GetUShort( pScriptHeader+4 ); 2401 pScriptHeader += 6; //### 2402 if( (nScriptTag != nRequestedScript) && (nRequestedScript != 0) ) 2403 continue; 2404 2405 const FT_Byte* pScriptTable = pGsubBase + nOfsScriptList + nOfsScriptTable; 2406 const sal_uInt16 nDefaultLangsysOfs = GetUShort( pScriptTable+0 ); 2407 const sal_uInt16 nCntLangSystem = GetUShort( pScriptTable+2 ); 2408 pScriptTable += 4; 2409 sal_uInt16 nLangsysOffset = 0; 2410 2411 for( sal_uInt16 nLangsysIndex = 0; nLangsysIndex < nCntLangSystem; ++nLangsysIndex ) 2412 { 2413 const sal_uLong nTag = GetUInt( pScriptTable+0 ); // e.g. KOR/ZHS/ZHT/JAN 2414 const sal_uInt16 nOffset= GetUShort( pScriptTable+4 ); 2415 pScriptTable += 6; 2416 if( (nTag != nRequestedLangsys) && (nRequestedLangsys != 0) ) 2417 continue; 2418 nLangsysOffset = nOffset; 2419 break; 2420 } 2421 2422 if( (nDefaultLangsysOfs != 0) && (nDefaultLangsysOfs != nLangsysOffset) ) 2423 { 2424 const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nDefaultLangsysOfs; 2425 const sal_uInt16 nReqFeatureIdx = GetUShort( pLangSys+2 ); 2426 const sal_uInt16 nCntFeature = GetUShort( pLangSys+4 ); 2427 pLangSys += 6; 2428 aFeatureIndexList.push_back( nReqFeatureIdx ); 2429 for( sal_uInt16 i = 0; i < nCntFeature; ++i ) 2430 { 2431 const sal_uInt16 nFeatureIndex = GetUShort( pLangSys ); 2432 pLangSys += 2; 2433 aFeatureIndexList.push_back( nFeatureIndex ); 2434 } 2435 } 2436 2437 if( nLangsysOffset != 0 ) 2438 { 2439 const FT_Byte* pLangSys = pGsubBase + nOfsScriptList + nOfsScriptTable + nLangsysOffset; 2440 const sal_uInt16 nReqFeatureIdx = GetUShort( pLangSys+2 ); 2441 const sal_uInt16 nCntFeature = GetUShort( pLangSys+4 ); 2442 pLangSys += 6; 2443 aFeatureIndexList.push_back( nReqFeatureIdx ); 2444 for( sal_uInt16 i = 0; i < nCntFeature; ++i ) 2445 { 2446 const sal_uInt16 nFeatureIndex = GetUShort( pLangSys ); 2447 pLangSys += 2; 2448 aFeatureIndexList.push_back( nFeatureIndex ); 2449 } 2450 } 2451 } 2452 2453 if( !aFeatureIndexList.size() ) 2454 return true; 2455 2456 UshortList aLookupIndexList; 2457 UshortList aLookupOffsetList; 2458 2459 // parse Feature Table 2460 const FT_Byte* pFeatureHeader = pGsubBase + nOfsFeatureTable; 2461 const sal_uInt16 nCntFeature = GetUShort( pFeatureHeader ); 2462 pFeatureHeader += 2; 2463 for( sal_uInt16 nFeatureIndex = 0; nFeatureIndex < nCntFeature; ++nFeatureIndex ) 2464 { 2465 const sal_uLong nTag = GetUInt( pFeatureHeader+0 ); // e.g. locl/vert/trad/smpl/liga/fina/... 2466 const sal_uInt16 nOffset= GetUShort( pFeatureHeader+4 ); 2467 pFeatureHeader += 6; 2468 2469 // short circuit some feature lookups 2470 if( aFeatureIndexList[0] != nFeatureIndex ) // required feature? 2471 { 2472 const int nRequested = std::count( aFeatureIndexList.begin(), aFeatureIndexList.end(), nFeatureIndex); 2473 if( !nRequested ) // ignore features that are not requested 2474 continue; 2475 const int nAvailable = std::count( aReqFeatureTagList.begin(), aReqFeatureTagList.end(), nTag); 2476 if( !nAvailable ) // some fonts don't provide features they request! 2477 continue; 2478 } 2479 2480 const FT_Byte* pFeatureTable = pGsubBase + nOfsFeatureTable + nOffset; 2481 pFeatureTable += 2; // ignore FeatureParams 2482 const sal_uInt16 nCntLookups = GetUShort( pFeatureTable+0 ); 2483 pFeatureTable += 2; 2484 for( sal_uInt16 i = 0; i < nCntLookups; ++i ) 2485 { 2486 const sal_uInt16 nLookupIndex = GetUShort( pFeatureTable ); 2487 pFeatureTable += 2; 2488 aLookupIndexList.push_back( nLookupIndex ); 2489 } 2490 if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/... 2491 aLookupIndexList.push_back( 0 ); 2492 } 2493 2494 // parse Lookup List 2495 const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList; 2496 const sal_uInt16 nCntLookupTable = GetUShort( pLookupHeader ); 2497 pLookupHeader += 2; 2498 for( sal_uInt16 nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx ) 2499 { 2500 const sal_uInt16 nOffset = GetUShort( pLookupHeader ); 2501 pLookupHeader += 2; 2502 if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) ) 2503 aLookupOffsetList.push_back( nOffset ); 2504 } 2505 2506 UshortList::const_iterator lookup_it = aLookupOffsetList.begin(); 2507 for(; lookup_it != aLookupOffsetList.end(); ++lookup_it ) 2508 { 2509 const sal_uInt16 nOfsLookupTable = *lookup_it; 2510 const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable; 2511 const sal_uInt16 eLookupType = GetUShort( pLookupTable+0 ); 2512 const sal_uInt16 nCntLookupSubtable = GetUShort( pLookupTable+4 ); 2513 pLookupTable += 6; 2514 2515 // TODO: switch( eLookupType ) 2516 if( eLookupType != 1 ) // TODO: once we go beyond SingleSubst 2517 continue; 2518 2519 for( sal_uInt16 nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx ) 2520 { 2521 const sal_uInt16 nOfsSubLookupTable = GetUShort( pLookupTable ); 2522 pLookupTable += 2; 2523 const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable; 2524 2525 const sal_uInt16 nFmtSubstitution = GetUShort( pSubLookup+0 ); 2526 const sal_uInt16 nOfsCoverage = GetUShort( pSubLookup+2 ); 2527 pSubLookup += 4; 2528 2529 typedef std::pair<sal_uInt16,sal_uInt16> GlyphSubst; 2530 typedef std::vector<GlyphSubst> SubstVector; 2531 SubstVector aSubstVector; 2532 2533 const FT_Byte* pCoverage = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage; 2534 const sal_uInt16 nFmtCoverage = GetUShort( pCoverage+0 ); 2535 pCoverage += 2; 2536 switch( nFmtCoverage ) 2537 { 2538 case 1: // Coverage Format 1 2539 { 2540 const sal_uInt16 nCntGlyph = GetUShort( pCoverage ); 2541 pCoverage += 2; 2542 aSubstVector.reserve( nCntGlyph ); 2543 for( sal_uInt16 i = 0; i < nCntGlyph; ++i ) 2544 { 2545 const sal_uInt16 nGlyphId = GetUShort( pCoverage ); 2546 pCoverage += 2; 2547 aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) ); 2548 } 2549 } 2550 break; 2551 2552 case 2: // Coverage Format 2 2553 { 2554 const sal_uInt16 nCntRange = GetUShort( pCoverage ); 2555 pCoverage += 2; 2556 for( int i = nCntRange; --i >= 0; ) 2557 { 2558 const sal_uInt32 nGlyph0 = GetUShort( pCoverage+0 ); 2559 const sal_uInt32 nGlyph1 = GetUShort( pCoverage+2 ); 2560 const sal_uInt16 nCovIdx = GetUShort( pCoverage+4 ); 2561 pCoverage += 6; 2562 for( sal_uInt32 j = nGlyph0; j <= nGlyph1; ++j ) 2563 aSubstVector.push_back( GlyphSubst( static_cast<sal_uInt16>(j + nCovIdx), 0 ) ); 2564 } 2565 } 2566 break; 2567 } 2568 2569 SubstVector::iterator it( aSubstVector.begin() ); 2570 2571 switch( nFmtSubstitution ) 2572 { 2573 case 1: // Single Substitution Format 1 2574 { 2575 const sal_uInt16 nDeltaGlyphId = GetUShort( pSubLookup ); 2576 pSubLookup += 2; 2577 for(; it != aSubstVector.end(); ++it ) 2578 (*it).second = (*it).first + nDeltaGlyphId; 2579 } 2580 break; 2581 2582 case 2: // Single Substitution Format 2 2583 { 2584 const sal_uInt16 nCntGlyph = GetUShort( pSubLookup ); 2585 pSubLookup += 2; 2586 for( int i = nCntGlyph; (it != aSubstVector.end()) && (--i>=0); ++it ) 2587 { 2588 const sal_uInt16 nGlyphId = GetUShort( pSubLookup ); 2589 pSubLookup += 2; 2590 (*it).second = nGlyphId; 2591 } 2592 } 2593 break; 2594 } 2595 2596 DBG_ASSERT( (it == aSubstVector.end()), "lookup<->coverage table mismatch" ); 2597 // now apply the glyph substitutions that have been collected in this subtable 2598 for( it = aSubstVector.begin(); it != aSubstVector.end(); ++it ) 2599 maGlyphSubstitution[ (*it).first ] = (*it).second; 2600 } 2601 } 2602 2603 return true; 2604 } 2605 2606 // ======================================================================= 2607 2608