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