1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
26 #include "gcach_ftyp.hxx"
28 #include "vcl/svapp.hxx"
29 #include <outfont.hxx>
30 #include <impfont.hxx>
31 #include <config_graphite.h>
33 #include <graphite2/Font.h>
34 #include <graphite_layout.hxx>
37 #include "tools/poly.hxx"
38 #include "basegfx/matrix/b2dhommatrix.hxx"
39 #include "basegfx/matrix/b2dhommatrixtools.hxx"
40 #include "basegfx/polygon/b2dpolypolygon.hxx"
42 #include "osl/file.hxx"
43 #include "osl/thread.hxx"
45 #include "langboost.hxx"
49 #include FT_FREETYPE_H
52 #include FT_TRUETYPE_TABLES_H
53 #include FT_TRUETYPE_TAGS_H
54 #include FT_TRUETYPE_IDS_H
58 #include FT_SYNTHESIS_H
61 #ifndef FT_RENDER_MODE_MONO // happens in the MACOSX build
62 #define FT_RENDER_MODE_MONO ft_render_mode_mono
64 #include "rtl/instance.hxx"
66 #define FTVERSION (1000*FREETYPE_MAJOR + 100*FREETYPE_MINOR + FREETYPE_PATCH)
69 typedef const FT_Vector
* FT_Vector_CPtr
;
70 #else // FTVERSION < 2200
71 typedef FT_Vector
* FT_Vector_CPtr
;
76 // TODO: move file mapping stuff to OSL
78 // PORTERS: dlfcn is used for getting symbols from FT versions newer than baseline
84 #include "vcl/fontmanager.hxx"
87 #define strncasecmp strnicmp
90 typedef const unsigned char* CPU8
;
91 inline sal_uInt16
NEXT_U16( CPU8
& p
) { p
+=2; return (p
[-2]<<8)|p
[-1]; }
92 inline sal_Int16
NEXT_S16( CPU8
& p
) { return (sal_Int16
)NEXT_U16(p
); }
93 inline sal_uInt32
NEXT_U32( CPU8
& p
) { p
+=4; return (p
[-4]<<24)|(p
[-3]<<16)|(p
[-2]<<8)|p
[-1]; }
94 //inline sal_Int32 NEXT_S32( U8*& p ) { return (sal_Int32)NEXT_U32(p); }
96 // -----------------------------------------------------------------------
98 // the gamma table makes artificial bold look better for CJK glyphs
99 static unsigned char aGammaTable
[257];
101 static void InitGammaTable()
103 static const int M_MAX
= 255;
104 static const int M_X
= 128;
105 static const int M_Y
= 208;
108 for( x
= 0; x
< 256; x
++)
111 a
= ( x
* M_Y
+ M_X
/ 2) / M_X
;
113 a
= M_Y
+ ( ( x
- M_X
) * ( M_MAX
- M_Y
) +
114 ( M_MAX
- M_X
) / 2 ) / ( M_MAX
- M_X
);
116 aGammaTable
[x
] = (unsigned char)a
;
120 // -----------------------------------------------------------------------
122 static FT_Library aLibFT
= 0;
124 // #110607# enable linking with old FT versions
125 static int nFTVERSION
= 0;
126 static FT_Error (*pFTNewSize
)(FT_Face
,FT_Size
*);
127 static FT_Error (*pFTActivateSize
)(FT_Size
);
128 static FT_Error (*pFTDoneSize
)(FT_Size
);
129 void (*pFTEmbolden
)(FT_GlyphSlot
);
130 static FT_UInt (*pFT_Face_GetCharVariantIndex
)(FT_Face
, FT_ULong
, FT_ULong
);
131 static bool bEnableSizeFT
= false;
133 typedef ::boost::unordered_map
<const char*, boost::shared_ptr
<FtFontFile
>, rtl::CStringHash
, rtl::CStringEqual
> FontFileList
;
135 namespace { struct vclFontFileList
: public rtl::Static
< FontFileList
, vclFontFileList
> {}; }
137 // -----------------------------------------------------------------------
139 // TODO: remove when the priorities are selected by UI
140 // if (AH==0) => disable autohinting
141 // if (AA==0) => disable antialiasing
142 // if (EB==0) => disable embedded bitmaps
143 // if (AA prio <= AH prio) => antialias + autohint
144 // if (AH<AA) => do not autohint when antialiasing
145 // if (EB<AH) => do not autohint for monochrome
146 static int nDefaultPrioEmbedded
= 2;
147 static int nDefaultPrioAutoHint
= 1;
148 static int nDefaultPrioAntiAlias
= 1;
150 // =======================================================================
152 // =======================================================================
154 FtFontFile::FtFontFile( const OString
& rNativeFileName
)
155 : maNativeFileName( rNativeFileName
),
161 // boost font preference if UI language is mentioned in filename
162 int nPos
= maNativeFileName
.lastIndexOf( '_' );
163 if( nPos
== -1 || maNativeFileName
[nPos
+1] == '.' )
164 mnLangBoost
+= 0x1000; // no langinfo => good
167 static const char* pLangBoost
= NULL
;
168 static bool bOnce
= true;
172 pLangBoost
= vcl::getLangBoost();
175 if( pLangBoost
&& !strncasecmp( pLangBoost
, &maNativeFileName
.getStr()[nPos
+1], 3 ) )
176 mnLangBoost
+= 0x2000; // matching langinfo => better
180 // -----------------------------------------------------------------------
182 FtFontFile
* FtFontFile::FindFontFile( const OString
& rNativeFileName
)
184 // font file already known? (e.g. for ttc, synthetic, aliased fonts)
185 const char* pFileName
= rNativeFileName
.getStr();
186 FontFileList
&rFontFileList
= vclFontFileList::get();
187 FontFileList::const_iterator it
= rFontFileList
.find( pFileName
);
188 if( it
!= rFontFileList
.end() )
189 return it
->second
.get();
191 // no => create new one
192 FtFontFile
* pFontFile
= new FtFontFile( rNativeFileName
);
193 pFileName
= pFontFile
->maNativeFileName
.getStr();
194 rFontFileList
[pFileName
].reset(pFontFile
);
198 // -----------------------------------------------------------------------
200 bool FtFontFile::Map()
202 if( mnRefCount
++ <= 0 )
204 const char* pFileName
= maNativeFileName
.getStr();
206 int nFile
= open( pFileName
, O_RDONLY
);
211 fstat( nFile
, &aStat
);
212 mnFileSize
= aStat
.st_size
;
213 mpFileMap
= (const unsigned char*)
214 mmap( NULL
, mnFileSize
, PROT_READ
, MAP_SHARED
, nFile
, 0 );
215 if( mpFileMap
== MAP_FAILED
)
219 void* pFileDesc
= ::CreateFile( pFileName
, GENERIC_READ
, FILE_SHARE_READ
,
220 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0 );
221 if( pFileDesc
== INVALID_HANDLE_VALUE
)
224 mnFileSize
= ::GetFileSize( pFileDesc
, NULL
);
225 HANDLE aHandle
= ::CreateFileMapping( pFileDesc
, NULL
, PAGE_READONLY
, 0, mnFileSize
, "TTF" );
226 mpFileMap
= (const unsigned char*)::MapViewOfFile( aHandle
, FILE_MAP_READ
, 0, 0, mnFileSize
);
227 ::CloseHandle( pFileDesc
);
229 FILE* pFile
= fopen( pFileName
, "rb" );
234 stat( pFileName
, &aStat
);
235 mnFileSize
= aStat
.st_size
;
236 mpFileMap
= new unsigned char[ mnFileSize
];
237 if( mnFileSize
!= fread( mpFileMap
, 1, mnFileSize
, pFile
) )
246 return (mpFileMap
!= NULL
);
249 // -----------------------------------------------------------------------
251 void FtFontFile::Unmap()
253 if( (--mnRefCount
> 0) || (mpFileMap
== NULL
) )
257 munmap( (char*)mpFileMap
, mnFileSize
);
259 UnmapViewOfFile( (LPCVOID
)mpFileMap
);
268 // wrap FtFontInfo's table function
269 const void * graphiteFontTable(const void* appFaceHandle
, unsigned int name
, size_t *len
)
271 const FtFontInfo
* pFontInfo
= reinterpret_cast<const FtFontInfo
*>(appFaceHandle
);
278 #ifndef OSL_BIGENDIAN
280 swapped
.m_c
[3] = tableId
.m_c
[0];
281 swapped
.m_c
[2] = tableId
.m_c
[1];
282 swapped
.m_c
[1] = tableId
.m_c
[2];
283 swapped
.m_c
[0] = tableId
.m_c
[3];
284 tableId
.m_id
= swapped
.m_id
;
286 tableId
.m_c
[4] = '\0';
287 sal_uLong nLength
= 0;
288 const void * pTable
= static_cast<const void*>(pFontInfo
->GetTable(tableId
.m_c
, &nLength
));
289 if (len
) *len
= static_cast<size_t>(nLength
);
294 // =======================================================================
296 FtFontInfo::FtFontInfo( const ImplDevFontAttributes
& rDevFontAttributes
,
297 const OString
& rNativeFileName
, int nFaceNum
, sal_IntPtr nFontId
, int nSynthetic
,
298 const ExtraKernInfo
* pExtraKernInfo
)
301 mpFontFile( FtFontFile::FindFontFile( rNativeFileName
) ),
302 mnFaceNum( nFaceNum
),
304 mnSynthetic( nSynthetic
),
306 mbCheckedGraphite(false),
307 mpGraphiteFace(NULL
),
310 maDevFontAttributes( rDevFontAttributes
),
311 mpFontCharMap( NULL
),
312 mpChar2Glyph( NULL
),
313 mpGlyph2Char( NULL
),
314 mpExtraKernInfo( pExtraKernInfo
)
316 // prefer font with low ID
317 maDevFontAttributes
.mnQuality
+= 10000 - nFontId
;
318 // prefer font with matching file names
319 maDevFontAttributes
.mnQuality
+= mpFontFile
->GetLangBoost();
320 // prefer font with more external info
322 maDevFontAttributes
.mnQuality
+= 100;
325 // -----------------------------------------------------------------------
327 FtFontInfo::~FtFontInfo()
330 mpFontCharMap
->DeReference();
331 delete mpExtraKernInfo
;
335 delete mpGraphiteFace
;
339 void FtFontInfo::InitHashes() const
341 // TODO: avoid pointers when empty stl::hash_* objects become cheap
342 mpChar2Glyph
= new Int2IntMap();
343 mpGlyph2Char
= new Int2IntMap();
346 // -----------------------------------------------------------------------
348 FT_FaceRec_
* FtFontInfo::GetFaceFT()
350 // get faceFT once/multiple depending on availability of SizeFT APIs
351 if( (mnRefCount
++ <= 0) || !bEnableSizeFT
)
353 if( !mpFontFile
->Map() )
355 FT_Error rc
= FT_New_Memory_Face( aLibFT
,
356 (FT_Byte
*)mpFontFile
->GetBuffer(),
357 mpFontFile
->GetFileSize(), mnFaceNum
, &maFaceFT
);
358 if( (rc
!= FT_Err_Ok
) || (maFaceFT
->num_glyphs
<= 0) )
366 GraphiteFaceWrapper
* FtFontInfo::GetGraphiteFace()
368 if (mbCheckedGraphite
)
369 return mpGraphiteFace
;
370 // test for graphite here so that it is cached most efficiently
371 if (GetTable("Silf", 0))
373 static const char* pGraphiteCacheStr
= getenv( "SAL_GRAPHITE_CACHE_SIZE" );
374 int graphiteSegCacheSize
= pGraphiteCacheStr
? (atoi(pGraphiteCacheStr
)) : 0;
375 gr_face
* pGraphiteFace
;
376 if (graphiteSegCacheSize
> 500)
377 pGraphiteFace
= gr_make_face_with_seg_cache(this, graphiteFontTable
, graphiteSegCacheSize
, gr_face_cacheCmap
);
379 pGraphiteFace
= gr_make_face(this, graphiteFontTable
, gr_face_cacheCmap
);
381 mpGraphiteFace
= new GraphiteFaceWrapper(pGraphiteFace
);
383 mbCheckedGraphite
= true;
384 return mpGraphiteFace
;
388 // -----------------------------------------------------------------------
390 void FtFontInfo::ReleaseFaceFT( FT_FaceRec_
* pFaceFT
)
392 // release last/each depending on SizeFT availability
393 if( (--mnRefCount
<= 0) || !bEnableSizeFT
)
395 FT_Done_Face( pFaceFT
);
401 // -----------------------------------------------------------------------
403 bool FtFontInfo::HasExtraKerning() const
405 if( !mpExtraKernInfo
)
407 // TODO: how to enable the line below without getting #i29881# back?
408 // on the other hand being too optimistic doesn't cause problems
409 // return mpExtraKernInfo->HasKernPairs();
413 // -----------------------------------------------------------------------
415 int FtFontInfo::GetExtraKernPairs( ImplKernPairData
** ppKernPairs
) const
417 if( !mpExtraKernInfo
)
419 return mpExtraKernInfo
->GetUnscaledKernPairs( ppKernPairs
);
422 // -----------------------------------------------------------------------
424 static unsigned GetUInt( const unsigned char* p
) { return((p
[0]<<24)+(p
[1]<<16)+(p
[2]<<8)+p
[3]);}
425 static unsigned GetUShort( const unsigned char* p
){ return((p
[0]<<8)+p
[1]);}
426 //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
428 static const sal_uInt32 T_true
= 0x74727565; /* 'true' */
429 static const sal_uInt32 T_ttcf
= 0x74746366; /* 'ttcf' */
430 static const sal_uInt32 T_otto
= 0x4f54544f; /* 'OTTO' */
432 const unsigned char* FtFontInfo::GetTable( const char* pTag
, sal_uLong
* pLength
) const
434 const unsigned char* pBuffer
= mpFontFile
->GetBuffer();
435 int nFileSize
= mpFontFile
->GetFileSize();
436 if( !pBuffer
|| nFileSize
<1024 )
439 // we currently handle TTF, TTC and OTF headers
440 unsigned nFormat
= GetUInt( pBuffer
);
442 const unsigned char* p
= pBuffer
+ 12;
443 if( nFormat
== T_ttcf
) // TTC_MAGIC
444 p
+= GetUInt( p
+ 4 * mnFaceNum
);
445 else if( nFormat
!= 0x00010000 && nFormat
!= T_true
&& nFormat
!= T_otto
) // TTF_MAGIC and Apple TTF Magic and PS-OpenType font
448 // walk table directory until match
449 int nTables
= GetUShort( p
- 8 );
450 if( nTables
>= 64 ) // something fishy?
452 for( int i
= 0; i
< nTables
; ++i
, p
+=16 )
454 if( p
[0]==pTag
[0] && p
[1]==pTag
[1] && p
[2]==pTag
[2] && p
[3]==pTag
[3] )
456 sal_uLong nLength
= GetUInt( p
+ 12 );
457 if( pLength
!= NULL
)
459 const unsigned char* pTable
= pBuffer
+ GetUInt( p
+ 8 );
460 if( (pTable
+ nLength
) <= (mpFontFile
->GetBuffer() + nFileSize
) )
468 // -----------------------------------------------------------------------
470 void FtFontInfo::AnnounceFont( ImplDevFontList
* pFontList
)
472 ImplFTSFontData
* pFD
= new ImplFTSFontData( this, maDevFontAttributes
);
473 pFontList
->Add( pFD
);
476 // =======================================================================
478 FreetypeManager::FreetypeManager()
481 /*FT_Error rcFT =*/ FT_Init_FreeType( &aLibFT
);
484 // For Android we use the bundled static libfreetype.a, and we
485 // want to avoid accidentally finding the FT_* symbols in the
486 // system FreeType code (which *is* present in a system library,
487 // libskia.so, but is not a public API, and in fact does crash the
489 pFTNewSize
= FT_New_Size
;
490 pFTActivateSize
= FT_Activate_Size
;
491 pFTDoneSize
= FT_Done_Size
;
492 pFTEmbolden
= FT_GlyphSlot_Embolden
;
493 pFT_Face_GetCharVariantIndex
= FT_Face_GetCharVariantIndex
;
494 nFTVERSION
= FTVERSION
;
496 #ifdef RTLD_DEFAULT // true if a good dlfcn.h header was included
497 // Get version of freetype library to enable workarounds.
498 // Freetype <= 2.0.9 does not have FT_Library_Version().
499 // Using dl_sym() instead of osl_getSymbol() because latter
500 // isn't designed to work with oslModule=NULL
501 void (*pFTLibraryVersion
)(FT_Library library
,
502 FT_Int
*amajor
, FT_Int
*aminor
, FT_Int
*apatch
);
503 pFTLibraryVersion
= (void (*)(FT_Library library
,
504 FT_Int
*amajor
, FT_Int
*aminor
, FT_Int
*apatch
))(sal_IntPtr
)dlsym( RTLD_DEFAULT
, "FT_Library_Version" );
506 pFTNewSize
= (FT_Error(*)(FT_Face
,FT_Size
*))(sal_IntPtr
)dlsym( RTLD_DEFAULT
, "FT_New_Size" );
507 pFTActivateSize
= (FT_Error(*)(FT_Size
))(sal_IntPtr
)dlsym( RTLD_DEFAULT
, "FT_Activate_Size" );
508 pFTDoneSize
= (FT_Error(*)(FT_Size
))(sal_IntPtr
)dlsym( RTLD_DEFAULT
, "FT_Done_Size" );
509 pFTEmbolden
= (void(*)(FT_GlyphSlot
))(sal_IntPtr
)dlsym( RTLD_DEFAULT
, "FT_GlyphSlot_Embolden" );
510 pFT_Face_GetCharVariantIndex
= (FT_UInt(*)(FT_Face
, FT_ULong
, FT_ULong
))(sal_IntPtr
)dlsym( RTLD_DEFAULT
, "FT_Face_GetCharVariantIndex" );
512 bEnableSizeFT
= (pFTNewSize
!=NULL
) && (pFTActivateSize
!=NULL
) && (pFTDoneSize
!=NULL
);
514 FT_Int nMajor
= 0, nMinor
= 0, nPatch
= 0;
515 if( pFTLibraryVersion
)
516 pFTLibraryVersion( aLibFT
, &nMajor
, &nMinor
, &nPatch
);
517 nFTVERSION
= nMajor
* 1000 + nMinor
* 100 + nPatch
;
519 // disable artificial emboldening with the Freetype API for older versions
520 if( nFTVERSION
< 2110 )
522 // disable FT_Face_GetCharVariantIndex for older versions
523 // https://bugzilla.mozilla.org/show_bug.cgi?id=618406#c8
524 if( nFTVERSION
< 2404 )
525 pFT_Face_GetCharVariantIndex
= NULL
;
527 #else // RTLD_DEFAULT
528 // assume systems where dlsym is not possible use supplied library
529 nFTVERSION
= FTVERSION
;
532 // TODO: remove when the priorities are selected by UI
534 pEnv
= ::getenv( "SAL_EMBEDDED_BITMAP_PRIORITY" );
536 nDefaultPrioEmbedded
= pEnv
[0] - '0';
537 pEnv
= ::getenv( "SAL_ANTIALIASED_TEXT_PRIORITY" );
539 nDefaultPrioAntiAlias
= pEnv
[0] - '0';
540 pEnv
= ::getenv( "SAL_AUTOHINTING_PRIORITY" );
542 nDefaultPrioAutoHint
= pEnv
[0] - '0';
545 vclFontFileList::get();
548 // -----------------------------------------------------------------------
550 FT_Face
ServerFont::GetFtFace() const
553 pFTActivateSize( maSizeFT
);
558 // -----------------------------------------------------------------------
560 FreetypeManager::~FreetypeManager()
565 // -----------------------------------------------------------------------
567 void FreetypeManager::AddFontFile( const OString
& rNormalizedName
,
568 int nFaceNum
, sal_IntPtr nFontId
, const ImplDevFontAttributes
& rDevFontAttr
,
569 const ExtraKernInfo
* pExtraKernInfo
)
571 if( rNormalizedName
.isEmpty() )
574 if( maFontList
.find( nFontId
) != maFontList
.end() )
577 FtFontInfo
* pFontInfo
= new FtFontInfo( rDevFontAttr
,
578 rNormalizedName
, nFaceNum
, nFontId
, 0, pExtraKernInfo
);
579 maFontList
[ nFontId
] = pFontInfo
;
580 if( mnMaxFontId
< nFontId
)
581 mnMaxFontId
= nFontId
;
584 // -----------------------------------------------------------------------
586 void FreetypeManager::AnnounceFonts( ImplDevFontList
* pToAdd
) const
588 for( FontList::const_iterator it
= maFontList
.begin(); it
!= maFontList
.end(); ++it
)
590 FtFontInfo
* pFtFontInfo
= it
->second
;
591 pFtFontInfo
->AnnounceFont( pToAdd
);
595 // -----------------------------------------------------------------------
597 void FreetypeManager::ClearFontList( )
599 for( FontList::iterator it
= maFontList
.begin(); it
!= maFontList
.end(); ++it
)
601 FtFontInfo
* pFtFontInfo
= it
->second
;
607 // -----------------------------------------------------------------------
609 ServerFont
* FreetypeManager::CreateFont( const FontSelectPattern
& rFSD
)
611 FtFontInfo
* pFontInfo
= NULL
;
613 // find a FontInfo matching to the font id
614 sal_IntPtr nFontId
= reinterpret_cast<sal_IntPtr
>( rFSD
.mpFontData
);
615 FontList::iterator it
= maFontList
.find( nFontId
);
616 if( it
!= maFontList
.end() )
617 pFontInfo
= it
->second
;
622 ServerFont
* pNew
= new ServerFont( rFSD
, pFontInfo
);
627 // =======================================================================
629 ImplFTSFontData::ImplFTSFontData( FtFontInfo
* pFI
, const ImplDevFontAttributes
& rDFA
)
630 : PhysicalFontFace( rDFA
, IFTSFONT_MAGIC
),
634 mbOrientation
= true;
637 // -----------------------------------------------------------------------
639 ImplFontEntry
* ImplFTSFontData::CreateFontInstance( FontSelectPattern
& rFSD
) const
641 ImplServerFontEntry
* pEntry
= new ImplServerFontEntry( rFSD
);
645 // =======================================================================
647 // =======================================================================
649 ServerFont::ServerFont( const FontSelectPattern
& rFSD
, FtFontInfo
* pFI
)
654 mnBytesUsed( sizeof(ServerFont
) ),
655 mpPrevGCFont( NULL
),
656 mpNextGCFont( NULL
),
659 mbCollectedZW( false ),
660 mnPrioEmbedded(nDefaultPrioEmbedded
),
661 mnPrioAntiAlias(nDefaultPrioAntiAlias
),
662 mnPrioAutoHint(nDefaultPrioAutoHint
),
667 maRecodeConverter( NULL
),
668 mpLayoutEngine( NULL
)
670 // TODO: move update of mpFontEntry into FontEntry class when
671 // it becomes reponsible for the ServerFont instantiation
672 ((ImplServerFontEntry
*)rFSD
.mpFontEntry
)->SetServerFont( this );
674 if( rFSD
.mnOrientation
!= 0 )
676 const double dRad
= rFSD
.mnOrientation
* ( F_2PI
/ 3600.0 );
677 mnCos
= static_cast<long>( 0x10000 * cos( dRad
) + 0.5 );
678 mnSin
= static_cast<long>( 0x10000 * sin( dRad
) + 0.5 );
681 maFaceFT
= pFI
->GetFaceFT();
686 // set the pixel size of the font instance
687 mnWidth
= rFSD
.mnWidth
;
689 mnWidth
= rFSD
.mnHeight
;
690 mfStretch
= (double)mnWidth
/ rFSD
.mnHeight
;
691 // sanity check (e.g. #i66394#, #i66244#, #66537#)
692 if( (mnWidth
< 0) || (mfStretch
> +64.0) || (mfStretch
< -64.0) )
695 // perf: use maSizeFT if available
698 pFTNewSize( maFaceFT
, &maSizeFT
);
699 pFTActivateSize( maSizeFT
);
701 FT_Error rc
= FT_Set_Pixel_Sizes( maFaceFT
, mnWidth
, rFSD
.mnHeight
);
702 if( rc
!= FT_Err_Ok
)
705 // prepare for font encodings other than unicode or symbol
706 FT_Encoding eEncoding
= FT_ENCODING_UNICODE
;
707 if( mpFontInfo
->IsSymbolFont() )
709 if( FT_IS_SFNT( maFaceFT
) )
710 eEncoding
= ft_encoding_symbol
;
712 eEncoding
= FT_ENCODING_ADOBE_CUSTOM
; // freetype wants this for PS symbol fonts
714 rc
= FT_Select_Charmap( maFaceFT
, eEncoding
);
715 // no standard encoding applies => we need an encoding converter
716 if( rc
!= FT_Err_Ok
)
718 rtl_TextEncoding eRecodeFrom
= RTL_TEXTENCODING_UNICODE
;
719 for( int i
= maFaceFT
->num_charmaps
; --i
>= 0; )
721 const FT_CharMap aCM
= maFaceFT
->charmaps
[i
];
722 if( aCM
->platform_id
== TT_PLATFORM_MICROSOFT
)
724 switch( aCM
->encoding_id
)
727 eEncoding
= FT_ENCODING_SJIS
;
728 eRecodeFrom
= RTL_TEXTENCODING_SHIFT_JIS
;
730 case TT_MS_ID_GB2312
:
731 eEncoding
= FT_ENCODING_GB2312
;
732 eRecodeFrom
= RTL_TEXTENCODING_GB_2312
;
735 eEncoding
= FT_ENCODING_BIG5
;
736 eRecodeFrom
= RTL_TEXTENCODING_BIG5
;
738 case TT_MS_ID_WANSUNG
:
739 eEncoding
= FT_ENCODING_WANSUNG
;
740 eRecodeFrom
= RTL_TEXTENCODING_MS_949
;
743 eEncoding
= FT_ENCODING_JOHAB
;
744 eRecodeFrom
= RTL_TEXTENCODING_MS_1361
;
748 else if( aCM
->platform_id
== TT_PLATFORM_MACINTOSH
)
750 switch( aCM
->encoding_id
)
752 case TT_MAC_ID_ROMAN
:
753 eEncoding
= FT_ENCODING_APPLE_ROMAN
;
754 eRecodeFrom
= RTL_TEXTENCODING_UNICODE
; // TODO: use better match
756 // TODO: add other encodings when Mac-only
757 // non-unicode fonts show up
760 else if( aCM
->platform_id
== TT_PLATFORM_ADOBE
)
762 switch( aCM
->encoding_id
)
764 #ifdef TT_ADOBE_ID_LATIN1
765 case TT_ADOBE_ID_LATIN1
: // better unicode than nothing
766 eEncoding
= FT_ENCODING_ADOBE_LATIN_1
;
767 eRecodeFrom
= RTL_TEXTENCODING_ISO_8859_1
;
769 #endif // TT_ADOBE_ID_LATIN1
770 case TT_ADOBE_ID_STANDARD
: // better unicode than nothing
771 eEncoding
= FT_ENCODING_ADOBE_STANDARD
;
772 eRecodeFrom
= RTL_TEXTENCODING_UNICODE
; // TODO: use better match
778 if( FT_Err_Ok
!= FT_Select_Charmap( maFaceFT
, eEncoding
) )
781 if( eRecodeFrom
!= RTL_TEXTENCODING_UNICODE
)
782 maRecodeConverter
= rtl_createUnicodeToTextConverter( eRecodeFrom
);
789 // TODO: query GASP table for load flags
790 mnLoadFlags
= FT_LOAD_DEFAULT
;
791 #if 1 // #i97326# cairo sometimes uses FT_Set_Transform() on our FT_FACE
792 // we are not using FT_Set_Transform() yet, so just ignore it for now
793 mnLoadFlags
|= FT_LOAD_IGNORE_TRANSFORM
;
796 mbArtItalic
= (rFSD
.GetSlant() != ITALIC_NONE
&& pFI
->GetFontAttributes().GetSlant() == ITALIC_NONE
);
797 mbArtBold
= (rFSD
.GetWeight() > WEIGHT_MEDIUM
&& pFI
->GetFontAttributes().GetWeight() <= WEIGHT_MEDIUM
);
801 //static const int TT_CODEPAGE_RANGE_874 = (1L << 16); // Thai
802 //static const int TT_CODEPAGE_RANGE_932 = (1L << 17); // JIS/Japan
803 //static const int TT_CODEPAGE_RANGE_936 = (1L << 18); // Chinese: Simplified
804 //static const int TT_CODEPAGE_RANGE_949 = (1L << 19); // Korean Wansung
805 //static const int TT_CODEPAGE_RANGE_950 = (1L << 20); // Chinese: Traditional
806 //static const int TT_CODEPAGE_RANGE_1361 = (1L << 21); // Korean Johab
807 static const int TT_CODEPAGE_RANGES1_CJKT
= 0x3F0000; // all of the above
808 const TT_OS2
* pOs2
= (const TT_OS2
*)FT_Get_Sfnt_Table( maFaceFT
, ft_sfnt_os2
);
809 if ((pOs2
) && (pOs2
->ulCodePageRange1
& TT_CODEPAGE_RANGES1_CJKT
)
810 && rFSD
.mnHeight
< 20)
814 if( ((mnCos
!= 0) && (mnSin
!= 0)) || (mnPrioEmbedded
<= 0) )
815 mnLoadFlags
|= FT_LOAD_NO_BITMAP
;
818 void ServerFont::SetFontOptions( boost::shared_ptr
<ImplFontOptions
> pFontOptions
)
820 mpFontOptions
= pFontOptions
;
825 FontAutoHint eHint
= mpFontOptions
->GetUseAutoHint();
826 if( eHint
== AUTOHINT_DONTKNOW
)
827 eHint
= mbUseGamma
? AUTOHINT_TRUE
: AUTOHINT_FALSE
;
829 if( eHint
== AUTOHINT_TRUE
)
830 mnLoadFlags
|= FT_LOAD_FORCE_AUTOHINT
;
832 if( (mnSin
!= 0) && (mnCos
!= 0) ) // hinting for 0/90/180/270 degrees only
833 mnLoadFlags
|= FT_LOAD_NO_HINTING
;
834 mnLoadFlags
|= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
; //#88334#
836 if( mpFontOptions
->DontUseAntiAlias() )
838 if( mpFontOptions
->DontUseEmbeddedBitmaps() )
840 if( mpFontOptions
->DontUseHinting() )
843 if( mnPrioAutoHint
<= 0 )
844 mnLoadFlags
|= FT_LOAD_NO_HINTING
;
846 #if defined(FT_LOAD_TARGET_LIGHT) && defined(FT_LOAD_TARGET_NORMAL)
847 if( !(mnLoadFlags
& FT_LOAD_NO_HINTING
) )
849 mnLoadFlags
|= FT_LOAD_TARGET_NORMAL
;
850 switch( mpFontOptions
->GetHintStyle() )
853 mnLoadFlags
|= FT_LOAD_NO_HINTING
;
856 mnLoadFlags
|= FT_LOAD_TARGET_LIGHT
;
867 if( mnPrioEmbedded
<= 0 )
868 mnLoadFlags
|= FT_LOAD_NO_BITMAP
;
871 boost::shared_ptr
<ImplFontOptions
> ServerFont::GetFontOptions() const
873 return mpFontOptions
;
876 const OString
* ServerFont::GetFontFileName() const
878 return mpFontInfo
->GetFontFileName();
881 bool ServerFont::TestFont() const
886 // -----------------------------------------------------------------------
888 ServerFont::~ServerFont()
891 delete mpLayoutEngine
;
893 if( maRecodeConverter
)
894 rtl_destroyUnicodeToTextConverter( maRecodeConverter
);
897 pFTDoneSize( maSizeFT
);
899 mpFontInfo
->ReleaseFaceFT( maFaceFT
);
901 ReleaseFromGarbageCollect();
904 // -----------------------------------------------------------------------
906 int ServerFont::GetEmUnits() const
908 return maFaceFT
->units_per_EM
;
911 // -----------------------------------------------------------------------
913 void ServerFont::FetchFontMetric( ImplFontMetricData
& rTo
, long& rFactor
) const
915 static_cast<ImplFontAttributes
&>(rTo
) = mpFontInfo
->GetFontAttributes();
917 rTo
.mbScalableFont
= true;
919 rTo
.mbKernableFont
= (FT_HAS_KERNING( maFaceFT
) != 0) || mpFontInfo
->HasExtraKerning();
920 rTo
.mnOrientation
= GetFontSelData().mnOrientation
;
922 //Always consider [star]symbol as symbol fonts
924 (rTo
.GetFamilyName() == "OpenSymbol" ) ||
925 (rTo
.GetFamilyName() == "StarSymbol" )
928 rTo
.SetSymbolFlag( true );
932 pFTActivateSize( maSizeFT
);
936 const TT_OS2
* pOS2
= (const TT_OS2
*)FT_Get_Sfnt_Table( maFaceFT
, ft_sfnt_os2
);
937 const double fScale
= (double)GetFontSelData().mnHeight
/ maFaceFT
->units_per_EM
;
941 rTo
.mnExtLeading
= 0;
943 rTo
.mnWidth
= mnWidth
;
945 // Calculating ascender and descender:
946 // FreeType >= 2.4.6 does the right thing, so we just use what it gives us,
947 // for earlier versions we emulate its behaviour;
948 // take them from 'hhea' table,
949 // if zero take them from 'OS/2' table,
950 // if zero take them from FreeType's font metrics
951 if (nFTVERSION
>= 2406)
953 const FT_Size_Metrics
& rMetrics
= maFaceFT
->size
->metrics
;
954 rTo
.mnAscent
= (rMetrics
.ascender
+ 32) >> 6;
955 rTo
.mnDescent
= (-rMetrics
.descender
+ 32) >> 6;
956 rTo
.mnExtLeading
= ((rMetrics
.height
+ 32) >> 6) - (rTo
.mnAscent
+ rTo
.mnDescent
);
960 const TT_HoriHeader
* pHHea
= (const TT_HoriHeader
*)FT_Get_Sfnt_Table(maFaceFT
, ft_sfnt_hhea
);
963 rTo
.mnAscent
= pHHea
->Ascender
* fScale
+ 0.5;
964 rTo
.mnDescent
= -pHHea
->Descender
* fScale
+ 0.5;
965 rTo
.mnExtLeading
= pHHea
->Line_Gap
* fScale
+ 0.5;
968 if (!(rTo
.mnAscent
|| rTo
.mnDescent
))
970 if (pOS2
&& (pOS2
->version
!= 0xFFFF))
972 if (pOS2
->sTypoAscender
|| pOS2
->sTypoDescender
)
974 rTo
.mnAscent
= pOS2
->sTypoAscender
* fScale
+ 0.5;
975 rTo
.mnDescent
= -pOS2
->sTypoDescender
* fScale
+ 0.5;
976 rTo
.mnExtLeading
= pOS2
->sTypoLineGap
* fScale
+ 0.5;
980 rTo
.mnAscent
= pOS2
->usWinAscent
* fScale
+ 0.5;
981 rTo
.mnDescent
= pOS2
->usWinDescent
* fScale
+ 0.5;
982 rTo
.mnExtLeading
= 0;
987 if (!(rTo
.mnAscent
|| rTo
.mnDescent
))
989 const FT_Size_Metrics
& rMetrics
= maFaceFT
->size
->metrics
;
990 rTo
.mnAscent
= (rMetrics
.ascender
+ 32) >> 6;
991 rTo
.mnDescent
= (-rMetrics
.descender
+ 32) >> 6;
992 rTo
.mnExtLeading
= ((rMetrics
.height
+ 32) >> 6) - (rTo
.mnAscent
+ rTo
.mnDescent
);
996 rTo
.mnIntLeading
= rTo
.mnAscent
+ rTo
.mnDescent
- (maFaceFT
->units_per_EM
* fScale
+ 0.5);
998 if( pOS2
&& (pOS2
->version
!= 0xFFFF) )
1000 // map the panose info from the OS2 table to their VCL counterparts
1001 switch( pOS2
->panose
[0] )
1003 case 1: rTo
.SetFamilyType( FAMILY_ROMAN
); break;
1004 case 2: rTo
.SetFamilyType( FAMILY_SWISS
); break;
1005 case 3: rTo
.SetFamilyType( FAMILY_MODERN
); break;
1006 case 4: rTo
.SetFamilyType( FAMILY_SCRIPT
); break;
1007 case 5: rTo
.SetFamilyType( FAMILY_DECORATIVE
); break;
1008 // TODO: is it reasonable to override the attribute with DONTKNOW?
1009 case 0: // fall through
1010 default: rTo
.meFamilyType
= FAMILY_DONTKNOW
; break;
1013 switch( pOS2
->panose
[3] )
1015 case 2: // fall through
1016 case 3: // fall through
1017 case 4: // fall through
1018 case 5: // fall through
1019 case 6: // fall through
1020 case 7: // fall through
1021 case 8: rTo
.SetPitch( PITCH_VARIABLE
); break;
1022 case 9: rTo
.SetPitch( PITCH_FIXED
); break;
1023 // TODO: is it reasonable to override the attribute with DONTKNOW?
1024 case 0: // fall through
1025 case 1: // fall through
1026 default: rTo
.SetPitch( PITCH_DONTKNOW
); break;
1030 // initialize kashida width
1031 // TODO: what if there are different versions of this glyph available
1032 const int nKashidaGlyphId
= GetRawGlyphIndex( 0x0640 );
1033 if( nKashidaGlyphId
)
1035 GlyphData aGlyphData
;
1036 InitGlyphData( nKashidaGlyphId
, aGlyphData
);
1037 rTo
.mnMinKashida
= aGlyphData
.GetMetric().GetCharWidth();
1041 // -----------------------------------------------------------------------
1043 static inline void SplitGlyphFlags( const ServerFont
& rFont
, int& nGlyphIndex
, int& nGlyphFlags
)
1045 nGlyphFlags
= nGlyphIndex
& GF_FLAGMASK
;
1046 nGlyphIndex
&= GF_IDXMASK
;
1048 if( nGlyphIndex
& GF_ISCHAR
)
1049 nGlyphIndex
= rFont
.GetRawGlyphIndex( nGlyphIndex
);
1052 // -----------------------------------------------------------------------
1054 int ServerFont::ApplyGlyphTransform( int nGlyphFlags
,
1055 FT_Glyph pGlyphFT
, bool bForBitmapProcessing
) const
1057 int nAngle
= GetFontSelData().mnOrientation
;
1058 // shortcut most common case
1059 if( !nAngle
&& !nGlyphFlags
)
1062 const FT_Size_Metrics
& rMetrics
= maFaceFT
->size
->metrics
;
1066 bool bStretched
= false;
1068 switch( nGlyphFlags
& GF_ROTMASK
)
1070 default: // straight
1073 aMatrix
.xx
= +mnCos
;
1074 aMatrix
.yy
= +mnCos
;
1075 aMatrix
.xy
= -mnSin
;
1076 aMatrix
.yx
= +mnSin
;
1078 case GF_ROTL
: // left
1080 bStretched
= (mfStretch
!= 1.0);
1081 aVector
.x
= (FT_Pos
)(+rMetrics
.descender
* mfStretch
);
1082 aVector
.y
= -rMetrics
.ascender
;
1083 aMatrix
.xx
= (FT_Pos
)(-mnSin
/ mfStretch
);
1084 aMatrix
.yy
= (FT_Pos
)(-mnSin
* mfStretch
);
1085 aMatrix
.xy
= (FT_Pos
)(-mnCos
* mfStretch
);
1086 aMatrix
.yx
= (FT_Pos
)(+mnCos
/ mfStretch
);
1088 case GF_ROTR
: // right
1090 bStretched
= (mfStretch
!= 1.0);
1091 aVector
.x
= -maFaceFT
->glyph
->metrics
.horiAdvance
;
1092 aVector
.x
+= (FT_Pos
)(rMetrics
.descender
* mnSin
/65536.0);
1093 aVector
.y
= (FT_Pos
)(-rMetrics
.descender
* mfStretch
* mnCos
/65536.0);
1094 aMatrix
.xx
= (FT_Pos
)(+mnSin
/ mfStretch
);
1095 aMatrix
.yy
= (FT_Pos
)(+mnSin
* mfStretch
);
1096 aMatrix
.xy
= (FT_Pos
)(+mnCos
* mfStretch
);
1097 aMatrix
.yx
= (FT_Pos
)(-mnCos
/ mfStretch
);
1104 if( pGlyphFT
->format
!= FT_GLYPH_FORMAT_BITMAP
)
1106 FT_Glyph_Transform( pGlyphFT
, NULL
, &aVector
);
1108 // orthogonal transforms are better handled by bitmap operations
1109 if( bStretched
|| (bForBitmapProcessing
&& (nAngle
% 900) != 0) )
1111 // apply non-orthogonal or stretch transformations
1112 FT_Glyph_Transform( pGlyphFT
, &aMatrix
, NULL
);
1118 // FT<=2005 ignores transforms for bitmaps, so do it manually
1119 FT_BitmapGlyph pBmpGlyphFT
= reinterpret_cast<FT_BitmapGlyph
>(pGlyphFT
);
1120 pBmpGlyphFT
->left
+= (aVector
.x
+ 32) >> 6;
1121 pBmpGlyphFT
->top
+= (aVector
.y
+ 32) >> 6;
1127 // -----------------------------------------------------------------------
1129 int ServerFont::GetRawGlyphIndex(sal_UCS4 aChar
, sal_UCS4 aVS
) const
1131 if( mpFontInfo
->IsSymbolFont() )
1133 if( !FT_IS_SFNT( maFaceFT
) )
1135 if( (aChar
& 0xFF00) == 0xF000 )
1136 aChar
&= 0xFF; // PS font symbol mapping
1137 else if( aChar
> 0xFF )
1142 // if needed recode from unicode to font encoding
1143 if( maRecodeConverter
)
1145 sal_Char aTempArray
[8];
1147 sal_uInt32 nCvtInfo
;
1149 // assume that modern UCS4 fonts have unicode CMAPs
1150 // => no encoding remapping to unicode is needed
1151 if( aChar
> 0xFFFF )
1154 sal_Unicode aUCS2Char
= static_cast<sal_Unicode
>(aChar
);
1155 rtl_UnicodeToTextContext aContext
= rtl_createUnicodeToTextContext( maRecodeConverter
);
1156 int nChars
= rtl_convertUnicodeToText( maRecodeConverter
, aContext
,
1157 &aUCS2Char
, 1, aTempArray
, sizeof(aTempArray
),
1158 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_QUESTIONMARK
1159 | RTL_UNICODETOTEXT_FLAGS_INVALID_QUESTIONMARK
,
1160 &nCvtInfo
, &nTempSize
);
1161 rtl_destroyUnicodeToTextContext( maRecodeConverter
, aContext
);
1164 for( int i
= 0; i
< nChars
; ++i
)
1165 aChar
= aChar
*256 + (aTempArray
[i
] & 0xFF);
1168 int nGlyphIndex
= 0;
1169 // If asked, check first for variant glyph with the given Unicode variation
1170 // selector. This is quite uncommon so we don't bother with caching here.
1171 if (aVS
&& pFT_Face_GetCharVariantIndex
)
1172 nGlyphIndex
= (*pFT_Face_GetCharVariantIndex
)(maFaceFT
, aChar
, aVS
);
1174 if (nGlyphIndex
== 0)
1176 // cache glyph indexes in font info to share between different sizes
1177 nGlyphIndex
= mpFontInfo
->GetGlyphIndex( aChar
);
1178 if( nGlyphIndex
< 0 )
1180 nGlyphIndex
= FT_Get_Char_Index( maFaceFT
, aChar
);
1183 // check if symbol aliasing helps
1184 if( (aChar
<= 0x00FF) && mpFontInfo
->IsSymbolFont() )
1185 nGlyphIndex
= FT_Get_Char_Index( maFaceFT
, aChar
| 0xF000 );
1187 mpFontInfo
->CacheGlyphIndex( aChar
, nGlyphIndex
);
1194 // -----------------------------------------------------------------------
1196 int ServerFont::FixupGlyphIndex( int nGlyphIndex
, sal_UCS4 aChar
) const
1198 int nGlyphFlags
= GF_NONE
;
1200 // do glyph substitution if necessary
1201 // CJK vertical writing needs special treatment
1202 if( GetFontSelData().mbVertical
)
1204 // TODO: rethink when GSUB is used for non-vertical case
1205 GlyphSubstitution::const_iterator it
= maGlyphSubstitution
.find( nGlyphIndex
);
1206 if( it
== maGlyphSubstitution
.end() )
1208 int nTemp
= GetVerticalChar( aChar
);
1209 if( nTemp
) // is substitution possible
1210 nTemp
= GetRawGlyphIndex( nTemp
);
1211 if( nTemp
) // substitute manually if sensible
1212 nGlyphIndex
= nTemp
| (GF_GSUB
| GF_ROTL
);
1214 nGlyphFlags
|= GetVerticalFlags( aChar
);
1218 // for vertical GSUB also compensate for nOrientation=2700
1219 nGlyphIndex
= (*it
).second
;
1220 nGlyphFlags
|= GF_GSUB
| GF_ROTL
;
1224 if( nGlyphIndex
!= 0 )
1225 nGlyphIndex
|= nGlyphFlags
;
1231 // -----------------------------------------------------------------------
1233 int ServerFont::GetGlyphIndex( sal_UCS4 aChar
) const
1235 int nGlyphIndex
= GetRawGlyphIndex( aChar
);
1236 nGlyphIndex
= FixupGlyphIndex( nGlyphIndex
, aChar
);
1240 // -----------------------------------------------------------------------
1242 static int lcl_GetCharWidth( FT_FaceRec_
* pFaceFT
, double fStretch
, int nGlyphFlags
)
1244 int nCharWidth
= pFaceFT
->glyph
->metrics
.horiAdvance
;
1246 if( nGlyphFlags
& GF_ROTMASK
) // for bVertical rotated glyphs
1248 const FT_Size_Metrics
& rMetrics
= pFaceFT
->size
->metrics
;
1249 nCharWidth
= (int)((rMetrics
.height
+ rMetrics
.descender
) * fStretch
);
1252 return (nCharWidth
+ 32) >> 6;
1255 // -----------------------------------------------------------------------
1257 void ServerFont::InitGlyphData( int nGlyphIndex
, GlyphData
& rGD
) const
1260 pFTActivateSize( maSizeFT
);
1263 SplitGlyphFlags( *this, nGlyphIndex
, nGlyphFlags
);
1265 int nLoadFlags
= mnLoadFlags
;
1267 // if( mbArtItalic )
1268 // nLoadFlags |= FT_LOAD_NO_BITMAP;
1271 rc
= FT_Load_Glyph( maFaceFT
, nGlyphIndex
, nLoadFlags
);
1273 if( rc
!= FT_Err_Ok
)
1275 // we get here e.g. when a PS font lacks the default glyph
1276 rGD
.SetCharWidth( 0 );
1277 rGD
.SetDelta( 0, 0 );
1278 rGD
.SetOffset( 0, 0 );
1279 rGD
.SetSize( Size( 0, 0 ) );
1283 const bool bOriginallyZeroWidth
= (maFaceFT
->glyph
->metrics
.horiAdvance
== 0);
1284 if( mbArtBold
&& pFTEmbolden
)
1285 (*pFTEmbolden
)( maFaceFT
->glyph
);
1287 const int nCharWidth
= bOriginallyZeroWidth
? 0 : lcl_GetCharWidth( maFaceFT
, mfStretch
, nGlyphFlags
);
1288 rGD
.SetCharWidth( nCharWidth
);
1291 rc
= FT_Get_Glyph( maFaceFT
->glyph
, &pGlyphFT
);
1293 ApplyGlyphTransform( nGlyphFlags
, pGlyphFT
, false );
1294 if( mbArtBold
&& pFTEmbolden
&& (nFTVERSION
< 2200) ) // #i71094# workaround staircase bug
1295 pGlyphFT
->advance
.y
= 0;
1296 rGD
.SetDelta( (pGlyphFT
->advance
.x
+ 0x8000) >> 16, -((pGlyphFT
->advance
.y
+ 0x8000) >> 16) );
1299 FT_Glyph_Get_CBox( pGlyphFT
, FT_GLYPH_BBOX_PIXELS
, &aBbox
);
1300 if( aBbox
.yMin
> aBbox
.yMax
) // circumvent freetype bug
1302 int t
=aBbox
.yMin
; aBbox
.yMin
=aBbox
.yMax
, aBbox
.yMax
=t
;
1305 rGD
.SetOffset( aBbox
.xMin
, -aBbox
.yMax
);
1306 rGD
.SetSize( Size( (aBbox
.xMax
-aBbox
.xMin
+1), (aBbox
.yMax
-aBbox
.yMin
) ) );
1308 FT_Done_Glyph( pGlyphFT
);
1311 // -----------------------------------------------------------------------
1313 bool ServerFont::GetAntialiasAdvice( void ) const
1315 if( GetFontSelData().mbNonAntialiased
|| (mnPrioAntiAlias
<=0) )
1317 bool bAdviseAA
= true;
1318 // TODO: also use GASP info
1322 // -----------------------------------------------------------------------
1324 bool ServerFont::GetGlyphBitmap1( int nGlyphIndex
, RawBitmap
& rRawBitmap
) const
1327 pFTActivateSize( maSizeFT
);
1330 SplitGlyphFlags( *this, nGlyphIndex
, nGlyphFlags
);
1332 FT_Int nLoadFlags
= mnLoadFlags
;
1333 // #i70930# force mono-hinting for monochrome text
1334 if( nFTVERSION
>= 2110 ) //#i71947# unless it looks worse
1336 nLoadFlags
&= ~0xF0000;
1337 nLoadFlags
|= FT_LOAD_TARGET_MONO
;
1341 nLoadFlags
|= FT_LOAD_NO_BITMAP
;
1343 // for 0/90/180/270 degree fonts enable hinting even if not advisable
1344 // non-hinted and non-antialiased bitmaps just look too ugly
1345 if( (mnCos
==0 || mnSin
==0) && (mnPrioAutoHint
> 0) )
1346 nLoadFlags
&= ~FT_LOAD_NO_HINTING
;
1348 if( mnPrioEmbedded
<= mnPrioAutoHint
)
1349 nLoadFlags
|= FT_LOAD_NO_BITMAP
;
1352 rc
= FT_Load_Glyph( maFaceFT
, nGlyphIndex
, nLoadFlags
);
1354 if( rc
!= FT_Err_Ok
)
1357 if( mbArtBold
&& pFTEmbolden
)
1358 (*pFTEmbolden
)( maFaceFT
->glyph
);
1361 rc
= FT_Get_Glyph( maFaceFT
->glyph
, &pGlyphFT
);
1362 if( rc
!= FT_Err_Ok
)
1365 int nAngle
= ApplyGlyphTransform( nGlyphFlags
, pGlyphFT
, true );
1370 aMatrix
.xx
= aMatrix
.yy
= 0x10000L
;
1371 aMatrix
.xy
= 0x6000L
, aMatrix
.yx
= 0;
1372 FT_Glyph_Transform( pGlyphFT
, &aMatrix
, NULL
);
1375 // Check for zero area bounding boxes as this crashes some versions of FT.
1376 // This also provides a handy short cut as much of the code following
1377 // becomes an expensive nop when a glyph covers no pixels.
1379 FT_Glyph_Get_CBox(pGlyphFT
, ft_glyph_bbox_unscaled
, &cbox
);
1381 if( (cbox
.xMax
- cbox
.xMin
) == 0 || (cbox
.yMax
- cbox
.yMin
== 0) )
1384 memset(&rRawBitmap
, 0, sizeof rRawBitmap
);
1385 FT_Done_Glyph( pGlyphFT
);
1389 if( pGlyphFT
->format
!= FT_GLYPH_FORMAT_BITMAP
)
1391 if( pGlyphFT
->format
== FT_GLYPH_FORMAT_OUTLINE
)
1392 ((FT_OutlineGlyphRec
*)pGlyphFT
)->outline
.flags
|= FT_OUTLINE_HIGH_PRECISION
;
1393 FT_Render_Mode nRenderMode
= FT_RENDER_MODE_MONO
;
1395 rc
= FT_Glyph_To_Bitmap( &pGlyphFT
, nRenderMode
, NULL
, sal_True
);
1396 if( rc
!= FT_Err_Ok
)
1398 FT_Done_Glyph( pGlyphFT
);
1403 const FT_BitmapGlyph pBmpGlyphFT
= reinterpret_cast<const FT_BitmapGlyph
>(pGlyphFT
);
1404 // NOTE: autohinting in FT<=2.0.2 miscalculates the offsets below by +-1
1405 rRawBitmap
.mnXOffset
= +pBmpGlyphFT
->left
;
1406 rRawBitmap
.mnYOffset
= -pBmpGlyphFT
->top
;
1408 const FT_Bitmap
& rBitmapFT
= pBmpGlyphFT
->bitmap
;
1409 rRawBitmap
.mnHeight
= rBitmapFT
.rows
;
1410 rRawBitmap
.mnBitCount
= 1;
1411 if( mbArtBold
&& !pFTEmbolden
)
1413 rRawBitmap
.mnWidth
= rBitmapFT
.width
+ 1;
1414 int nLineBytes
= (rRawBitmap
.mnWidth
+ 7) >> 3;
1415 rRawBitmap
.mnScanlineSize
= (nLineBytes
> rBitmapFT
.pitch
) ? nLineBytes
: rBitmapFT
.pitch
;
1419 rRawBitmap
.mnWidth
= rBitmapFT
.width
;
1420 rRawBitmap
.mnScanlineSize
= rBitmapFT
.pitch
;
1423 const sal_uLong nNeededSize
= rRawBitmap
.mnScanlineSize
* rRawBitmap
.mnHeight
;
1425 if( rRawBitmap
.mnAllocated
< nNeededSize
)
1427 delete[] rRawBitmap
.mpBits
;
1428 rRawBitmap
.mnAllocated
= 2*nNeededSize
;
1429 rRawBitmap
.mpBits
= new unsigned char[ rRawBitmap
.mnAllocated
];
1432 if( !mbArtBold
|| pFTEmbolden
)
1434 memcpy( rRawBitmap
.mpBits
, rBitmapFT
.buffer
, nNeededSize
);
1438 memset( rRawBitmap
.mpBits
, 0, nNeededSize
);
1439 const unsigned char* pSrcLine
= rBitmapFT
.buffer
;
1440 unsigned char* pDstLine
= rRawBitmap
.mpBits
;
1441 for( int h
= rRawBitmap
.mnHeight
; --h
>= 0; )
1443 memcpy( pDstLine
, pSrcLine
, rBitmapFT
.pitch
);
1444 pDstLine
+= rRawBitmap
.mnScanlineSize
;
1445 pSrcLine
+= rBitmapFT
.pitch
;
1448 unsigned char* p
= rRawBitmap
.mpBits
;
1449 for( sal_uLong y
=0; y
< rRawBitmap
.mnHeight
; y
++ )
1451 unsigned char nLastByte
= 0;
1452 for( sal_uLong x
=0; x
< rRawBitmap
.mnScanlineSize
; x
++ )
1454 unsigned char nTmp
= p
[x
] << 7;
1455 p
[x
] |= (p
[x
] >> 1) | nLastByte
;
1458 p
+= rRawBitmap
.mnScanlineSize
;
1462 FT_Done_Glyph( pGlyphFT
);
1464 // special case for 0/90/180/270 degree orientation
1471 rRawBitmap
.Rotate( nAngle
);
1478 // -----------------------------------------------------------------------
1480 bool ServerFont::GetGlyphBitmap8( int nGlyphIndex
, RawBitmap
& rRawBitmap
) const
1483 pFTActivateSize( maSizeFT
);
1486 SplitGlyphFlags( *this, nGlyphIndex
, nGlyphFlags
);
1488 FT_Int nLoadFlags
= mnLoadFlags
;
1491 nLoadFlags
|= FT_LOAD_NO_BITMAP
;
1493 if( (nGlyphFlags
& GF_UNHINTED
) || (mnPrioAutoHint
< mnPrioAntiAlias
) )
1494 nLoadFlags
|= FT_LOAD_NO_HINTING
;
1496 if( mnPrioEmbedded
<= mnPrioAntiAlias
)
1497 nLoadFlags
|= FT_LOAD_NO_BITMAP
;
1500 rc
= FT_Load_Glyph( maFaceFT
, nGlyphIndex
, nLoadFlags
);
1502 if( rc
!= FT_Err_Ok
)
1505 if( mbArtBold
&& pFTEmbolden
)
1506 (*pFTEmbolden
)( maFaceFT
->glyph
);
1509 rc
= FT_Get_Glyph( maFaceFT
->glyph
, &pGlyphFT
);
1510 if( rc
!= FT_Err_Ok
)
1513 int nAngle
= ApplyGlyphTransform( nGlyphFlags
, pGlyphFT
, true );
1518 aMatrix
.xx
= aMatrix
.yy
= 0x10000L
;
1519 aMatrix
.xy
= 0x6000L
, aMatrix
.yx
= 0;
1520 FT_Glyph_Transform( pGlyphFT
, &aMatrix
, NULL
);
1523 if( pGlyphFT
->format
== FT_GLYPH_FORMAT_OUTLINE
)
1524 ((FT_OutlineGlyph
)pGlyphFT
)->outline
.flags
|= FT_OUTLINE_HIGH_PRECISION
;
1526 bool bEmbedded
= (pGlyphFT
->format
== FT_GLYPH_FORMAT_BITMAP
);
1529 rc
= FT_Glyph_To_Bitmap( &pGlyphFT
, FT_RENDER_MODE_NORMAL
, NULL
, sal_True
);
1530 if( rc
!= FT_Err_Ok
)
1532 FT_Done_Glyph( pGlyphFT
);
1537 const FT_BitmapGlyph pBmpGlyphFT
= reinterpret_cast<const FT_BitmapGlyph
>(pGlyphFT
);
1538 rRawBitmap
.mnXOffset
= +pBmpGlyphFT
->left
;
1539 rRawBitmap
.mnYOffset
= -pBmpGlyphFT
->top
;
1541 const FT_Bitmap
& rBitmapFT
= pBmpGlyphFT
->bitmap
;
1542 rRawBitmap
.mnHeight
= rBitmapFT
.rows
;
1543 rRawBitmap
.mnWidth
= rBitmapFT
.width
;
1544 rRawBitmap
.mnBitCount
= 8;
1545 rRawBitmap
.mnScanlineSize
= bEmbedded
? rBitmapFT
.width
: rBitmapFT
.pitch
;
1546 if( mbArtBold
&& !pFTEmbolden
)
1548 ++rRawBitmap
.mnWidth
;
1549 ++rRawBitmap
.mnScanlineSize
;
1551 rRawBitmap
.mnScanlineSize
= (rRawBitmap
.mnScanlineSize
+ 3) & -4;
1553 const sal_uLong nNeededSize
= rRawBitmap
.mnScanlineSize
* rRawBitmap
.mnHeight
;
1554 if( rRawBitmap
.mnAllocated
< nNeededSize
)
1556 delete[] rRawBitmap
.mpBits
;
1557 rRawBitmap
.mnAllocated
= 2*nNeededSize
;
1558 rRawBitmap
.mpBits
= new unsigned char[ rRawBitmap
.mnAllocated
];
1561 const unsigned char* pSrc
= rBitmapFT
.buffer
;
1562 unsigned char* pDest
= rRawBitmap
.mpBits
;
1565 for( int y
= rRawBitmap
.mnHeight
, x
; --y
>= 0 ; )
1567 for( x
= 0; x
< rBitmapFT
.width
; ++x
)
1568 *(pDest
++) = *(pSrc
++);
1569 for(; x
< int(rRawBitmap
.mnScanlineSize
); ++x
)
1575 for( int y
= rRawBitmap
.mnHeight
, x
; --y
>= 0 ; )
1577 unsigned char nSrc
= 0;
1578 for( x
= 0; x
< rBitmapFT
.width
; ++x
, nSrc
+=nSrc
)
1582 *(pDest
++) = (0x7F - nSrc
) >> 8;
1584 for(; x
< int(rRawBitmap
.mnScanlineSize
); ++x
)
1589 if( mbArtBold
&& !pFTEmbolden
)
1591 // overlay with glyph image shifted by one left pixel
1592 unsigned char* p
= rRawBitmap
.mpBits
;
1593 for( sal_uLong y
=0; y
< rRawBitmap
.mnHeight
; y
++ )
1595 unsigned char nLastByte
= 0;
1596 for( sal_uLong x
=0; x
< rRawBitmap
.mnWidth
; x
++ )
1598 unsigned char nTmp
= p
[x
];
1599 p
[x
] |= p
[x
] | nLastByte
;
1602 p
+= rRawBitmap
.mnScanlineSize
;
1606 if( !bEmbedded
&& mbUseGamma
)
1608 unsigned char* p
= rRawBitmap
.mpBits
;
1609 for( sal_uLong y
=0; y
< rRawBitmap
.mnHeight
; y
++ )
1611 for( sal_uLong x
=0; x
< rRawBitmap
.mnWidth
; x
++ )
1613 p
[x
] = aGammaTable
[ p
[x
] ];
1615 p
+= rRawBitmap
.mnScanlineSize
;
1619 FT_Done_Glyph( pGlyphFT
);
1621 // special case for 0/90/180/270 degree orientation
1628 rRawBitmap
.Rotate( nAngle
);
1635 // -----------------------------------------------------------------------
1636 // determine unicode ranges in font
1637 // -----------------------------------------------------------------------
1639 const ImplFontCharMap
* ServerFont::GetImplFontCharMap( void ) const
1641 const ImplFontCharMap
* pIFCMap
= mpFontInfo
->GetImplFontCharMap();
1645 const ImplFontCharMap
* FtFontInfo::GetImplFontCharMap( void )
1647 // check if the charmap is already cached
1649 return mpFontCharMap
;
1651 // get the charmap and cache it
1652 CmapResult aCmapResult
;
1653 bool bOK
= GetFontCodeRanges( aCmapResult
);
1655 mpFontCharMap
= new ImplFontCharMap( aCmapResult
);
1657 mpFontCharMap
= ImplFontCharMap::GetDefaultMap();
1658 mpFontCharMap
->AddReference();
1659 return mpFontCharMap
;
1662 // TODO: merge into method GetFontCharMap()
1663 bool FtFontInfo::GetFontCodeRanges( CmapResult
& rResult
) const
1665 rResult
.mbSymbolic
= IsSymbolFont();
1667 // TODO: is the full CmapResult needed on platforms calling this?
1668 if( FT_IS_SFNT( maFaceFT
) )
1670 sal_uLong nLength
= 0;
1671 const unsigned char* pCmap
= GetTable( "cmap", &nLength
);
1672 if( pCmap
&& (nLength
> 0) )
1673 if( ParseCMAP( pCmap
, nLength
, rResult
) )
1677 typedef std::vector
<sal_uInt32
> U32Vector
;
1680 // FT's coverage is available since FT>=2.1.0 (OOo-baseline>=2.1.4 => ok)
1681 aCodes
.reserve( 0x1000 );
1682 FT_UInt nGlyphIndex
;
1683 for( sal_uInt32 cCode
= FT_Get_First_Char( maFaceFT
, &nGlyphIndex
);; )
1687 aCodes
.push_back( cCode
); // first code inside range
1688 sal_uInt32 cNext
= cCode
;
1689 do cNext
= FT_Get_Next_Char( maFaceFT
, cCode
, &nGlyphIndex
); while( cNext
== ++cCode
);
1690 aCodes
.push_back( cCode
); // first code outside range
1694 const int nCount
= aCodes
.size();
1696 if( !rResult
.mbSymbolic
)
1699 // we usually get here for Type1 symbol fonts
1700 aCodes
.push_back( 0xF020 );
1701 aCodes
.push_back( 0xF100 );
1704 sal_uInt32
* pCodes
= new sal_uInt32
[ nCount
];
1705 for( int i
= 0; i
< nCount
; ++i
)
1706 pCodes
[i
] = aCodes
[i
];
1707 rResult
.mpRangeCodes
= pCodes
;
1708 rResult
.mnRangeCount
= nCount
/ 2;
1712 bool ServerFont::GetFontCapabilities(vcl::FontCapabilities
&rFontCapabilities
) const
1716 sal_uLong nLength
= 0;
1718 const FT_Byte
* pGSUB
= mpFontInfo
->GetTable("GSUB", &nLength
);
1720 vcl::getTTScripts(rFontCapabilities
.maGSUBScriptTags
, pGSUB
, nLength
);
1723 const FT_Byte
* pOS2
= mpFontInfo
->GetTable("OS/2", &nLength
);
1726 bRet
= vcl::getTTCoverage(
1727 rFontCapabilities
.maUnicodeRange
,
1728 rFontCapabilities
.maCodePageRange
,
1735 // -----------------------------------------------------------------------
1737 sal_uLong
ServerFont::GetKernPairs( ImplKernPairData
** ppKernPairs
) const
1739 // if no kerning info is available in the font file
1740 *ppKernPairs
= NULL
;
1741 if( !FT_HAS_KERNING( maFaceFT
) || !FT_IS_SFNT( maFaceFT
) )
1743 // then we have may have extra kerning info from e.g. psprint
1744 int nCount
= mpFontInfo
->GetExtraKernPairs( ppKernPairs
);
1745 // scale the kern values to match the font size
1746 const FontSelectPattern
& rFSD
= GetFontSelData();
1747 int nFontWidth
= rFSD
.mnWidth
? rFSD
.mnWidth
: rFSD
.mnHeight
;
1748 ImplKernPairData
* pKernPair
= *ppKernPairs
;
1749 for( int i
= nCount
; --i
>= 0; ++pKernPair
)
1751 long& rVal
= pKernPair
->mnKern
;
1752 rVal
= ((rVal
* nFontWidth
) + 500) / 1000;
1757 // when font faces of different sizes share the same maFaceFT
1758 // then we have to make sure that it uses the correct maSizeFT
1760 pFTActivateSize( maSizeFT
);
1762 // first figure out which glyph pairs are involved in kerning
1763 sal_uLong nKernLength
= 0;
1764 const FT_Byte
* const pKern
= mpFontInfo
->GetTable( "kern", &nKernLength
);
1768 // combine TTF/OTF tables from the font file to build a vector of
1769 // unicode kerning pairs using Freetype's glyph kerning calculation
1770 // for the kerning value
1772 // TODO: is it worth to share the glyph->unicode mapping between
1773 // different instances of the same font face?
1775 typedef std::vector
<ImplKernPairData
> KernVector
;
1776 KernVector aKernGlyphVector
;
1777 ImplKernPairData aKernPair
;
1778 aKernPair
.mnKern
= 0; // To prevent "is used uninitialized" warning...
1780 const FT_Byte
* pBuffer
= pKern
;
1781 sal_uLong nVersion
= GetUShort( pBuffer
+0 );
1782 sal_uInt16 nTableCnt
= GetUShort( pBuffer
+2 );
1784 // Microsoft/Old TrueType style kern table
1785 if ( nVersion
== 0 )
1789 for( sal_uInt16 nTableIdx
= 0; nTableIdx
< nTableCnt
; ++nTableIdx
)
1791 // sal_uInt16 nSubVersion = GetUShort( pBuffer+0 );
1792 // sal_uInt16 nSubLength = GetUShort( pBuffer+2 );
1793 sal_uInt16 nSubCoverage
= GetUShort( pBuffer
+4 );
1795 if( (nSubCoverage
&0x03) != 0x01 ) // no interest in minimum info here
1797 switch( nSubCoverage
>> 8 )
1799 case 0: // version 0, kerning format 0
1801 sal_uInt16 nPairs
= GetUShort( pBuffer
);
1802 pBuffer
+= 8; // skip search hints
1803 aKernGlyphVector
.reserve( aKernGlyphVector
.size() + nPairs
);
1804 for( int i
= 0; i
< nPairs
; ++i
)
1806 aKernPair
.mnChar1
= GetUShort( pBuffer
+0 );
1807 aKernPair
.mnChar2
= GetUShort( pBuffer
+2 );
1808 //long nUnscaledKern= GetSShort( pBuffer );
1810 aKernGlyphVector
.push_back( aKernPair
);
1815 case 2: // version 0, kerning format 2
1817 const FT_Byte
* pSubTable
= pBuffer
;
1818 //sal_uInt16 nRowWidth = GetUShort( pBuffer+0 );
1819 sal_uInt16 nOfsLeft
= GetUShort( pBuffer
+2 );
1820 sal_uInt16 nOfsRight
= GetUShort( pBuffer
+4 );
1821 sal_uInt16 nOfsArray
= GetUShort( pBuffer
+6 );
1824 const FT_Byte
* pTmp
= pSubTable
+ nOfsLeft
;
1825 sal_uInt16 nFirstLeft
= GetUShort( pTmp
+0 );
1826 sal_uInt16 nLastLeft
= GetUShort( pTmp
+2 ) + nFirstLeft
- 1;
1828 pTmp
= pSubTable
+ nOfsRight
;
1829 sal_uInt16 nFirstRight
= GetUShort( pTmp
+0 );
1830 sal_uInt16 nLastRight
= GetUShort( pTmp
+2 ) + nFirstRight
- 1;
1832 sal_uLong nPairs
= (sal_uLong
)(nLastLeft
- nFirstLeft
+ 1) * (nLastRight
- nFirstRight
+ 1);
1833 aKernGlyphVector
.reserve( aKernGlyphVector
.size() + nPairs
);
1835 pTmp
= pSubTable
+ nOfsArray
;
1836 for( int nLeft
= nFirstLeft
; nLeft
< nLastLeft
; ++nLeft
)
1838 aKernPair
.mnChar1
= nLeft
;
1839 for( int nRight
= 0; nRight
< nLastRight
; ++nRight
)
1841 if( GetUShort( pTmp
) != 0 )
1843 aKernPair
.mnChar2
= nRight
;
1844 aKernGlyphVector
.push_back( aKernPair
);
1855 // Apple New style kern table
1857 nVersion
= NEXT_U32( pBuffer
);
1858 nTableCnt
= NEXT_U32( pBuffer
);
1859 if ( nVersion
== 0x00010000 )
1861 for( sal_uInt16 nTableIdx
= 0; nTableIdx
< nTableCnt
; ++nTableIdx
)
1863 /*sal_uLong nLength =*/ NEXT_U32( pBuffer
);
1864 sal_uInt16 nCoverage
= NEXT_U16( pBuffer
);
1865 /*sal_uInt16 nTupleIndex =*/ NEXT_U16( pBuffer
);
1867 // Kerning sub-table format, 0 through 3
1868 sal_uInt8 nSubTableFormat
= nCoverage
& 0x00FF;
1870 switch( nSubTableFormat
)
1872 case 0: // version 0, kerning format 0
1874 sal_uInt16 nPairs
= NEXT_U16( pBuffer
);
1875 pBuffer
+= 6; // skip search hints
1876 aKernGlyphVector
.reserve( aKernGlyphVector
.size() + nPairs
);
1877 for( int i
= 0; i
< nPairs
; ++i
)
1879 aKernPair
.mnChar1
= NEXT_U16( pBuffer
);
1880 aKernPair
.mnChar2
= NEXT_U16( pBuffer
);
1881 /*long nUnscaledKern=*/ NEXT_S16( pBuffer
);
1882 aKernGlyphVector
.push_back( aKernPair
);
1887 case 2: // version 0, kerning format 2
1889 const FT_Byte
* pSubTable
= pBuffer
;
1890 /*sal_uInt16 nRowWidth =*/ NEXT_U16( pBuffer
);
1891 sal_uInt16 nOfsLeft
= NEXT_U16( pBuffer
);
1892 sal_uInt16 nOfsRight
= NEXT_U16( pBuffer
);
1893 sal_uInt16 nOfsArray
= NEXT_U16( pBuffer
);
1895 const FT_Byte
* pTmp
= pSubTable
+ nOfsLeft
;
1896 sal_uInt16 nFirstLeft
= NEXT_U16( pTmp
);
1897 sal_uInt16 nLastLeft
= NEXT_U16( pTmp
) + nFirstLeft
- 1;
1899 pTmp
= pSubTable
+ nOfsRight
;
1900 sal_uInt16 nFirstRight
= NEXT_U16( pTmp
);
1901 sal_uInt16 nLastRight
= NEXT_U16( pTmp
) + nFirstRight
- 1;
1903 sal_uLong nPairs
= (sal_uLong
)(nLastLeft
- nFirstLeft
+ 1) * (nLastRight
- nFirstRight
+ 1);
1904 aKernGlyphVector
.reserve( aKernGlyphVector
.size() + nPairs
);
1906 pTmp
= pSubTable
+ nOfsArray
;
1907 for( int nLeft
= nFirstLeft
; nLeft
< nLastLeft
; ++nLeft
)
1909 aKernPair
.mnChar1
= nLeft
;
1910 for( int nRight
= 0; nRight
< nLastRight
; ++nRight
)
1912 if( NEXT_S16( pTmp
) != 0 )
1914 aKernPair
.mnChar2
= nRight
;
1915 aKernGlyphVector
.push_back( aKernPair
);
1923 fprintf( stderr
, "gcach_ftyp.cxx: Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat
);
1929 // now create VCL's ImplKernPairData[] format for all glyph pairs
1930 sal_uLong nKernCount
= aKernGlyphVector
.size();
1933 // prepare glyphindex to character mapping
1934 // TODO: this is needed to support VCL's existing kerning infrastructure,
1935 // eliminate it up by redesigning kerning infrastructure to work with glyph indizes
1936 typedef boost::unordered_multimap
<sal_uInt16
,sal_Unicode
> Cmap
;
1938 for( sal_Unicode aChar
= 0x0020; aChar
< 0xFFFE; ++aChar
)
1940 sal_uInt16 nGlyphIndex
= GetGlyphIndex( aChar
);
1942 aCmap
.insert( Cmap::value_type( nGlyphIndex
, aChar
) );
1945 // translate both glyph indizes in kerning pairs to characters
1946 // problem is that these are 1:n mappings...
1947 KernVector aKernCharVector
;
1948 aKernCharVector
.reserve( nKernCount
);
1949 KernVector::iterator it
;
1950 for( it
= aKernGlyphVector
.begin(); it
!= aKernGlyphVector
.end(); ++it
)
1953 FT_Error rcFT
= FT_Get_Kerning( maFaceFT
, it
->mnChar1
, it
->mnChar2
,
1954 FT_KERNING_DEFAULT
, &aKernVal
);
1955 aKernPair
.mnKern
= aKernVal
.x
>> 6;
1956 if( (aKernPair
.mnKern
== 0) || (rcFT
!= FT_Err_Ok
) )
1959 typedef std::pair
<Cmap::iterator
,Cmap::iterator
> CPair
;
1960 const CPair p1
= aCmap
.equal_range( it
->mnChar1
);
1961 const CPair p2
= aCmap
.equal_range( it
->mnChar2
);
1962 for( Cmap::const_iterator i1
= p1
.first
; i1
!= p1
.second
; ++i1
)
1964 aKernPair
.mnChar1
= (*i1
).second
;
1965 for( Cmap::const_iterator i2
= p2
.first
; i2
!= p2
.second
; ++i2
)
1967 aKernPair
.mnChar2
= (*i2
).second
;
1968 aKernCharVector
.push_back( aKernPair
);
1973 // now move the resulting vector into VCL's ImplKernPairData[] format
1974 nKernCount
= aKernCharVector
.size();
1975 ImplKernPairData
* pTo
= new ImplKernPairData
[ nKernCount
];
1977 for( it
= aKernCharVector
.begin(); it
!= aKernCharVector
.end(); ++it
, ++pTo
)
1979 pTo
->mnChar1
= it
->mnChar1
;
1980 pTo
->mnChar2
= it
->mnChar2
;
1981 pTo
->mnKern
= it
->mnKern
;
1988 // -----------------------------------------------------------------------
1990 // -----------------------------------------------------------------------
1995 PolyArgs( PolyPolygon
& rPolyPoly
, sal_uInt16 nMaxPoints
);
1998 void AddPoint( long nX
, long nY
, PolyFlags
);
1999 void ClosePolygon();
2001 long GetPosX() const { return maPosition
.x
;}
2002 long GetPosY() const { return maPosition
.y
;}
2005 PolyPolygon
& mrPolyPoly
;
2008 sal_uInt8
* mpFlagAry
;
2010 FT_Vector maPosition
;
2011 sal_uInt16 mnMaxPoints
;
2012 sal_uInt16 mnPoints
;
2017 // -----------------------------------------------------------------------
2019 PolyArgs::PolyArgs( PolyPolygon
& rPolyPoly
, sal_uInt16 nMaxPoints
)
2020 : mrPolyPoly(rPolyPoly
),
2021 mnMaxPoints(nMaxPoints
),
2026 mpPointAry
= new Point
[ mnMaxPoints
];
2027 mpFlagAry
= new sal_uInt8
[ mnMaxPoints
];
2030 // -----------------------------------------------------------------------
2033 PolyArgs::~PolyArgs()
2036 delete[] mpPointAry
;
2039 // -----------------------------------------------------------------------
2041 void PolyArgs::AddPoint( long nX
, long nY
, PolyFlags aFlag
)
2043 DBG_ASSERT( (mnPoints
< mnMaxPoints
), "FTGlyphOutline: AddPoint overflow!" );
2044 if( mnPoints
>= mnMaxPoints
)
2049 mpPointAry
[ mnPoints
] = Point( nX
, nY
);
2050 mpFlagAry
[ mnPoints
++ ]= aFlag
;
2051 bHasOffline
|= (aFlag
!= POLY_NORMAL
);
2054 // -----------------------------------------------------------------------
2056 void PolyArgs::ClosePolygon()
2061 // freetype seems to always close the polygon with an ON_CURVE point
2062 // PolyPoly wants to close the polygon itself => remove last point
2063 DBG_ASSERT( (mnPoints
>= 2), "FTGlyphOutline: PolyFinishNum failed!" );
2065 DBG_ASSERT( (mpPointAry
[0]==mpPointAry
[mnPoints
]), "FTGlyphOutline: PolyFinishEq failed!" );
2066 DBG_ASSERT( (mpFlagAry
[0]==POLY_NORMAL
), "FTGlyphOutline: PolyFinishFE failed!" );
2067 DBG_ASSERT( (mpFlagAry
[mnPoints
]==POLY_NORMAL
), "FTGlyphOutline: PolyFinishFS failed!" );
2069 Polygon
aPoly( mnPoints
, mpPointAry
, (bHasOffline
? mpFlagAry
: NULL
) );
2072 // This may be a invalid polygons, e.g. the last point is a control point.
2073 // So close the polygon (and add the first point again) if the last point
2074 // is a control point or different from first.
2076 // Now really duplicating the first point, to close or correct the
2077 // polygon. Also no longer duplicating the flags, but enforcing
2078 // POLY_NORMAL for the newly added last point.
2079 const sal_uInt16
nPolySize(aPoly
.GetSize());
2082 if((aPoly
.HasFlags() && POLY_CONTROL
== aPoly
.GetFlags(nPolySize
- 1))
2083 || (aPoly
.GetPoint(nPolySize
- 1) != aPoly
.GetPoint(0)))
2085 aPoly
.SetSize(nPolySize
+ 1);
2086 aPoly
.SetPoint(aPoly
.GetPoint(0), nPolySize
);
2088 if(aPoly
.HasFlags())
2090 aPoly
.SetFlags(nPolySize
, POLY_NORMAL
);
2095 mrPolyPoly
.Insert( aPoly
);
2097 bHasOffline
= false;
2100 // -----------------------------------------------------------------------
2104 // TODO: wait till all compilers accept that calling conventions
2105 // for functions are the same independent of implementation constness,
2106 // then uncomment the const-tokens in the function interfaces below
2107 static int FT_move_to( FT_Vector_CPtr p0
, void* vpPolyArgs
)
2109 PolyArgs
& rA
= *reinterpret_cast<PolyArgs
*>(vpPolyArgs
);
2111 // move_to implies a new polygon => finish old polygon first
2114 rA
.AddPoint( p0
->x
, p0
->y
, POLY_NORMAL
);
2118 static int FT_line_to( FT_Vector_CPtr p1
, void* vpPolyArgs
)
2120 PolyArgs
& rA
= *reinterpret_cast<PolyArgs
*>(vpPolyArgs
);
2121 rA
.AddPoint( p1
->x
, p1
->y
, POLY_NORMAL
);
2125 static int FT_conic_to( FT_Vector_CPtr p1
, FT_Vector_CPtr p2
, void* vpPolyArgs
)
2127 PolyArgs
& rA
= *reinterpret_cast<PolyArgs
*>(vpPolyArgs
);
2129 // VCL's Polygon only knows cubic beziers
2130 const long nX1
= (2 * rA
.GetPosX() + 4 * p1
->x
+ 3) / 6;
2131 const long nY1
= (2 * rA
.GetPosY() + 4 * p1
->y
+ 3) / 6;
2132 rA
.AddPoint( nX1
, nY1
, POLY_CONTROL
);
2134 const long nX2
= (2 * p2
->x
+ 4 * p1
->x
+ 3) / 6;
2135 const long nY2
= (2 * p2
->y
+ 4 * p1
->y
+ 3) / 6;
2136 rA
.AddPoint( nX2
, nY2
, POLY_CONTROL
);
2138 rA
.AddPoint( p2
->x
, p2
->y
, POLY_NORMAL
);
2142 static int FT_cubic_to( FT_Vector_CPtr p1
, FT_Vector_CPtr p2
, FT_Vector_CPtr p3
, void* vpPolyArgs
)
2144 PolyArgs
& rA
= *reinterpret_cast<PolyArgs
*>(vpPolyArgs
);
2145 rA
.AddPoint( p1
->x
, p1
->y
, POLY_CONTROL
);
2146 rA
.AddPoint( p2
->x
, p2
->y
, POLY_CONTROL
);
2147 rA
.AddPoint( p3
->x
, p3
->y
, POLY_NORMAL
);
2153 // -----------------------------------------------------------------------
2155 bool ServerFont::GetGlyphOutline( int nGlyphIndex
,
2156 ::basegfx::B2DPolyPolygon
& rB2DPolyPoly
) const
2159 pFTActivateSize( maSizeFT
);
2161 rB2DPolyPoly
.clear();
2164 SplitGlyphFlags( *this, nGlyphIndex
, nGlyphFlags
);
2166 FT_Int nLoadFlags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_TRANSFORM
;
2168 #ifdef FT_LOAD_TARGET_LIGHT
2169 // enable "light hinting" if available
2170 nLoadFlags
|= FT_LOAD_TARGET_LIGHT
;
2173 FT_Error rc
= FT_Load_Glyph( maFaceFT
, nGlyphIndex
, nLoadFlags
);
2174 if( rc
!= FT_Err_Ok
)
2177 if( mbArtBold
&& pFTEmbolden
)
2178 (*pFTEmbolden
)( maFaceFT
->glyph
);
2181 rc
= FT_Get_Glyph( maFaceFT
->glyph
, &pGlyphFT
);
2182 if( rc
!= FT_Err_Ok
)
2185 if( pGlyphFT
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
2191 aMatrix
.xx
= aMatrix
.yy
= 0x10000L
;
2192 aMatrix
.xy
= 0x6000L
, aMatrix
.yx
= 0;
2193 FT_Glyph_Transform( pGlyphFT
, &aMatrix
, NULL
);
2196 FT_Outline
& rOutline
= reinterpret_cast<FT_OutlineGlyphRec
*>(pGlyphFT
)->outline
;
2197 if( !rOutline
.n_points
) // blank glyphs are ok
2200 long nMaxPoints
= 1 + rOutline
.n_points
* 3;
2201 PolyPolygon aToolPolyPolygon
;
2202 PolyArgs
aPolyArg( aToolPolyPolygon
, nMaxPoints
);
2204 /*int nAngle =*/ ApplyGlyphTransform( nGlyphFlags
, pGlyphFT
, false );
2206 FT_Outline_Funcs aFuncs
;
2207 aFuncs
.move_to
= &FT_move_to
;
2208 aFuncs
.line_to
= &FT_line_to
;
2209 aFuncs
.conic_to
= &FT_conic_to
;
2210 aFuncs
.cubic_to
= &FT_cubic_to
;
2213 rc
= FT_Outline_Decompose( &rOutline
, &aFuncs
, (void*)&aPolyArg
);
2214 aPolyArg
.ClosePolygon(); // close last polygon
2215 FT_Done_Glyph( pGlyphFT
);
2217 // convert to basegfx polypolygon
2218 // TODO: get rid of the intermediate tools polypolygon
2219 rB2DPolyPoly
= aToolPolyPolygon
.getB2DPolyPolygon();
2220 rB2DPolyPoly
.transform(basegfx::tools::createScaleB2DHomMatrix( +1.0/(1<<6), -1.0/(1<<6) ));
2225 // -----------------------------------------------------------------------
2227 bool ServerFont::ApplyGSUB( const FontSelectPattern
& rFSD
)
2229 #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3])
2231 typedef std::vector
<sal_uLong
> ReqFeatureTagList
;
2232 ReqFeatureTagList aReqFeatureTagList
;
2233 if( rFSD
.mbVertical
)
2234 aReqFeatureTagList
.push_back( MKTAG("vert") );
2235 sal_uLong nRequestedScript
= 0; //MKTAG("hani");//### TODO: where to get script?
2236 sal_uLong nRequestedLangsys
= 0; //MKTAG("ZHT"); //### TODO: where to get langsys?
2237 // TODO: request more features depending on script and language system
2239 if( aReqFeatureTagList
.empty()) // nothing to do
2242 // load GSUB table into memory
2243 sal_uLong nLength
= 0;
2244 const FT_Byte
* const pGsubBase
= mpFontInfo
->GetTable( "GSUB", &nLength
);
2248 // parse GSUB header
2249 const FT_Byte
* pGsubHeader
= pGsubBase
;
2250 const sal_uInt16 nOfsScriptList
= GetUShort( pGsubHeader
+4 );
2251 const sal_uInt16 nOfsFeatureTable
= GetUShort( pGsubHeader
+6 );
2252 const sal_uInt16 nOfsLookupList
= GetUShort( pGsubHeader
+8 );
2255 typedef std::vector
<sal_uInt16
> UshortList
;
2256 UshortList aFeatureIndexList
;
2258 // parse Script Table
2259 const FT_Byte
* pScriptHeader
= pGsubBase
+ nOfsScriptList
;
2260 const sal_uInt16 nCntScript
= GetUShort( pScriptHeader
+0 );
2262 for( sal_uInt16 nScriptIndex
= 0; nScriptIndex
< nCntScript
; ++nScriptIndex
)
2264 const sal_uLong nScriptTag
= GetUInt( pScriptHeader
+0 ); // e.g. hani/arab/kana/hang
2265 const sal_uInt16 nOfsScriptTable
= GetUShort( pScriptHeader
+4 );
2266 pScriptHeader
+= 6; //###
2267 if( (nScriptTag
!= nRequestedScript
) && (nRequestedScript
!= 0) )
2270 const FT_Byte
* pScriptTable
= pGsubBase
+ nOfsScriptList
+ nOfsScriptTable
;
2271 const sal_uInt16 nDefaultLangsysOfs
= GetUShort( pScriptTable
+0 );
2272 const sal_uInt16 nCntLangSystem
= GetUShort( pScriptTable
+2 );
2274 sal_uInt16 nLangsysOffset
= 0;
2276 for( sal_uInt16 nLangsysIndex
= 0; nLangsysIndex
< nCntLangSystem
; ++nLangsysIndex
)
2278 const sal_uLong nTag
= GetUInt( pScriptTable
+0 ); // e.g. KOR/ZHS/ZHT/JAN
2279 const sal_uInt16 nOffset
= GetUShort( pScriptTable
+4 );
2281 if( (nTag
!= nRequestedLangsys
) && (nRequestedLangsys
!= 0) )
2283 nLangsysOffset
= nOffset
;
2287 if( (nDefaultLangsysOfs
!= 0) && (nDefaultLangsysOfs
!= nLangsysOffset
) )
2289 const FT_Byte
* pLangSys
= pGsubBase
+ nOfsScriptList
+ nOfsScriptTable
+ nDefaultLangsysOfs
;
2290 const sal_uInt16 nReqFeatureIdx
= GetUShort( pLangSys
+2 );
2291 const sal_uInt16 nCntFeature
= GetUShort( pLangSys
+4 );
2293 aFeatureIndexList
.push_back( nReqFeatureIdx
);
2294 for( sal_uInt16 i
= 0; i
< nCntFeature
; ++i
)
2296 const sal_uInt16 nFeatureIndex
= GetUShort( pLangSys
);
2298 aFeatureIndexList
.push_back( nFeatureIndex
);
2302 if( nLangsysOffset
!= 0 )
2304 const FT_Byte
* pLangSys
= pGsubBase
+ nOfsScriptList
+ nOfsScriptTable
+ nLangsysOffset
;
2305 const sal_uInt16 nReqFeatureIdx
= GetUShort( pLangSys
+2 );
2306 const sal_uInt16 nCntFeature
= GetUShort( pLangSys
+4 );
2308 aFeatureIndexList
.push_back( nReqFeatureIdx
);
2309 for( sal_uInt16 i
= 0; i
< nCntFeature
; ++i
)
2311 const sal_uInt16 nFeatureIndex
= GetUShort( pLangSys
);
2313 aFeatureIndexList
.push_back( nFeatureIndex
);
2318 if( aFeatureIndexList
.empty() )
2321 UshortList aLookupIndexList
;
2322 UshortList aLookupOffsetList
;
2324 // parse Feature Table
2325 const FT_Byte
* pFeatureHeader
= pGsubBase
+ nOfsFeatureTable
;
2326 const sal_uInt16 nCntFeature
= GetUShort( pFeatureHeader
);
2327 pFeatureHeader
+= 2;
2328 for( sal_uInt16 nFeatureIndex
= 0; nFeatureIndex
< nCntFeature
; ++nFeatureIndex
)
2330 const sal_uLong nTag
= GetUInt( pFeatureHeader
+0 ); // e.g. locl/vert/trad/smpl/liga/fina/...
2331 const sal_uInt16 nOffset
= GetUShort( pFeatureHeader
+4 );
2332 pFeatureHeader
+= 6;
2334 // short circuit some feature lookups
2335 if( aFeatureIndexList
[0] != nFeatureIndex
) // required feature?
2337 const int nRequested
= std::count( aFeatureIndexList
.begin(), aFeatureIndexList
.end(), nFeatureIndex
);
2338 if( !nRequested
) // ignore features that are not requested
2340 const int nAvailable
= std::count( aReqFeatureTagList
.begin(), aReqFeatureTagList
.end(), nTag
);
2341 if( !nAvailable
) // some fonts don't provide features they request!
2345 const FT_Byte
* pFeatureTable
= pGsubBase
+ nOfsFeatureTable
+ nOffset
;
2346 const sal_uInt16 nCntLookups
= GetUShort( pFeatureTable
+0 );
2348 for( sal_uInt16 i
= 0; i
< nCntLookups
; ++i
)
2350 const sal_uInt16 nLookupIndex
= GetUShort( pFeatureTable
);
2352 aLookupIndexList
.push_back( nLookupIndex
);
2354 if( nCntLookups
== 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
2355 aLookupIndexList
.push_back( 0 );
2358 // parse Lookup List
2359 const FT_Byte
* pLookupHeader
= pGsubBase
+ nOfsLookupList
;
2360 const sal_uInt16 nCntLookupTable
= GetUShort( pLookupHeader
);
2362 for( sal_uInt16 nLookupIdx
= 0; nLookupIdx
< nCntLookupTable
; ++nLookupIdx
)
2364 const sal_uInt16 nOffset
= GetUShort( pLookupHeader
);
2366 if( std::count( aLookupIndexList
.begin(), aLookupIndexList
.end(), nLookupIdx
) )
2367 aLookupOffsetList
.push_back( nOffset
);
2370 UshortList::const_iterator lookup_it
= aLookupOffsetList
.begin();
2371 for(; lookup_it
!= aLookupOffsetList
.end(); ++lookup_it
)
2373 const sal_uInt16 nOfsLookupTable
= *lookup_it
;
2374 const FT_Byte
* pLookupTable
= pGsubBase
+ nOfsLookupList
+ nOfsLookupTable
;
2375 const sal_uInt16 eLookupType
= GetUShort( pLookupTable
+0 );
2376 const sal_uInt16 nCntLookupSubtable
= GetUShort( pLookupTable
+4 );
2379 // TODO: switch( eLookupType )
2380 if( eLookupType
!= 1 ) // TODO: once we go beyond SingleSubst
2383 for( sal_uInt16 nSubTableIdx
= 0; nSubTableIdx
< nCntLookupSubtable
; ++nSubTableIdx
)
2385 const sal_uInt16 nOfsSubLookupTable
= GetUShort( pLookupTable
);
2387 const FT_Byte
* pSubLookup
= pGsubBase
+ nOfsLookupList
+ nOfsLookupTable
+ nOfsSubLookupTable
;
2389 const sal_uInt16 nFmtSubstitution
= GetUShort( pSubLookup
+0 );
2390 const sal_uInt16 nOfsCoverage
= GetUShort( pSubLookup
+2 );
2393 typedef std::pair
<sal_uInt16
,sal_uInt16
> GlyphSubst
;
2394 typedef std::vector
<GlyphSubst
> SubstVector
;
2395 SubstVector aSubstVector
;
2397 const FT_Byte
* pCoverage
= pGsubBase
+ nOfsLookupList
+ nOfsLookupTable
+ nOfsSubLookupTable
+ nOfsCoverage
;
2398 const sal_uInt16 nFmtCoverage
= GetUShort( pCoverage
+0 );
2400 switch( nFmtCoverage
)
2402 case 1: // Coverage Format 1
2404 const sal_uInt16 nCntGlyph
= GetUShort( pCoverage
);
2406 aSubstVector
.reserve( nCntGlyph
);
2407 for( sal_uInt16 i
= 0; i
< nCntGlyph
; ++i
)
2409 const sal_uInt16 nGlyphId
= GetUShort( pCoverage
);
2411 aSubstVector
.push_back( GlyphSubst( nGlyphId
, 0 ) );
2416 case 2: // Coverage Format 2
2418 const sal_uInt16 nCntRange
= GetUShort( pCoverage
);
2420 for( int i
= nCntRange
; --i
>= 0; )
2422 const sal_uInt32 nGlyph0
= GetUShort( pCoverage
+0 );
2423 const sal_uInt32 nGlyph1
= GetUShort( pCoverage
+2 );
2424 const sal_uInt16 nCovIdx
= GetUShort( pCoverage
+4 );
2426 for( sal_uInt32 j
= nGlyph0
; j
<= nGlyph1
; ++j
)
2427 aSubstVector
.push_back( GlyphSubst( static_cast<sal_uInt16
>(j
+ nCovIdx
), 0 ) );
2433 SubstVector::iterator
it( aSubstVector
.begin() );
2435 switch( nFmtSubstitution
)
2437 case 1: // Single Substitution Format 1
2439 const sal_uInt16 nDeltaGlyphId
= GetUShort( pSubLookup
);
2441 for(; it
!= aSubstVector
.end(); ++it
)
2442 (*it
).second
= (*it
).first
+ nDeltaGlyphId
;
2446 case 2: // Single Substitution Format 2
2448 const sal_uInt16 nCntGlyph
= GetUShort( pSubLookup
);
2450 for( int i
= nCntGlyph
; (it
!= aSubstVector
.end()) && (--i
>=0); ++it
)
2452 const sal_uInt16 nGlyphId
= GetUShort( pSubLookup
);
2454 (*it
).second
= nGlyphId
;
2460 DBG_ASSERT( (it
== aSubstVector
.end()), "lookup<->coverage table mismatch" );
2461 // now apply the glyph substitutions that have been collected in this subtable
2462 for( it
= aSubstVector
.begin(); it
!= aSubstVector
.end(); ++it
)
2463 maGlyphSubstitution
[ (*it
).first
] = (*it
).second
;
2470 const unsigned char* ServerFont::GetTable(const char* pName
, sal_uLong
* pLength
)
2472 return mpFontInfo
->GetTable( pName
, pLength
);
2476 GraphiteFaceWrapper
* ServerFont::GetGraphiteFace() const
2478 return mpFontInfo
->GetGraphiteFace();
2482 // =======================================================================
2484 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */