PageRenderTime 75ms CodeModel.GetById 36ms RepoModel.GetById 1ms app.codeStats 0ms

/OOO330_m20/vcl/source/glyphs/gcach_ftyp.cxx

https://bitbucket.org/tora/ooo-enum-attribute-packed-experiment-ooo330_m20-vcl
C++ | 2557 lines | 1902 code | 387 blank | 268 comment | 439 complexity | afa160770e84614e0347aee319233ea2 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*************************************************************************
  2. *
  3. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4. *
  5. * Copyright 2000, 2010 Oracle and/or its affiliates.
  6. *
  7. * OpenOffice.org - a multi-platform office productivity suite
  8. *
  9. * This file is part of OpenOffice.org.
  10. *
  11. * OpenOffice.org is free software: you can redistribute it and/or modify
  12. * it under the terms of the GNU Lesser General Public License version 3
  13. * only, as published by the Free Software Foundation.
  14. *
  15. * OpenOffice.org is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Lesser General Public License version 3 for more details
  19. * (a copy is included in the LICENSE file that accompanied this code).
  20. *
  21. * You should have received a copy of the GNU Lesser General Public License
  22. * version 3 along with OpenOffice.org. If not, see
  23. * <http://www.openoffice.org/license.html>
  24. * for a copy of the LGPLv3 License.
  25. *
  26. ************************************************************************/
  27. // MARKER(update_precomp.py): autogen include statement, do not remove
  28. #include "precompiled_vcl.hxx"
  29. #ifdef WNT
  30. #include <svsys.h>
  31. #undef CreateFont
  32. #endif
  33. #include "gcach_ftyp.hxx"
  34. #include "vcl/svapp.hxx"
  35. #include "vcl/outfont.hxx"
  36. #include "vcl/impfont.hxx"
  37. #include "tools/poly.hxx"
  38. #include "basegfx/matrix/b2dhommatrix.hxx"
  39. #include <basegfx/matrix/b2dhommatrixtools.hxx>
  40. #include "basegfx/polygon/b2dpolypolygon.hxx"
  41. #include "osl/file.hxx"
  42. #include "osl/thread.hxx"
  43. #include <ft2build.h>
  44. #include FT_FREETYPE_H
  45. #include FT_GLYPH_H
  46. #include FT_OUTLINE_H
  47. #include FT_TRUETYPE_TABLES_H
  48. #include FT_TRUETYPE_TAGS_H
  49. #include FT_TRUETYPE_IDS_H
  50. #ifndef FT_RENDER_MODE_MONO // happens in the MACOSX build
  51. #define FT_RENDER_MODE_MONO ft_render_mode_mono
  52. #endif
  53. #include "rtl/instance.hxx"
  54. #ifndef FREETYPE_PATCH
  55. // VERSION_MINOR in freetype.h is too coarse
  56. // if patch-level is not available we need to fine-tune the version ourselves
  57. #define FTVERSION 2005
  58. #else
  59. #define FTVERSION (1000*FREETYPE_MAJOR + 100*FREETYPE_MINOR + FREETYPE_PATCH)
  60. #endif
  61. #if FTVERSION >= 2200
  62. typedef const FT_Vector* FT_Vector_CPtr;
  63. #else // FTVERSION < 2200
  64. typedef FT_Vector* FT_Vector_CPtr;
  65. #endif
  66. #include <vector>
  67. // TODO: move file mapping stuff to OSL
  68. #if defined(UNX)
  69. #if !defined(HPUX)
  70. // PORTERS: dlfcn is used for getting symbols from FT versions newer than baseline
  71. #include <dlfcn.h>
  72. #endif
  73. #include <unistd.h>
  74. #include <fcntl.h>
  75. #include <sys/stat.h>
  76. #include <sys/mman.h>
  77. #include "vcl/fontmanager.hxx"
  78. #elif defined(WNT)
  79. #include <io.h>
  80. #define strncasecmp strnicmp
  81. #endif
  82. typedef const unsigned char* CPU8;
  83. inline sal_uInt16 NEXT_U16( CPU8& p ) { p+=2; return (p[-2]<<8)|p[-1]; }
  84. inline sal_Int16 NEXT_S16( CPU8& p ) { return (sal_Int16)NEXT_U16(p); }
  85. inline sal_uInt32 NEXT_U32( CPU8& p ) { p+=4; return (p[-4]<<24)|(p[-3]<<16)|(p[-2]<<8)|p[-1]; }
  86. //inline sal_Int32 NEXT_S32( U8*& p ) { return (sal_Int32)NEXT_U32(p); }
  87. // -----------------------------------------------------------------------
  88. // the gamma table makes artificial bold look better for CJK glyphs
  89. static unsigned char aGammaTable[257];
  90. static void InitGammaTable()
  91. {
  92. static const int M_MAX = 255;
  93. static const int M_X = 128;
  94. static const int M_Y = 208;
  95. int x, a;
  96. for( x = 0; x < 256; x++)
  97. {
  98. if ( x <= M_X )
  99. a = ( x * M_Y + M_X / 2) / M_X;
  100. else
  101. a = M_Y + ( ( x - M_X ) * ( M_MAX - M_Y ) +
  102. ( M_MAX - M_X ) / 2 ) / ( M_MAX - M_X );
  103. aGammaTable[x] = (unsigned char)a;
  104. }
  105. }
  106. // -----------------------------------------------------------------------
  107. static FT_Library aLibFT = 0;
  108. // #110607# enable linking with old FT versions
  109. static int nFTVERSION = 0;
  110. static FT_Error (*pFTNewSize)(FT_Face,FT_Size*);
  111. static FT_Error (*pFTActivateSize)(FT_Size);
  112. static FT_Error (*pFTDoneSize)(FT_Size);
  113. FT_Error (*pFTEmbolden)(FT_GlyphSlot);
  114. FT_Error (*pFTOblique)(FT_GlyphSlot);
  115. static bool bEnableSizeFT = false;
  116. struct EqStr{ bool operator()(const char* a, const char* b) const { return !strcmp(a,b); } };
  117. typedef ::std::hash_map<const char*,FtFontFile*,::std::hash<const char*>, EqStr> FontFileList;
  118. namespace { struct vclFontFileList : public rtl::Static< FontFileList, vclFontFileList > {}; }
  119. // -----------------------------------------------------------------------
  120. // TODO: remove when the priorities are selected by UI
  121. // if (AH==0) => disable autohinting
  122. // if (AA==0) => disable antialiasing
  123. // if (EB==0) => disable embedded bitmaps
  124. // if (AA prio <= AH prio) => antialias + autohint
  125. // if (AH<AA) => do not autohint when antialiasing
  126. // if (EB<AH) => do not autohint for monochrome
  127. static int nDefaultPrioEmbedded = 2;
  128. static int nDefaultPrioAutoHint = 1;
  129. static int nDefaultPrioAntiAlias = 1;
  130. // =======================================================================
  131. // FreetypeManager
  132. // =======================================================================
  133. FtFontFile::FtFontFile( const ::rtl::OString& rNativeFileName )
  134. : maNativeFileName( rNativeFileName ),
  135. mpFileMap( NULL ),
  136. mnFileSize( 0 ),
  137. mnRefCount( 0 ),
  138. mnLangBoost( 0 )
  139. {
  140. // boost font preference if UI language is mentioned in filename
  141. int nPos = maNativeFileName.lastIndexOf( '_' );
  142. if( nPos == -1 || maNativeFileName[nPos+1] == '.' )
  143. mnLangBoost += 0x1000; // no langinfo => good
  144. else
  145. {
  146. static const char* pLangBoost = NULL;
  147. static bool bOnce = true;
  148. if( bOnce )
  149. {
  150. bOnce = false;
  151. LanguageType aLang = Application::GetSettings().GetUILanguage();
  152. switch( aLang )
  153. {
  154. case LANGUAGE_JAPANESE:
  155. pLangBoost = "jan";
  156. break;
  157. case LANGUAGE_CHINESE:
  158. case LANGUAGE_CHINESE_SIMPLIFIED:
  159. case LANGUAGE_CHINESE_SINGAPORE:
  160. pLangBoost = "zhs";
  161. break;
  162. case LANGUAGE_CHINESE_TRADITIONAL:
  163. case LANGUAGE_CHINESE_HONGKONG:
  164. case LANGUAGE_CHINESE_MACAU:
  165. pLangBoost = "zht";
  166. break;
  167. case LANGUAGE_KOREAN:
  168. case LANGUAGE_KOREAN_JOHAB:
  169. pLangBoost = "kor";
  170. break;
  171. }
  172. }
  173. if( pLangBoost && !strncasecmp( pLangBoost, &maNativeFileName.getStr()[nPos+1], 3 ) )
  174. mnLangBoost += 0x2000; // matching langinfo => better
  175. }
  176. }
  177. // -----------------------------------------------------------------------
  178. FtFontFile* FtFontFile::FindFontFile( const ::rtl::OString& rNativeFileName )
  179. {
  180. // font file already known? (e.g. for ttc, synthetic, aliased fonts)
  181. const char* pFileName = rNativeFileName.getStr();
  182. FontFileList &rFontFileList = vclFontFileList::get();
  183. FontFileList::const_iterator it = rFontFileList.find( pFileName );
  184. if( it != rFontFileList.end() )
  185. return (*it).second;
  186. // no => create new one
  187. FtFontFile* pFontFile = new FtFontFile( rNativeFileName );
  188. pFileName = pFontFile->maNativeFileName.getStr();
  189. rFontFileList[ pFileName ] = pFontFile;
  190. return pFontFile;
  191. }
  192. // -----------------------------------------------------------------------
  193. bool FtFontFile::Map()
  194. {
  195. if( mnRefCount++ <= 0 )
  196. {
  197. const char* pFileName = maNativeFileName.getStr();
  198. #if defined(UNX)
  199. int nFile = open( pFileName, O_RDONLY );
  200. if( nFile < 0 )
  201. return false;
  202. struct stat aStat;
  203. fstat( nFile, &aStat );
  204. mnFileSize = aStat.st_size;
  205. mpFileMap = (const unsigned char*)
  206. mmap( NULL, mnFileSize, PROT_READ, MAP_SHARED, nFile, 0 );
  207. if( mpFileMap == MAP_FAILED )
  208. mpFileMap = NULL;
  209. close( nFile );
  210. #elif defined(WNT)
  211. void* pFileDesc = ::CreateFile( pFileName, GENERIC_READ, FILE_SHARE_READ,
  212. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
  213. if( pFileDesc == INVALID_HANDLE_VALUE)
  214. return false;
  215. mnFileSize = ::GetFileSize( pFileDesc, NULL );
  216. HANDLE aHandle = ::CreateFileMapping( pFileDesc, NULL, PAGE_READONLY, 0, mnFileSize, "TTF" );
  217. mpFileMap = (const unsigned char*)::MapViewOfFile( aHandle, FILE_MAP_READ, 0, 0, mnFileSize );
  218. ::CloseHandle( pFileDesc );
  219. #else
  220. FILE* pFile = fopen( pFileName, "rb" );
  221. if( !pFile )
  222. return false;
  223. struct stat aStat;
  224. stat( pFileName, &aStat );
  225. mnFileSize = aStat.st_size;
  226. mpFileMap = new unsigned char[ mnFileSize ];
  227. if( mnFileSize != fread( mpFileMap, 1, mnFileSize, pFile ) )
  228. {
  229. delete[] mpFileMap;
  230. mpFileMap = NULL;
  231. }
  232. fclose( pFile );
  233. #endif
  234. }
  235. return (mpFileMap != NULL);
  236. }
  237. // -----------------------------------------------------------------------
  238. void FtFontFile::Unmap()
  239. {
  240. if( (--mnRefCount > 0) || (mpFileMap == NULL) )
  241. return;
  242. #if defined(UNX)
  243. munmap( (char*)mpFileMap, mnFileSize );
  244. #elif defined(WNT)
  245. UnmapViewOfFile( (LPCVOID)mpFileMap );
  246. #else
  247. delete[] mpFileMap;
  248. #endif
  249. mpFileMap = NULL;
  250. }
  251. // =======================================================================
  252. FtFontInfo::FtFontInfo( const ImplDevFontAttributes& rDevFontAttributes,
  253. const ::rtl::OString& rNativeFileName, int nFaceNum, sal_IntPtr nFontId, int nSynthetic,
  254. const ExtraKernInfo* pExtraKernInfo )
  255. :
  256. maFaceFT( NULL ),
  257. mpFontFile( FtFontFile::FindFontFile( rNativeFileName ) ),
  258. mnFaceNum( nFaceNum ),
  259. mnRefCount( 0 ),
  260. mnSynthetic( nSynthetic ),
  261. mnFontId( nFontId ),
  262. maDevFontAttributes( rDevFontAttributes ),
  263. mpChar2Glyph( NULL ),
  264. mpGlyph2Char( NULL ),
  265. mpExtraKernInfo( pExtraKernInfo )
  266. {
  267. // prefer font with low ID
  268. maDevFontAttributes.mnQuality += 10000 - nFontId;
  269. // prefer font with matching file names
  270. maDevFontAttributes.mnQuality += mpFontFile->GetLangBoost();
  271. // prefer font with more external info
  272. if( pExtraKernInfo )
  273. maDevFontAttributes.mnQuality += 100;
  274. }
  275. // -----------------------------------------------------------------------
  276. FtFontInfo::~FtFontInfo()
  277. {
  278. delete mpExtraKernInfo;
  279. delete mpChar2Glyph;
  280. delete mpGlyph2Char;
  281. }
  282. void FtFontInfo::InitHashes() const
  283. {
  284. // TODO: avoid pointers when empty stl::hash_* objects become cheap
  285. mpChar2Glyph = new Int2IntMap();
  286. mpGlyph2Char = new Int2IntMap();
  287. }
  288. // -----------------------------------------------------------------------
  289. FT_FaceRec_* FtFontInfo::GetFaceFT()
  290. {
  291. // get faceFT once/multiple depending on availability of SizeFT APIs
  292. if( (mnRefCount++ <= 0) || !bEnableSizeFT )
  293. {
  294. if( !mpFontFile->Map() )
  295. return NULL;
  296. FT_Error rc = FT_New_Memory_Face( aLibFT,
  297. (FT_Byte*)mpFontFile->GetBuffer(),
  298. mpFontFile->GetFileSize(), mnFaceNum, &maFaceFT );
  299. if( (rc != FT_Err_Ok) || (maFaceFT->num_glyphs <= 0) )
  300. maFaceFT = NULL;
  301. }
  302. return maFaceFT;
  303. }
  304. // -----------------------------------------------------------------------
  305. void FtFontInfo::ReleaseFaceFT( FT_FaceRec_* pFaceFT )
  306. {
  307. // release last/each depending on SizeFT availability
  308. if( (--mnRefCount <= 0) || !bEnableSizeFT )
  309. {
  310. FT_Done_Face( pFaceFT );
  311. maFaceFT = NULL;
  312. mpFontFile->Unmap();
  313. }
  314. }
  315. // -----------------------------------------------------------------------
  316. bool FtFontInfo::HasExtraKerning() const
  317. {
  318. if( !mpExtraKernInfo )
  319. return false;
  320. // TODO: how to enable the line below without getting #i29881# back?
  321. // on the other hand being to optimistic doesn't cause problems
  322. // return mpExtraKernInfo->HasKernPairs();
  323. return true;
  324. }
  325. // -----------------------------------------------------------------------
  326. int FtFontInfo::GetExtraKernPairs( ImplKernPairData** ppKernPairs ) const
  327. {
  328. if( !mpExtraKernInfo )
  329. return 0;
  330. return mpExtraKernInfo->GetUnscaledKernPairs( ppKernPairs );
  331. }
  332. // -----------------------------------------------------------------------
  333. int FtFontInfo::GetExtraGlyphKernValue( int nLeftGlyph, int nRightGlyph ) const
  334. {
  335. if( !mpExtraKernInfo )
  336. return 0;
  337. if( !mpGlyph2Char )
  338. return 0;
  339. sal_Unicode cLeftChar = (*mpGlyph2Char)[ nLeftGlyph ];
  340. sal_Unicode cRightChar = (*mpGlyph2Char)[ nRightGlyph ];
  341. return mpExtraKernInfo->GetUnscaledKernValue( cLeftChar, cRightChar );
  342. }
  343. // -----------------------------------------------------------------------
  344. static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
  345. static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
  346. //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
  347. // -----------------------------------------------------------------------
  348. const unsigned char* FtFontInfo::GetTable( const char* pTag, ULONG* pLength ) const
  349. {
  350. const unsigned char* pBuffer = mpFontFile->GetBuffer();
  351. int nFileSize = mpFontFile->GetFileSize();
  352. if( !pBuffer || nFileSize<1024 )
  353. return NULL;
  354. // we currently only handle TTF and TTC headers
  355. unsigned nFormat = GetUInt( pBuffer );
  356. const unsigned char* p = pBuffer + 12;
  357. if( nFormat == 0x74746366 ) // TTC_MAGIC
  358. p += GetUInt( p + 4 * mnFaceNum );
  359. else if( (nFormat!=0x00010000) && (nFormat!=0x74727565) ) // TTF_MAGIC and Apple TTF Magic
  360. return NULL;
  361. // walk table directory until match
  362. int nTables = GetUShort( p - 8 );
  363. if( nTables >= 64 ) // something fishy?
  364. return NULL;
  365. for( int i = 0; i < nTables; ++i, p+=16 )
  366. {
  367. if( p[0]==pTag[0] && p[1]==pTag[1] && p[2]==pTag[2] && p[3]==pTag[3] )
  368. {
  369. ULONG nLength = GetUInt( p + 12 );
  370. if( pLength != NULL )
  371. *pLength = nLength;
  372. const unsigned char* pTable = pBuffer + GetUInt( p + 8 );
  373. if( (pTable + nLength) <= (mpFontFile->GetBuffer() + nFileSize) )
  374. return pTable;
  375. }
  376. }
  377. return NULL;
  378. }
  379. // -----------------------------------------------------------------------
  380. void FtFontInfo::AnnounceFont( ImplDevFontList* pFontList )
  381. {
  382. ImplFTSFontData* pFD = new ImplFTSFontData( this, maDevFontAttributes );
  383. pFontList->Add( pFD );
  384. }
  385. // =======================================================================
  386. FreetypeManager::FreetypeManager()
  387. : mnMaxFontId( 0 ), mnNextFontId( 0x1000 )
  388. {
  389. /*FT_Error rcFT =*/ FT_Init_FreeType( &aLibFT );
  390. #ifdef RTLD_DEFAULT // true if a good dlfcn.h header was included
  391. // Get version of freetype library to enable workarounds.
  392. // Freetype <= 2.0.9 does not have FT_Library_Version().
  393. // Using dl_sym() instead of osl_getSymbol() because latter
  394. // isn't designed to work with oslModule=NULL
  395. void (*pFTLibraryVersion)(FT_Library library,
  396. FT_Int *amajor, FT_Int *aminor, FT_Int *apatch);
  397. pFTLibraryVersion = (void (*)(FT_Library library,
  398. FT_Int *amajor, FT_Int *aminor, FT_Int *apatch))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Library_Version" );
  399. pFTNewSize = (FT_Error(*)(FT_Face,FT_Size*))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_New_Size" );
  400. pFTActivateSize = (FT_Error(*)(FT_Size))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Activate_Size" );
  401. pFTDoneSize = (FT_Error(*)(FT_Size))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_Done_Size" );
  402. pFTEmbolden = (FT_Error(*)(FT_GlyphSlot))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_GlyphSlot_Embolden" );
  403. pFTOblique = (FT_Error(*)(FT_GlyphSlot))(sal_IntPtr)dlsym( RTLD_DEFAULT, "FT_GlyphSlot_Oblique" );
  404. bEnableSizeFT = (pFTNewSize!=NULL) && (pFTActivateSize!=NULL) && (pFTDoneSize!=NULL);
  405. FT_Int nMajor = 0, nMinor = 0, nPatch = 0;
  406. if( pFTLibraryVersion )
  407. pFTLibraryVersion( aLibFT, &nMajor, &nMinor, &nPatch );
  408. nFTVERSION = nMajor * 1000 + nMinor * 100 + nPatch;
  409. // disable embedded bitmaps for Freetype-2.1.3 unless explicitly
  410. // requested by env var below because it crashes StarOffice on RH9
  411. // reason: double free in freetype's embedded bitmap handling
  412. if( nFTVERSION == 2103 )
  413. nDefaultPrioEmbedded = 0;
  414. // disable artificial emboldening with the Freetype API for older versions
  415. if( nFTVERSION < 2110 )
  416. pFTEmbolden = NULL;
  417. #else // RTLD_DEFAULT
  418. // assume systems where dlsym is not possible use supplied library
  419. nFTVERSION = FTVERSION;
  420. #endif
  421. // TODO: remove when the priorities are selected by UI
  422. char* pEnv;
  423. pEnv = ::getenv( "SAL_EMBEDDED_BITMAP_PRIORITY" );
  424. if( pEnv )
  425. nDefaultPrioEmbedded = pEnv[0] - '0';
  426. pEnv = ::getenv( "SAL_ANTIALIASED_TEXT_PRIORITY" );
  427. if( pEnv )
  428. nDefaultPrioAntiAlias = pEnv[0] - '0';
  429. pEnv = ::getenv( "SAL_AUTOHINTING_PRIORITY" );
  430. if( pEnv )
  431. nDefaultPrioAutoHint = pEnv[0] - '0';
  432. InitGammaTable();
  433. }
  434. // -----------------------------------------------------------------------
  435. void* FreetypeServerFont::GetFtFace() const
  436. {
  437. if( maSizeFT )
  438. pFTActivateSize( maSizeFT );
  439. return maFaceFT;
  440. }
  441. // -----------------------------------------------------------------------
  442. FreetypeManager::~FreetypeManager()
  443. {
  444. // This crashes on Solaris 10
  445. // TODO: check which versions have this problem
  446. //
  447. // FT_Error rcFT = FT_Done_FreeType( aLibFT );
  448. }
  449. // -----------------------------------------------------------------------
  450. void FreetypeManager::AddFontFile( const rtl::OString& rNormalizedName,
  451. int nFaceNum, sal_IntPtr nFontId, const ImplDevFontAttributes& rDevFontAttr,
  452. const ExtraKernInfo* pExtraKernInfo )
  453. {
  454. if( !rNormalizedName.getLength() )
  455. return;
  456. if( maFontList.find( nFontId ) != maFontList.end() )
  457. return;
  458. FtFontInfo* pFontInfo = new FtFontInfo( rDevFontAttr,
  459. rNormalizedName, nFaceNum, nFontId, 0, pExtraKernInfo );
  460. maFontList[ nFontId ] = pFontInfo;
  461. if( mnMaxFontId < nFontId )
  462. mnMaxFontId = nFontId;
  463. }
  464. // -----------------------------------------------------------------------
  465. long FreetypeManager::AddFontDir( const String& rUrlName )
  466. {
  467. osl::Directory aDir( rUrlName );
  468. osl::FileBase::RC rcOSL = aDir.open();
  469. if( rcOSL != osl::FileBase::E_None )
  470. return 0;
  471. long nCount = 0;
  472. osl::DirectoryItem aDirItem;
  473. rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
  474. while( (rcOSL = aDir.getNextItem( aDirItem, 20 )) == osl::FileBase::E_None )
  475. {
  476. osl::FileStatus aFileStatus( FileStatusMask_FileURL );
  477. rcOSL = aDirItem.getFileStatus( aFileStatus );
  478. ::rtl::OUString aUSytemPath;
  479. OSL_VERIFY( osl::FileBase::E_None
  480. == osl::FileBase::getSystemPathFromFileURL( aFileStatus.getFileURL(), aUSytemPath ));
  481. ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
  482. const char* pszFontFileName = aCFileName.getStr();
  483. FT_FaceRec_* aFaceFT = NULL;
  484. for( int nFaceNum = 0, nMaxFaces = 1; nFaceNum < nMaxFaces; ++nFaceNum )
  485. {
  486. FT_Error rcFT = FT_New_Face( aLibFT, pszFontFileName, nFaceNum, &aFaceFT );
  487. if( (rcFT != FT_Err_Ok) || (aFaceFT == NULL) )
  488. break;
  489. if( !FT_IS_SCALABLE( aFaceFT ) ) // ignore non-scalabale fonts
  490. continue;
  491. nMaxFaces = aFaceFT->num_faces;
  492. ImplDevFontAttributes aDFA;
  493. // TODO: prefer unicode names if available
  494. // TODO: prefer locale specific names if available?
  495. if ( aFaceFT->family_name )
  496. aDFA.maName = String::CreateFromAscii( aFaceFT->family_name );
  497. if ( aFaceFT->style_name )
  498. aDFA.maStyleName = String::CreateFromAscii( aFaceFT->style_name );
  499. aDFA.mbSymbolFlag = false;
  500. for( int i = aFaceFT->num_charmaps; --i >= 0; )
  501. {
  502. const FT_CharMap aCM = aFaceFT->charmaps[i];
  503. #if (FTVERSION < 2000)
  504. if( aCM->encoding == FT_ENCODING_NONE )
  505. #else
  506. if( (aCM->platform_id == TT_PLATFORM_MICROSOFT)
  507. && (aCM->encoding_id == TT_MS_ID_SYMBOL_CS) )
  508. #endif
  509. aDFA.mbSymbolFlag = true;
  510. }
  511. // TODO: extract better font characterization data from font
  512. aDFA.meFamily = FAMILY_DONTKNOW;
  513. aDFA.mePitch = FT_IS_FIXED_WIDTH( aFaceFT ) ? PITCH_FIXED : PITCH_VARIABLE;
  514. aDFA.meWidthType = WIDTH_DONTKNOW;
  515. aDFA.meWeight = FT_STYLE_FLAG_BOLD & aFaceFT->style_flags ? WEIGHT_BOLD : WEIGHT_NORMAL;
  516. aDFA.meItalic = FT_STYLE_FLAG_ITALIC & aFaceFT->style_flags ? ITALIC_NORMAL : ITALIC_NONE;
  517. aDFA.mnQuality = 0;
  518. aDFA.mbOrientation= true;
  519. aDFA.mbDevice = true;
  520. aDFA.mbSubsettable= false;
  521. aDFA.mbEmbeddable = false;
  522. FT_Done_Face( aFaceFT );
  523. AddFontFile( aCFileName, nFaceNum, ++mnNextFontId, aDFA, NULL );
  524. ++nCount;
  525. }
  526. }
  527. aDir.close();
  528. return nCount;
  529. }
  530. // -----------------------------------------------------------------------
  531. void FreetypeManager::AnnounceFonts( ImplDevFontList* pToAdd ) const
  532. {
  533. for( FontList::const_iterator it = maFontList.begin(); it != maFontList.end(); ++it )
  534. {
  535. FtFontInfo* pFtFontInfo = it->second;
  536. pFtFontInfo->AnnounceFont( pToAdd );
  537. }
  538. }
  539. // -----------------------------------------------------------------------
  540. void FreetypeManager::ClearFontList( )
  541. {
  542. for( FontList::iterator it = maFontList.begin(); it != maFontList.end(); ++it )
  543. {
  544. FtFontInfo* pFtFontInfo = it->second;
  545. delete pFtFontInfo;
  546. }
  547. maFontList.clear();
  548. }
  549. // -----------------------------------------------------------------------
  550. FreetypeServerFont* FreetypeManager::CreateFont( const ImplFontSelectData& rFSD )
  551. {
  552. FtFontInfo* pFontInfo = NULL;
  553. // find a FontInfo matching to the font id
  554. sal_IntPtr nFontId = reinterpret_cast<sal_IntPtr>( rFSD.mpFontData );
  555. FontList::iterator it = maFontList.find( nFontId );
  556. if( it != maFontList.end() )
  557. pFontInfo = it->second;
  558. if( !pFontInfo )
  559. return NULL;
  560. FreetypeServerFont* pNew = new FreetypeServerFont( rFSD, pFontInfo );
  561. return pNew;
  562. }
  563. // =======================================================================
  564. ImplFTSFontData::ImplFTSFontData( FtFontInfo* pFI, const ImplDevFontAttributes& rDFA )
  565. : ImplFontData( rDFA, IFTSFONT_MAGIC ),
  566. mpFtFontInfo( pFI )
  567. {
  568. mbDevice = false;
  569. mbOrientation = true;
  570. }
  571. // -----------------------------------------------------------------------
  572. ImplFontEntry* ImplFTSFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
  573. {
  574. ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD );
  575. return pEntry;
  576. }
  577. // =======================================================================
  578. // FreetypeServerFont
  579. // =======================================================================
  580. FreetypeServerFont::FreetypeServerFont( const ImplFontSelectData& rFSD, FtFontInfo* pFI )
  581. : ServerFont( rFSD ),
  582. mnPrioEmbedded(nDefaultPrioEmbedded),
  583. mnPrioAntiAlias(nDefaultPrioAntiAlias),
  584. mnPrioAutoHint(nDefaultPrioAutoHint),
  585. mpFontInfo( pFI ),
  586. maFaceFT( NULL ),
  587. maSizeFT( NULL ),
  588. mbFaceOk( false ),
  589. maRecodeConverter( NULL ),
  590. mpLayoutEngine( NULL )
  591. {
  592. maFaceFT = pFI->GetFaceFT();
  593. #ifdef HDU_DEBUG
  594. fprintf( stderr, "FTSF::FTSF(\"%s\", h=%d, w=%d, sy=%d) => %d\n",
  595. pFI->GetFontFileName()->getStr(), rFSD.mnHeight, rFSD.mnWidth, pFI->IsSymbolFont(), maFaceFT!=0 );
  596. #endif
  597. if( !maFaceFT )
  598. return;
  599. // set the pixel size of the font instance
  600. mnWidth = rFSD.mnWidth;
  601. if( !mnWidth )
  602. mnWidth = rFSD.mnHeight;
  603. mfStretch = (double)mnWidth / rFSD.mnHeight;
  604. // sanity check (e.g. #i66394#, #i66244#, #66537#)
  605. if( (mnWidth < 0) || (mfStretch > +64.0) || (mfStretch < -64.0) )
  606. return;
  607. // perf: use maSizeFT if available
  608. if( bEnableSizeFT )
  609. {
  610. pFTNewSize( maFaceFT, &maSizeFT );
  611. pFTActivateSize( maSizeFT );
  612. }
  613. FT_Error rc = FT_Set_Pixel_Sizes( maFaceFT, mnWidth, rFSD.mnHeight );
  614. if( rc != FT_Err_Ok )
  615. return;
  616. // prepare for font encodings other than unicode or symbol
  617. FT_Encoding eEncoding = FT_ENCODING_UNICODE;
  618. if( mpFontInfo->IsSymbolFont() )
  619. {
  620. #if (FTVERSION < 2000)
  621. eEncoding = FT_ENCODING_NONE;
  622. #else
  623. if( FT_IS_SFNT( maFaceFT ) )
  624. eEncoding = ft_encoding_symbol;
  625. else
  626. eEncoding = FT_ENCODING_ADOBE_CUSTOM; // freetype wants this for PS symbol fonts
  627. #endif
  628. }
  629. rc = FT_Select_Charmap( maFaceFT, eEncoding );
  630. // no standard encoding applies => we need an encoding converter
  631. if( rc != FT_Err_Ok )
  632. {
  633. rtl_TextEncoding eRecodeFrom = RTL_TEXTENCODING_UNICODE;
  634. for( int i = maFaceFT->num_charmaps; --i >= 0; )
  635. {
  636. const FT_CharMap aCM = maFaceFT->charmaps[i];
  637. if( aCM->platform_id == TT_PLATFORM_MICROSOFT )
  638. {
  639. switch( aCM->encoding_id )
  640. {
  641. case TT_MS_ID_SJIS:
  642. eEncoding = FT_ENCODING_SJIS;
  643. eRecodeFrom = RTL_TEXTENCODING_SHIFT_JIS;
  644. break;
  645. case TT_MS_ID_GB2312:
  646. eEncoding = FT_ENCODING_GB2312;
  647. eRecodeFrom = RTL_TEXTENCODING_GB_2312;
  648. break;
  649. case TT_MS_ID_BIG_5:
  650. eEncoding = FT_ENCODING_BIG5;
  651. eRecodeFrom = RTL_TEXTENCODING_BIG5;
  652. break;
  653. case TT_MS_ID_WANSUNG:
  654. eEncoding = FT_ENCODING_WANSUNG;
  655. eRecodeFrom = RTL_TEXTENCODING_MS_949;
  656. break;
  657. case TT_MS_ID_JOHAB:
  658. eEncoding = FT_ENCODING_JOHAB;
  659. eRecodeFrom = RTL_TEXTENCODING_MS_1361;
  660. break;
  661. }
  662. }
  663. else if( aCM->platform_id == TT_PLATFORM_MACINTOSH )
  664. {
  665. switch( aCM->encoding_id )
  666. {
  667. case TT_MAC_ID_ROMAN:
  668. eEncoding = FT_ENCODING_APPLE_ROMAN;
  669. eRecodeFrom = RTL_TEXTENCODING_UNICODE; // TODO: use better match
  670. break;
  671. // TODO: add other encodings when Mac-only
  672. // non-unicode fonts show up
  673. }
  674. }
  675. else if( aCM->platform_id == TT_PLATFORM_ADOBE )
  676. {
  677. switch( aCM->encoding_id )
  678. {
  679. #ifdef TT_ADOBE_ID_LATIN1
  680. case TT_ADOBE_ID_LATIN1: // better unicode than nothing
  681. eEncoding = FT_ENCODING_ADOBE_LATIN_1;
  682. eRecodeFrom = RTL_TEXTENCODING_ISO_8859_1;
  683. break;
  684. #endif // TT_ADOBE_ID_LATIN1
  685. case TT_ADOBE_ID_STANDARD: // better unicode than nothing
  686. eEncoding = FT_ENCODING_ADOBE_STANDARD;
  687. eRecodeFrom = RTL_TEXTENCODING_UNICODE; // TODO: use better match
  688. break;
  689. }
  690. }
  691. }
  692. if( FT_Err_Ok != FT_Select_Charmap( maFaceFT, eEncoding ) )
  693. return;
  694. if( eRecodeFrom != RTL_TEXTENCODING_UNICODE )
  695. maRecodeConverter = rtl_createUnicodeToTextConverter( eRecodeFrom );
  696. }
  697. mbFaceOk = true;
  698. ApplyGSUB( rFSD );
  699. // TODO: query GASP table for load flags
  700. mnLoadFlags = FT_LOAD_DEFAULT;
  701. #if 1 // #i97326# cairo sometimes uses FT_Set_Transform() on our FT_FACE
  702. // we are not using FT_Set_Transform() yet, so just ignore it for now
  703. mnLoadFlags |= FT_LOAD_IGNORE_TRANSFORM;
  704. #endif
  705. mbArtItalic = (rFSD.meItalic != ITALIC_NONE && pFI->GetFontAttributes().GetSlant() == ITALIC_NONE);
  706. mbArtBold = (rFSD.meWeight > WEIGHT_MEDIUM && pFI->GetFontAttributes().GetWeight() <= WEIGHT_MEDIUM);
  707. mbUseGamma = false;
  708. if( mbArtBold )
  709. {
  710. //static const int TT_CODEPAGE_RANGE_874 = (1L << 16); // Thai
  711. //static const int TT_CODEPAGE_RANGE_932 = (1L << 17); // JIS/Japan
  712. //static const int TT_CODEPAGE_RANGE_936 = (1L << 18); // Chinese: Simplified
  713. //static const int TT_CODEPAGE_RANGE_949 = (1L << 19); // Korean Wansung
  714. //static const int TT_CODEPAGE_RANGE_950 = (1L << 20); // Chinese: Traditional
  715. //static const int TT_CODEPAGE_RANGE_1361 = (1L << 21); // Korean Johab
  716. static const int TT_CODEPAGE_RANGES1_CJKT = 0x3F0000; // all of the above
  717. const TT_OS2* pOs2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 );
  718. if ((pOs2) && (pOs2->ulCodePageRange1 & TT_CODEPAGE_RANGES1_CJKT )
  719. && rFSD.mnHeight < 20)
  720. mbUseGamma = true;
  721. }
  722. if( ((mnCos != 0) && (mnSin != 0)) || (mnPrioEmbedded <= 0) )
  723. mnLoadFlags |= FT_LOAD_NO_BITMAP;
  724. }
  725. void FreetypeServerFont::SetFontOptions( const ImplFontOptions& rFontOptions)
  726. {
  727. FontAutoHint eHint = rFontOptions.GetUseAutoHint();
  728. if( eHint == AUTOHINT_DONTKNOW )
  729. eHint = mbUseGamma ? AUTOHINT_TRUE : AUTOHINT_FALSE;
  730. if( eHint == AUTOHINT_TRUE )
  731. mnLoadFlags |= FT_LOAD_FORCE_AUTOHINT;
  732. if( (mnSin != 0) && (mnCos != 0) ) // hinting for 0/90/180/270 degrees only
  733. mnLoadFlags |= FT_LOAD_NO_HINTING;
  734. mnLoadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; //#88334#
  735. if( rFontOptions.DontUseAntiAlias() )
  736. mnPrioAntiAlias = 0;
  737. if( rFontOptions.DontUseEmbeddedBitmaps() )
  738. mnPrioEmbedded = 0;
  739. if( rFontOptions.DontUseHinting() )
  740. mnPrioAutoHint = 0;
  741. #if (FTVERSION >= 2005) || defined(TT_CONFIG_OPTION_BYTECODE_INTERPRETER)
  742. if( mnPrioAutoHint <= 0 )
  743. #endif
  744. mnLoadFlags |= FT_LOAD_NO_HINTING;
  745. #if defined(FT_LOAD_TARGET_LIGHT) && defined(FT_LOAD_TARGET_NORMAL)
  746. if( !(mnLoadFlags & FT_LOAD_NO_HINTING) && (nFTVERSION >= 2103))
  747. {
  748. mnLoadFlags |= FT_LOAD_TARGET_NORMAL;
  749. switch( rFontOptions.GetHintStyle() )
  750. {
  751. case HINT_NONE:
  752. mnLoadFlags |= FT_LOAD_NO_HINTING;
  753. break;
  754. case HINT_SLIGHT:
  755. mnLoadFlags |= FT_LOAD_TARGET_LIGHT;
  756. break;
  757. case HINT_MEDIUM:
  758. break;
  759. case HINT_FULL:
  760. default:
  761. break;
  762. }
  763. }
  764. #endif
  765. }
  766. // -----------------------------------------------------------------------
  767. bool FreetypeServerFont::TestFont() const
  768. {
  769. return mbFaceOk;
  770. }
  771. // -----------------------------------------------------------------------
  772. FreetypeServerFont::~FreetypeServerFont()
  773. {
  774. if( mpLayoutEngine )
  775. delete mpLayoutEngine;
  776. if( maRecodeConverter )
  777. rtl_destroyUnicodeToTextConverter( maRecodeConverter );
  778. if( maSizeFT )
  779. pFTDoneSize( maSizeFT );
  780. mpFontInfo->ReleaseFaceFT( maFaceFT );
  781. }
  782. // -----------------------------------------------------------------------
  783. int FreetypeServerFont::GetEmUnits() const
  784. {
  785. return maFaceFT->units_per_EM;
  786. }
  787. // -----------------------------------------------------------------------
  788. void FreetypeServerFont::FetchFontMetric( ImplFontMetricData& rTo, long& rFactor ) const
  789. {
  790. static_cast<ImplFontAttributes&>(rTo) = mpFontInfo->GetFontAttributes();
  791. rTo.mbScalableFont = true;
  792. rTo.mbDevice = true;
  793. rTo.mbKernableFont = (FT_HAS_KERNING( maFaceFT ) != 0) || mpFontInfo->HasExtraKerning();
  794. rTo.mnOrientation = GetFontSelData().mnOrientation;
  795. //Always consider [star]symbol as symbol fonts
  796. if (
  797. (rTo.GetFamilyName().EqualsAscii("OpenSymbol")) ||
  798. (rTo.GetFamilyName().EqualsAscii("StarSymbol"))
  799. )
  800. {
  801. rTo.mbSymbolFlag = true;
  802. }
  803. if( maSizeFT )
  804. pFTActivateSize( maSizeFT );
  805. rFactor = 0x100;
  806. rTo.mnWidth = mnWidth;
  807. const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
  808. rTo.mnAscent = (+rMetrics.ascender + 32) >> 6;
  809. #if (FTVERSION < 2000)
  810. rTo.mnDescent = (+rMetrics.descender + 32) >> 6;
  811. #else
  812. rTo.mnDescent = (-rMetrics.descender + 32) >> 6;
  813. #endif
  814. rTo.mnIntLeading = ((rMetrics.height + 32) >> 6) - (rTo.mnAscent + rTo.mnDescent);
  815. rTo.mnSlant = 0;
  816. const TT_OS2* pOS2 = (const TT_OS2*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_os2 );
  817. const TT_HoriHeader* pHHEA = (const TT_HoriHeader*)FT_Get_Sfnt_Table( maFaceFT, ft_sfnt_hhea );
  818. if( pOS2 && (pOS2->version != 0xFFFF) )
  819. {
  820. // map the panose info from the OS2 table to their VCL counterparts
  821. switch( pOS2->panose[0] )
  822. {
  823. case 1: rTo.meFamily = FAMILY_ROMAN; break;
  824. case 2: rTo.meFamily = FAMILY_SWISS; break;
  825. case 3: rTo.meFamily = FAMILY_MODERN; break;
  826. case 4: rTo.meFamily = FAMILY_SCRIPT; break;
  827. case 5: rTo.meFamily = FAMILY_DECORATIVE; break;
  828. // TODO: is it reasonable to override the attribute with DONTKNOW?
  829. case 0: // fall through
  830. default: rTo.meFamilyType = FAMILY_DONTKNOW; break;
  831. }
  832. switch( pOS2->panose[3] )
  833. {
  834. case 2: // fall through
  835. case 3: // fall through
  836. case 4: // fall through
  837. case 5: // fall through
  838. case 6: // fall through
  839. case 7: // fall through
  840. case 8: rTo.mePitch = PITCH_VARIABLE; break;
  841. case 9: rTo.mePitch = PITCH_FIXED; break;
  842. // TODO: is it reasonable to override the attribute with DONTKNOW?
  843. case 0: // fall through
  844. case 1: // fall through
  845. default: rTo.mePitch = PITCH_DONTKNOW; break;
  846. }
  847. // #108862# sanity check, some fonts treat descent as signed !!!
  848. int nDescent = pOS2->usWinDescent;
  849. if( nDescent > 5*maFaceFT->units_per_EM )
  850. nDescent = (short)pOS2->usWinDescent; // interpret it as signed!
  851. const double fScale = (double)GetFontSelData().mnHeight / maFaceFT->units_per_EM;
  852. if( pOS2->usWinAscent || pOS2->usWinDescent ) // #i30551#
  853. {
  854. rTo.mnAscent = (long)( +pOS2->usWinAscent * fScale + 0.5 );
  855. rTo.mnDescent = (long)( +nDescent * fScale + 0.5 );
  856. rTo.mnIntLeading = (long)( (+pOS2->usWinAscent + pOS2->usWinDescent - maFaceFT->units_per_EM) * fScale + 0.5 );
  857. }
  858. rTo.mnExtLeading = 0;
  859. if( (pHHEA != NULL) && (pOS2->usWinAscent || pOS2->usWinDescent) )
  860. {
  861. int nExtLeading = pHHEA->Line_Gap;
  862. nExtLeading -= (pOS2->usWinAscent + pOS2->usWinDescent);
  863. nExtLeading += (pHHEA->Ascender - pHHEA->Descender);
  864. if( nExtLeading > 0 )
  865. rTo.mnExtLeading = (long)(nExtLeading * fScale + 0.5);
  866. }
  867. // Check for CJK capabilities of the current font
  868. // #107888# workaround for Asian...
  869. // TODO: remove when ExtLeading fully implemented
  870. BOOL bCJKCapable = ((pOS2->ulUnicodeRange2 & 0x2DF00000) != 0);
  871. if ( bCJKCapable && (pOS2->usWinAscent || pOS2->usWinDescent) )
  872. {
  873. rTo.mnIntLeading += rTo.mnExtLeading;
  874. // #109280# The line height for Asian fonts is too small.
  875. // Therefore we add half of the external leading to the
  876. // ascent, the other half is added to the descent.
  877. const long nHalfTmpExtLeading = rTo.mnExtLeading / 2;
  878. const long nOtherHalfTmpExtLeading = rTo.mnExtLeading -
  879. nHalfTmpExtLeading;
  880. // #110641# external leading for Asian fonts.
  881. // The factor 0.3 has been verified during experiments.
  882. const long nCJKExtLeading = (long)(0.30 * (rTo.mnAscent + rTo.mnDescent));
  883. if ( nCJKExtLeading > rTo.mnExtLeading )
  884. rTo.mnExtLeading = nCJKExtLeading - rTo.mnExtLeading;
  885. else
  886. rTo.mnExtLeading = 0;
  887. rTo.mnAscent += nHalfTmpExtLeading;
  888. rTo.mnDescent += nOtherHalfTmpExtLeading;
  889. }
  890. }
  891. // initialize kashida width
  892. // TODO: what if there are different versions of this glyph available
  893. rTo.mnMinKashida = rTo.mnAscent / 4; // a reasonable default
  894. const int nKashidaGlyphId = GetRawGlyphIndex( 0x0640 );
  895. if( nKashidaGlyphId )
  896. {
  897. GlyphData aGlyphData;
  898. InitGlyphData( nKashidaGlyphId, aGlyphData );
  899. rTo.mnMinKashida = aGlyphData.GetMetric().GetCharWidth();
  900. }
  901. }
  902. // -----------------------------------------------------------------------
  903. static inline void SplitGlyphFlags( const FreetypeServerFont& rFont, int& nGlyphIndex, int& nGlyphFlags )
  904. {
  905. nGlyphFlags = nGlyphIndex & GF_FLAGMASK;
  906. nGlyphIndex &= GF_IDXMASK;
  907. if( nGlyphIndex & GF_ISCHAR )
  908. nGlyphIndex = rFont.GetRawGlyphIndex( nGlyphIndex );
  909. }
  910. // -----------------------------------------------------------------------
  911. int FreetypeServerFont::ApplyGlyphTransform( int nGlyphFlags,
  912. FT_Glyph pGlyphFT, bool bForBitmapProcessing ) const
  913. {
  914. int nAngle = GetFontSelData().mnOrientation;
  915. // shortcut most common case
  916. if( !nAngle && !nGlyphFlags )
  917. return nAngle;
  918. const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
  919. FT_Vector aVector;
  920. FT_Matrix aMatrix;
  921. bool bStretched = false;
  922. switch( nGlyphFlags & GF_ROTMASK )
  923. {
  924. default: // straight
  925. aVector.x = 0;
  926. aVector.y = 0;
  927. aMatrix.xx = +mnCos;
  928. aMatrix.yy = +mnCos;
  929. aMatrix.xy = -mnSin;
  930. aMatrix.yx = +mnSin;
  931. break;
  932. case GF_ROTL: // left
  933. nAngle += 900;
  934. bStretched = (mfStretch != 1.0);
  935. aVector.x = (FT_Pos)(+rMetrics.descender * mfStretch);
  936. aVector.y = -rMetrics.ascender;
  937. aMatrix.xx = (FT_Pos)(-mnSin / mfStretch);
  938. aMatrix.yy = (FT_Pos)(-mnSin * mfStretch);
  939. aMatrix.xy = (FT_Pos)(-mnCos * mfStretch);
  940. aMatrix.yx = (FT_Pos)(+mnCos / mfStretch);
  941. break;
  942. case GF_ROTR: // right
  943. nAngle -= 900;
  944. bStretched = (mfStretch != 1.0);
  945. aVector.x = -maFaceFT->glyph->metrics.horiAdvance;
  946. aVector.x += (FT_Pos)(rMetrics.descender * mnSin/65536.0);
  947. aVector.y = (FT_Pos)(-rMetrics.descender * mfStretch * mnCos/65536.0);
  948. aMatrix.xx = (FT_Pos)(+mnSin / mfStretch);
  949. aMatrix.yy = (FT_Pos)(+mnSin * mfStretch);
  950. aMatrix.xy = (FT_Pos)(+mnCos * mfStretch);
  951. aMatrix.yx = (FT_Pos)(-mnCos / mfStretch);
  952. break;
  953. }
  954. while( nAngle < 0 )
  955. nAngle += 3600;
  956. if( pGlyphFT->format != FT_GLYPH_FORMAT_BITMAP )
  957. {
  958. FT_Glyph_Transform( pGlyphFT, NULL, &aVector );
  959. // orthogonal transforms are better handled by bitmap operations
  960. if( bStretched || (bForBitmapProcessing && (nAngle % 900) != 0) )
  961. {
  962. // workaround for compatibility with older FT versions
  963. if( nFTVERSION < 2102 )
  964. {
  965. FT_Fixed t = aMatrix.xy;
  966. aMatrix.xy = aMatrix.yx;
  967. aMatrix.yx = t;
  968. }
  969. // apply non-orthogonal or stretch transformations
  970. FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
  971. nAngle = 0;
  972. }
  973. }
  974. else
  975. {
  976. // FT<=2005 ignores transforms for bitmaps, so do it manually
  977. FT_BitmapGlyph pBmpGlyphFT = reinterpret_cast<FT_BitmapGlyph>(pGlyphFT);
  978. pBmpGlyphFT->left += (aVector.x + 32) >> 6;
  979. pBmpGlyphFT->top += (aVector.y + 32) >> 6;
  980. }
  981. return nAngle;
  982. }
  983. // -----------------------------------------------------------------------
  984. int FreetypeServerFont::GetRawGlyphIndex( sal_UCS4 aChar ) const
  985. {
  986. if( mpFontInfo->IsSymbolFont() )
  987. {
  988. if( !FT_IS_SFNT( maFaceFT ) )
  989. {
  990. if( (aChar & 0xFF00) == 0xF000 )
  991. aChar &= 0xFF; // PS font symbol mapping
  992. else if( aChar > 0xFF )
  993. return 0;
  994. }
  995. }
  996. // if needed recode from unicode to font encoding
  997. if( maRecodeConverter )
  998. {
  999. sal_Char aTempArray[8];
  1000. sal_Size nTempSize;
  1001. sal_uInt32 nCvtInfo;
  1002. // assume that modern UCS4 fonts have unicode CMAPs
  1003. // => no encoding remapping to unicode is needed
  1004. if( aChar > 0xFFFF )
  1005. return 0;
  1006. sal_Unicode aUCS2Char = static_cast<sal_Unicode>(aChar);
  1007. rtl_UnicodeToTextContext aContext = rtl_createUnicodeToTextContext( maRecodeConverter );
  1008. int nChars = rtl_convertUnicodeToText( maRecodeConverter, aContext,
  1009. &aUCS2Char, 1, aTempArray, sizeof(aTempArray),
  1010. RTL_UNICODETOTEXT_FLAGS_UNDEFINED_QUESTIONMARK
  1011. | RTL_UNICODETOTEXT_FLAGS_INVALID_QUESTIONMARK,
  1012. &nCvtInfo, &nTempSize );
  1013. rtl_destroyUnicodeToTextContext( maRecodeConverter, aContext );
  1014. aChar = 0;
  1015. for( int i = 0; i < nChars; ++i )
  1016. aChar = aChar*256 + (aTempArray[i] & 0xFF);
  1017. }
  1018. // cache glyph indexes in font info to share between different sizes
  1019. int nGlyphIndex = mpFontInfo->GetGlyphIndex( aChar );
  1020. if( nGlyphIndex < 0 )
  1021. {
  1022. nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar );
  1023. if( !nGlyphIndex)
  1024. {
  1025. // check if symbol aliasing helps
  1026. if( (aChar <= 0x00FF) && mpFontInfo->IsSymbolFont() )
  1027. nGlyphIndex = FT_Get_Char_Index( maFaceFT, aChar | 0xF000 );
  1028. #if 0 // disabled for now because it introduced ae bad side-effect (#i88376#)
  1029. // Finally try the postscript name table
  1030. if (!nGlyphIndex)
  1031. nGlyphIndex = psp::PrintFontManager::get().FreeTypeCharIndex( maFaceFT, aChar );
  1032. #endif
  1033. }
  1034. mpFontInfo->CacheGlyphIndex( aChar, nGlyphIndex );
  1035. }
  1036. return nGlyphIndex;
  1037. }
  1038. // -----------------------------------------------------------------------
  1039. int FreetypeServerFont::FixupGlyphIndex( int nGlyphIndex, sal_UCS4 aChar ) const
  1040. {
  1041. int nGlyphFlags = GF_NONE;
  1042. // do glyph substitution if necessary
  1043. // CJK vertical writing needs special treatment
  1044. if( GetFontSelData().mbVertical )
  1045. {
  1046. // TODO: rethink when GSUB is used for non-vertical case
  1047. GlyphSubstitution::const_iterator it = maGlyphSubstitution.find( nGlyphIndex );
  1048. if( it == maGlyphSubstitution.end() )
  1049. {
  1050. int nTemp = GetVerticalChar( aChar );
  1051. if( nTemp ) // is substitution possible
  1052. nTemp = GetRawGlyphIndex( nTemp );
  1053. if( nTemp ) // substitute manually if sensible
  1054. nGlyphIndex = nTemp | (GF_GSUB | GF_ROTL);
  1055. else
  1056. nGlyphFlags |= GetVerticalFlags( aChar );
  1057. }
  1058. else
  1059. {
  1060. // for vertical GSUB also compensate for nOrientation=2700
  1061. nGlyphIndex = (*it).second;
  1062. nGlyphFlags |= GF_GSUB | GF_ROTL;
  1063. }
  1064. }
  1065. #if 0
  1066. // #95556# autohinting not yet optimized for non-western glyph styles
  1067. if( !(mnLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_FORCE_AUTOHINT) )
  1068. && ( (aChar >= 0x0600 && aChar < 0x1E00) // south-east asian + arabic
  1069. ||(aChar >= 0x2900 && aChar < 0xD800) // CJKV
  1070. ||(aChar >= 0xF800) ) ) // presentation + symbols
  1071. {
  1072. nGlyphFlags |= GF_UNHINTED;
  1073. }
  1074. #endif
  1075. if( nGlyphIndex != 0 )
  1076. nGlyphIndex |= nGlyphFlags;
  1077. return nGlyphIndex;
  1078. }
  1079. // -----------------------------------------------------------------------
  1080. int FreetypeServerFont::GetGlyphIndex( sal_UCS4 aChar ) const
  1081. {
  1082. int nGlyphIndex = GetRawGlyphIndex( aChar );
  1083. nGlyphIndex = FixupGlyphIndex( nGlyphIndex, aChar );
  1084. return nGlyphIndex;
  1085. }
  1086. // -----------------------------------------------------------------------
  1087. static int lcl_GetCharWidth( FT_FaceRec_* pFaceFT, double fStretch, int nGlyphFlags )
  1088. {
  1089. int nCharWidth = pFaceFT->glyph->metrics.horiAdvance;
  1090. if( nGlyphFlags & GF_ROTMASK ) // for bVertical rotated glyphs
  1091. {
  1092. const FT_Size_Metrics& rMetrics = pFaceFT->size->metrics;
  1093. #if (FTVERSION < 2000)
  1094. nCharWidth = (int)((rMetrics.height - rMetrics.descender) * fStretch);
  1095. #else
  1096. nCharWidth = (int)((rMetrics.height + rMetrics.descender) * fStretch);
  1097. #endif
  1098. }
  1099. return (nCharWidth + 32) >> 6;
  1100. }
  1101. // -----------------------------------------------------------------------
  1102. void FreetypeServerFont::InitGlyphData( int nGlyphIndex, GlyphData& rGD ) const
  1103. {
  1104. if( maSizeFT )
  1105. pFTActivateSize( maSizeFT );
  1106. int nGlyphFlags;
  1107. SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
  1108. int nLoadFlags = mnLoadFlags;
  1109. // if( mbArtItalic )
  1110. // nLoadFlags |= FT_LOAD_NO_BITMAP;
  1111. FT_Error rc = -1;
  1112. #if (FTVERSION <= 2008)
  1113. // #88364# freetype<=2005 prefers autohinting to embedded bitmaps
  1114. // => first we have to try without hinting
  1115. if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 )
  1116. {
  1117. rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags|FT_LOAD_NO_HINTING );
  1118. if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format!=FT_GLYPH_FORMAT_BITMAP) )
  1119. rc = -1; // mark as "loading embedded bitmap" was unsuccessful
  1120. nLoadFlags |= FT_LOAD_NO_BITMAP;
  1121. }
  1122. if( rc != FT_Err_Ok )
  1123. #endif
  1124. rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
  1125. if( rc != FT_Err_Ok )
  1126. {
  1127. // we get here e.g. when a PS font lacks the default glyph
  1128. rGD.SetCharWidth( 0 );
  1129. rGD.SetDelta( 0, 0 );
  1130. rGD.SetOffset( 0, 0 );
  1131. rGD.SetSize( Size( 0, 0 ) );
  1132. return;
  1133. }
  1134. const bool bOriginallyZeroWidth = (maFaceFT->glyph->metrics.horiAdvance == 0);
  1135. if( mbArtBold && pFTEmbolden )
  1136. (*pFTEmbolden)( maFaceFT->glyph );
  1137. const int nCharWidth = bOriginallyZeroWidth ? 0 : lcl_GetCharWidth( maFaceFT, mfStretch, nGlyphFlags );
  1138. rGD.SetCharWidth( nCharWidth );
  1139. FT_Glyph pGlyphFT;
  1140. rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
  1141. ApplyGlyphTransform( nGlyphFlags, pGlyphFT, false );
  1142. if( mbArtBold && pFTEmbolden && (nFTVERSION < 2200) ) // #i71094# workaround staircase bug
  1143. pGlyphFT->advance.y = 0;
  1144. rGD.SetDelta( (pGlyphFT->advance.x + 0x8000) >> 16, -((pGlyphFT->advance.y + 0x8000) >> 16) );
  1145. FT_BBox aBbox;
  1146. FT_Glyph_Get_CBox( pGlyphFT, FT_GLYPH_BBOX_PIXELS, &aBbox );
  1147. if( aBbox.yMin > aBbox.yMax ) // circumvent freetype bug
  1148. {
  1149. int t=aBbox.yMin; aBbox.yMin=aBbox.yMax, aBbox.yMax=t;
  1150. }
  1151. rGD.SetOffset( aBbox.xMin, -aBbox.yMax );
  1152. rGD.SetSize( Size( (aBbox.xMax-aBbox.xMin+1), (aBbox.yMax-aBbox.yMin) ) );
  1153. FT_Done_Glyph( pGlyphFT );
  1154. }
  1155. // -----------------------------------------------------------------------
  1156. bool FreetypeServerFont::GetAntialiasAdvice( void ) const
  1157. {
  1158. if( GetFontSelData().mbNonAntialiased || (mnPrioAntiAlias<=0) )
  1159. return false;
  1160. bool bAdviseAA = true;
  1161. // TODO: also use GASP info
  1162. return bAdviseAA;
  1163. }
  1164. // -----------------------------------------------------------------------
  1165. bool FreetypeServerFont::GetGlyphBitmap1( int nGlyphIndex, RawBitmap& rRawBitmap ) const
  1166. {
  1167. if( maSizeFT )
  1168. pFTActivateSize( maSizeFT );
  1169. int nGlyphFlags;
  1170. SplitGlyphFlags( *this, nGlyphIndex, nGlyphFlags );
  1171. FT_Int nLoadFlags = mnLoadFlags;
  1172. // #i70930# force mono-hinting for monochrome text
  1173. if( nFTVERSION >= 2110 ) //#i71947# unless it looks worse
  1174. {
  1175. nLoadFlags &= ~0xF0000;
  1176. nLoadFlags |= FT_LOAD_TARGET_MONO;
  1177. }
  1178. if( mbArtItalic )
  1179. nLoadFlags |= FT_LOAD_NO_BITMAP;
  1180. #if (FTVERSION >= 2002)
  1181. // for 0/90/180/270 degree fonts enable hinting even if not advisable
  1182. // non-hinted and non-antialiased bitmaps just look too ugly
  1183. if( (mnCos==0 || mnSin==0) && (mnPrioAutoHint > 0) )
  1184. nLoadFlags &= ~FT_LOAD_NO_HINTING;
  1185. #endif
  1186. if( mnPrioEmbedded <= mnPrioAutoHint )
  1187. nLoadFlags |= FT_LOAD_NO_BITMAP;
  1188. FT_Error rc = -1;
  1189. #if (FTVERSION <= 2008)
  1190. // #88364# freetype<=2005 prefers autohinting to embedded bitmaps
  1191. // => first we have to try without hinting
  1192. if( (nLoadFlags & (FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) == 0 )
  1193. {
  1194. rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags|FT_LOAD_NO_HINTING );
  1195. if( (rc==FT_Err_Ok) && (maFaceFT->glyph->format != FT_GLYPH_FORMAT_BITMAP) )
  1196. rc = -1; // mark as "loading embedded bitmap" was unsuccessful
  1197. nLoadFlags |= FT_LOAD_NO_BITMAP;
  1198. }
  1199. if( rc != FT_Err_Ok )
  1200. #endif
  1201. rc = FT_Load_Glyph( maFaceFT, nGlyphIndex, nLoadFlags );
  1202. if( rc != FT_Err_Ok )
  1203. return false;
  1204. if( mbArtBold && pFTEmbolden )
  1205. (*pFTEmbolden)( maFaceFT->glyph );
  1206. FT_Glyph pGlyphFT;
  1207. rc = FT_Get_Glyph( maFaceFT->glyph, &pGlyphFT );
  1208. if( rc != FT_Err_Ok )
  1209. return false;
  1210. int nAngle = ApplyGlyphTransform( nGlyphFlags, pGlyphFT, true );
  1211. if( mbArtItalic )
  1212. {
  1213. FT_Matrix aMatrix;
  1214. aMatrix.xx = aMatrix.yy = 0x10000L;
  1215. if( nFTVERSION >= 2102 ) // Freetype 2.1.2 API swapped xy with yx
  1216. aMatrix.xy = 0x6000L, aMatrix.yx = 0;
  1217. else
  1218. aMatrix.yx = 0x6000L, aMatrix.xy = 0;
  1219. FT_Glyph_Transform( pGlyphFT, &aMatrix, NULL );
  1220. }
  1221. // Check for zero area bounding boxes as this crashes some versions of FT.
  1222. // This also provides a handy short cut as much of the code following
  1223. // becomes an expensive nop when a glyph covers no pixels.
  1224. FT_BBox cbox;
  1225. FT_Glyph_Get_CBox(pGlyphFT, ft_glyph_bbox_unscaled, &cbox);
  1226. if( (cbox.xMax - cbox.xMin) ==

Large files files are truncated, but you can click here to view the full file