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