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 .
20 #include "gcach_ftyp.hxx"
22 #include "vcl/svapp.hxx"
23 #include <outfont.hxx>
24 #include <impfont.hxx>
25 #include <config_features.h>
26 #include <config_graphite.h>
28 # include <graphite_static.hxx>
29 # include <graphite2/Font.h>
30 # include <graphite_layout.hxx>
32 #include <unotools/fontdefs.hxx>
34 #include "tools/poly.hxx"
35 #include "basegfx/matrix/b2dhommatrix.hxx"
36 #include "basegfx/matrix/b2dhommatrixtools.hxx"
37 #include "basegfx/polygon/b2dpolypolygon.hxx"
39 #include "osl/file.hxx"
40 #include "osl/thread.hxx"
42 #include "langboost.hxx"
43 #include "PhysicalFontCollection.hxx"
47 #include FT_FREETYPE_H
51 #include FT_SYNTHESIS_H
52 #include FT_TRUETYPE_TABLES_H
53 #include FT_TRUETYPE_TAGS_H
54 #include FT_TRUETYPE_IDS_H
56 #include "rtl/instance.hxx"
58 typedef const FT_Vector
* FT_Vector_CPtr
;
62 // TODO: move file mapping stuff to OSL
67 #include "fontmanager.hxx"
69 // the gamma table makes artificial bold look better for CJK glyphs
70 static unsigned char aGammaTable
[257];
72 static void InitGammaTable()
74 static const int M_MAX
= 255;
75 static const int M_X
= 128;
76 static const int M_Y
= 208;
79 for( x
= 0; x
< 256; x
++)
82 a
= ( x
* M_Y
+ M_X
/ 2) / M_X
;
84 a
= M_Y
+ ( ( x
- M_X
) * ( M_MAX
- M_Y
) +
85 ( M_MAX
- M_X
) / 2 ) / ( M_MAX
- M_X
);
87 aGammaTable
[x
] = (unsigned char)a
;
91 static FT_Library aLibFT
= 0;
93 // enable linking with old FT versions
94 static int nFTVERSION
= 0;
96 typedef std::unordered_map
<const char*, std::shared_ptr
<FtFontFile
>, rtl::CStringHash
, rtl::CStringEqual
> FontFileList
;
98 namespace { struct vclFontFileList
: public rtl::Static
< FontFileList
, vclFontFileList
> {}; }
100 // TODO: remove when the priorities are selected by UI
101 // if (AH==0) => disable autohinting
102 // if (AA==0) => disable antialiasing
103 // if (EB==0) => disable embedded bitmaps
104 // if (AA prio <= AH prio) => antialias + autohint
105 // if (AH<AA) => do not autohint when antialiasing
106 // if (EB<AH) => do not autohint for monochrome
107 static int nDefaultPrioEmbedded
= 2;
108 static int nDefaultPrioAutoHint
= 1;
109 static int nDefaultPrioAntiAlias
= 1;
113 FtFontFile::FtFontFile( const OString
& rNativeFileName
)
114 : maNativeFileName( rNativeFileName
),
120 // boost font preference if UI language is mentioned in filename
121 int nPos
= maNativeFileName
.lastIndexOf( '_' );
122 if( nPos
== -1 || maNativeFileName
[nPos
+1] == '.' )
123 mnLangBoost
+= 0x1000; // no langinfo => good
126 static const char* pLangBoost
= NULL
;
127 static bool bOnce
= true;
131 pLangBoost
= vcl::getLangBoost();
134 if( pLangBoost
&& !strncasecmp( pLangBoost
, &maNativeFileName
.getStr()[nPos
+1], 3 ) )
135 mnLangBoost
+= 0x2000; // matching langinfo => better
139 FtFontFile
* FtFontFile::FindFontFile( const OString
& rNativeFileName
)
141 // font file already known? (e.g. for ttc, synthetic, aliased fonts)
142 const char* pFileName
= rNativeFileName
.getStr();
143 FontFileList
&rFontFileList
= vclFontFileList::get();
144 FontFileList::const_iterator it
= rFontFileList
.find( pFileName
);
145 if( it
!= rFontFileList
.end() )
146 return it
->second
.get();
148 // no => create new one
149 FtFontFile
* pFontFile
= new FtFontFile( rNativeFileName
);
150 pFileName
= pFontFile
->maNativeFileName
.getStr();
151 rFontFileList
[pFileName
].reset(pFontFile
);
155 bool FtFontFile::Map()
157 if( mnRefCount
++ <= 0 )
159 const char* pFileName
= maNativeFileName
.getStr();
160 int nFile
= open( pFileName
, O_RDONLY
);
165 int nRet
= fstat( nFile
, &aStat
);
171 mnFileSize
= aStat
.st_size
;
172 mpFileMap
= static_cast<unsigned char*>(
173 mmap( NULL
, mnFileSize
, PROT_READ
, MAP_SHARED
, nFile
, 0 ));
174 if( mpFileMap
== MAP_FAILED
)
179 return (mpFileMap
!= NULL
);
182 void FtFontFile::Unmap()
184 if( (--mnRefCount
> 0) || (mpFileMap
== NULL
) )
187 munmap( mpFileMap
, mnFileSize
);
192 // wrap FtFontInfo's table function
193 const void * graphiteFontTable(const void* appFaceHandle
, unsigned int name
, size_t *len
)
195 const FtFontInfo
* pFontInfo
= static_cast<const FtFontInfo
*>(appFaceHandle
);
202 #ifndef OSL_BIGENDIAN
204 swapped
.m_c
[3] = tableId
.m_c
[0];
205 swapped
.m_c
[2] = tableId
.m_c
[1];
206 swapped
.m_c
[1] = tableId
.m_c
[2];
207 swapped
.m_c
[0] = tableId
.m_c
[3];
208 tableId
.m_id
= swapped
.m_id
;
210 tableId
.m_c
[4] = '\0';
211 sal_uLong nLength
= 0;
212 const void * pTable
= static_cast<const void*>(pFontInfo
->GetTable(tableId
.m_c
, &nLength
));
213 if (len
) *len
= static_cast<size_t>(nLength
);
218 FtFontInfo::FtFontInfo( const ImplDevFontAttributes
& rDevFontAttributes
,
219 const OString
& rNativeFileName
, int nFaceNum
, sal_IntPtr nFontId
, int nSynthetic
)
222 mpFontFile( FtFontFile::FindFontFile( rNativeFileName
) ),
223 mnFaceNum( nFaceNum
),
225 mnSynthetic( nSynthetic
),
227 mbCheckedGraphite(false),
228 mpGraphiteFace(NULL
),
231 maDevFontAttributes( rDevFontAttributes
),
232 mpFontCharMap( NULL
),
233 mpChar2Glyph( NULL
),
236 // prefer font with low ID
237 maDevFontAttributes
.mnQuality
+= 10000 - nFontId
;
238 // prefer font with matching file names
239 maDevFontAttributes
.mnQuality
+= mpFontFile
->GetLangBoost();
242 FtFontInfo::~FtFontInfo()
249 delete mpGraphiteFace
;
253 void FtFontInfo::InitHashes() const
255 // TODO: avoid pointers when empty stl::hash_* objects become cheap
256 mpChar2Glyph
= new Int2IntMap();
257 mpGlyph2Char
= new Int2IntMap();
260 FT_FaceRec_
* FtFontInfo::GetFaceFT()
262 if (!maFaceFT
&& mpFontFile
->Map())
264 FT_Error rc
= FT_New_Memory_Face( aLibFT
,
265 mpFontFile
->GetBuffer(),
266 mpFontFile
->GetFileSize(), mnFaceNum
, &maFaceFT
);
267 if( (rc
!= FT_Err_Ok
) || (maFaceFT
->num_glyphs
<= 0) )
276 GraphiteFaceWrapper
* FtFontInfo::GetGraphiteFace()
278 if (mbCheckedGraphite
)
279 return mpGraphiteFace
;
280 // test for graphite here so that it is cached most efficiently
281 if (GetTable("Silf", 0))
283 static const char* pGraphiteCacheStr
= getenv( "SAL_GRAPHITE_CACHE_SIZE" );
284 int graphiteSegCacheSize
= pGraphiteCacheStr
? (atoi(pGraphiteCacheStr
)) : 0;
285 gr_face
* pGraphiteFace
;
286 if (graphiteSegCacheSize
> 500)
287 pGraphiteFace
= gr_make_face_with_seg_cache(this, graphiteFontTable
, graphiteSegCacheSize
, gr_face_cacheCmap
);
289 pGraphiteFace
= gr_make_face(this, graphiteFontTable
, gr_face_cacheCmap
);
291 mpGraphiteFace
= new GraphiteFaceWrapper(pGraphiteFace
);
293 mbCheckedGraphite
= true;
294 return mpGraphiteFace
;
298 void FtFontInfo::ReleaseFaceFT()
300 if (--mnRefCount
<= 0)
302 FT_Done_Face( maFaceFT
);
308 static unsigned GetUInt( const unsigned char* p
) { return((p
[0]<<24)+(p
[1]<<16)+(p
[2]<<8)+p
[3]);}
309 static unsigned GetUShort( const unsigned char* p
){ return((p
[0]<<8)+p
[1]);}
310 //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
312 static const sal_uInt32 T_true
= 0x74727565; /* 'true' */
313 static const sal_uInt32 T_ttcf
= 0x74746366; /* 'ttcf' */
314 static const sal_uInt32 T_otto
= 0x4f54544f; /* 'OTTO' */
316 const unsigned char* FtFontInfo::GetTable( const char* pTag
, sal_uLong
* pLength
) const
318 const unsigned char* pBuffer
= mpFontFile
->GetBuffer();
319 int nFileSize
= mpFontFile
->GetFileSize();
320 if( !pBuffer
|| nFileSize
<1024 )
323 // we currently handle TTF, TTC and OTF headers
324 unsigned nFormat
= GetUInt( pBuffer
);
326 const unsigned char* p
= pBuffer
+ 12;
327 if( nFormat
== T_ttcf
) // TTC_MAGIC
328 p
+= GetUInt( p
+ 4 * mnFaceNum
);
329 else if( nFormat
!= 0x00010000 && nFormat
!= T_true
&& nFormat
!= T_otto
) // TTF_MAGIC and Apple TTF Magic and PS-OpenType font
332 // walk table directory until match
333 int nTables
= GetUShort( p
- 8 );
334 if( nTables
>= 64 ) // something fishy?
336 for( int i
= 0; i
< nTables
; ++i
, p
+=16 )
338 if( p
[0]==pTag
[0] && p
[1]==pTag
[1] && p
[2]==pTag
[2] && p
[3]==pTag
[3] )
340 sal_uLong nLength
= GetUInt( p
+ 12 );
341 if( pLength
!= NULL
)
343 const unsigned char* pTable
= pBuffer
+ GetUInt( p
+ 8 );
344 if( (pTable
+ nLength
) <= (mpFontFile
->GetBuffer() + nFileSize
) )
352 void FtFontInfo::AnnounceFont( PhysicalFontCollection
* pFontCollection
)
354 ImplFTSFontData
* pFD
= new ImplFTSFontData( this, maDevFontAttributes
);
355 pFontCollection
->Add( pFD
);
358 FreetypeManager::FreetypeManager()
361 /*FT_Error rcFT =*/ FT_Init_FreeType( &aLibFT
);
363 FT_Int nMajor
= 0, nMinor
= 0, nPatch
= 0;
364 FT_Library_Version(aLibFT
, &nMajor
, &nMinor
, &nPatch
);
365 nFTVERSION
= nMajor
* 1000 + nMinor
* 100 + nPatch
;
367 // TODO: remove when the priorities are selected by UI
369 pEnv
= ::getenv( "SAL_EMBEDDED_BITMAP_PRIORITY" );
371 nDefaultPrioEmbedded
= pEnv
[0] - '0';
372 pEnv
= ::getenv( "SAL_ANTIALIASED_TEXT_PRIORITY" );
374 nDefaultPrioAntiAlias
= pEnv
[0] - '0';
375 pEnv
= ::getenv( "SAL_AUTOHINTING_PRIORITY" );
377 nDefaultPrioAutoHint
= pEnv
[0] - '0';
380 vclFontFileList::get();
383 FT_Face
ServerFont::GetFtFace() const
385 FT_Activate_Size( maSizeFT
);
390 FreetypeManager::~FreetypeManager()
395 void FreetypeManager::AddFontFile( const OString
& rNormalizedName
,
396 int nFaceNum
, sal_IntPtr nFontId
, const ImplDevFontAttributes
& rDevFontAttr
)
398 if( rNormalizedName
.isEmpty() )
401 if( maFontList
.find( nFontId
) != maFontList
.end() )
404 FtFontInfo
* pFontInfo
= new FtFontInfo( rDevFontAttr
,
405 rNormalizedName
, nFaceNum
, nFontId
, 0);
406 maFontList
[ nFontId
] = pFontInfo
;
407 if( mnMaxFontId
< nFontId
)
408 mnMaxFontId
= nFontId
;
411 void FreetypeManager::AnnounceFonts( PhysicalFontCollection
* pToAdd
) const
413 for( FontList::const_iterator it
= maFontList
.begin(); it
!= maFontList
.end(); ++it
)
415 FtFontInfo
* pFtFontInfo
= it
->second
;
416 pFtFontInfo
->AnnounceFont( pToAdd
);
420 void FreetypeManager::ClearFontList( )
422 for( FontList::iterator it
= maFontList
.begin(); it
!= maFontList
.end(); ++it
)
424 FtFontInfo
* pFtFontInfo
= it
->second
;
430 ServerFont
* FreetypeManager::CreateFont( const FontSelectPattern
& rFSD
)
432 FtFontInfo
* pFontInfo
= NULL
;
434 // find a FontInfo matching to the font id
435 sal_IntPtr nFontId
= reinterpret_cast<sal_IntPtr
>( rFSD
.mpFontData
);
436 FontList::iterator it
= maFontList
.find( nFontId
);
437 if( it
!= maFontList
.end() )
438 pFontInfo
= it
->second
;
443 ServerFont
* pNew
= new ServerFont( rFSD
, pFontInfo
);
448 ImplFTSFontData::ImplFTSFontData( FtFontInfo
* pFI
, const ImplDevFontAttributes
& rDFA
)
449 : PhysicalFontFace( rDFA
, IFTSFONT_MAGIC
),
453 mbOrientation
= true;
456 ImplFontEntry
* ImplFTSFontData::CreateFontInstance( FontSelectPattern
& rFSD
) const
458 ImplServerFontEntry
* pEntry
= new ImplServerFontEntry( rFSD
);
464 ServerFont::ServerFont( const FontSelectPattern
& rFSD
, FtFontInfo
* pFI
)
468 mnBytesUsed( sizeof(ServerFont
) ),
469 mpPrevGCFont( NULL
),
470 mpNextGCFont( NULL
),
473 mbCollectedZW( false ),
474 mnPrioEmbedded(nDefaultPrioEmbedded
),
475 mnPrioAntiAlias(nDefaultPrioAntiAlias
),
476 mnPrioAutoHint(nDefaultPrioAutoHint
),
482 mbArtItalic( false ),
485 mpLayoutEngine( NULL
)
487 // TODO: move update of mpFontEntry into FontEntry class when
488 // it becomes responsible for the ServerFont instantiation
489 static_cast<ImplServerFontEntry
*>(rFSD
.mpFontEntry
)->SetServerFont( this );
491 maFaceFT
= pFI
->GetFaceFT();
493 if( rFSD
.mnOrientation
!= 0 )
495 const double dRad
= rFSD
.mnOrientation
* ( F_2PI
/ 3600.0 );
496 mnCos
= static_cast<long>( 0x10000 * cos( dRad
) + 0.5 );
497 mnSin
= static_cast<long>( 0x10000 * sin( dRad
) + 0.5 );
500 // set the pixel size of the font instance
501 mnWidth
= rFSD
.mnWidth
;
503 mnWidth
= rFSD
.mnHeight
;
504 mfStretch
= (double)mnWidth
/ rFSD
.mnHeight
;
505 // sanity check (e.g. #i66394#, #i66244#, #66537#)
506 if( (mnWidth
< 0) || (mfStretch
> +64.0) || (mfStretch
< -64.0) )
512 FT_New_Size( maFaceFT
, &maSizeFT
);
513 FT_Activate_Size( maSizeFT
);
514 FT_Error rc
= FT_Set_Pixel_Sizes( maFaceFT
, mnWidth
, rFSD
.mnHeight
);
515 if( rc
!= FT_Err_Ok
)
518 FT_Select_Charmap(maFaceFT
, FT_ENCODING_UNICODE
);
520 if( mpFontInfo
->IsSymbolFont() )
522 FT_Encoding eEncoding
= FT_ENCODING_MS_SYMBOL
;
523 if (!FT_IS_SFNT(maFaceFT
))
524 eEncoding
= FT_ENCODING_ADOBE_CUSTOM
; // freetype wants this for PS symbol fonts
526 FT_Select_Charmap(maFaceFT
, eEncoding
);
533 // TODO: query GASP table for load flags
534 mnLoadFlags
= FT_LOAD_DEFAULT
;
535 #if 1 // #i97326# cairo sometimes uses FT_Set_Transform() on our FT_FACE
536 // we are not using FT_Set_Transform() yet, so just ignore it for now
537 mnLoadFlags
|= FT_LOAD_IGNORE_TRANSFORM
;
540 mbArtItalic
= (rFSD
.GetSlant() != ITALIC_NONE
&& pFI
->GetFontAttributes().GetSlant() == ITALIC_NONE
);
541 mbArtBold
= (rFSD
.GetWeight() > WEIGHT_MEDIUM
&& pFI
->GetFontAttributes().GetWeight() <= WEIGHT_MEDIUM
);
544 //static const int TT_CODEPAGE_RANGE_874 = (1L << 16); // Thai
545 //static const int TT_CODEPAGE_RANGE_932 = (1L << 17); // JIS/Japan
546 //static const int TT_CODEPAGE_RANGE_936 = (1L << 18); // Chinese: Simplified
547 //static const int TT_CODEPAGE_RANGE_949 = (1L << 19); // Korean Wansung
548 //static const int TT_CODEPAGE_RANGE_950 = (1L << 20); // Chinese: Traditional
549 //static const int TT_CODEPAGE_RANGE_1361 = (1L << 21); // Korean Johab
550 static const int TT_CODEPAGE_RANGES1_CJKT
= 0x3F0000; // all of the above
551 const TT_OS2
* pOs2
= static_cast<const TT_OS2
*>(FT_Get_Sfnt_Table( maFaceFT
, ft_sfnt_os2
));
552 if ((pOs2
) && (pOs2
->ulCodePageRange1
& TT_CODEPAGE_RANGES1_CJKT
)
553 && rFSD
.mnHeight
< 20)
557 if( ((mnCos
!= 0) && (mnSin
!= 0)) || (mnPrioEmbedded
<= 0) )
558 mnLoadFlags
|= FT_LOAD_NO_BITMAP
;
561 void ServerFont::SetFontOptions(std::shared_ptr
<ImplFontOptions
> xFontOptions
)
563 mxFontOptions
= xFontOptions
;
568 FontAutoHint eHint
= mxFontOptions
->GetUseAutoHint();
569 if( eHint
== AUTOHINT_DONTKNOW
)
570 eHint
= mbUseGamma
? AUTOHINT_TRUE
: AUTOHINT_FALSE
;
572 if( eHint
== AUTOHINT_TRUE
)
573 mnLoadFlags
|= FT_LOAD_FORCE_AUTOHINT
;
575 if( (mnSin
!= 0) && (mnCos
!= 0) ) // hinting for 0/90/180/270 degrees only
576 mnLoadFlags
|= FT_LOAD_NO_HINTING
;
577 mnLoadFlags
|= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH
; //#88334#
579 if (mxFontOptions
->DontUseAntiAlias())
581 if (mxFontOptions
->DontUseEmbeddedBitmaps())
583 if (mxFontOptions
->DontUseHinting())
586 if( mnPrioAutoHint
<= 0 )
587 mnLoadFlags
|= FT_LOAD_NO_HINTING
;
589 #if defined(FT_LOAD_TARGET_LIGHT) && defined(FT_LOAD_TARGET_NORMAL)
590 if( !(mnLoadFlags
& FT_LOAD_NO_HINTING
) )
592 mnLoadFlags
|= FT_LOAD_TARGET_NORMAL
;
593 switch (mxFontOptions
->GetHintStyle())
596 mnLoadFlags
|= FT_LOAD_NO_HINTING
;
599 mnLoadFlags
|= FT_LOAD_TARGET_LIGHT
;
610 if( mnPrioEmbedded
<= 0 )
611 mnLoadFlags
|= FT_LOAD_NO_BITMAP
;
614 std::shared_ptr
<ImplFontOptions
> ServerFont::GetFontOptions() const
616 return mxFontOptions
;
619 const OString
& ServerFont::GetFontFileName() const
621 return mpFontInfo
->GetFontFileName();
625 ServerFont::~ServerFont()
627 delete mpLayoutEngine
;
630 FT_Done_Size( maSizeFT
);
632 mpFontInfo
->ReleaseFaceFT();
634 ReleaseFromGarbageCollect();
638 void ServerFont::FetchFontMetric( ImplFontMetricData
& rTo
, long& rFactor
) const
640 static_cast<ImplFontAttributes
&>(rTo
) = mpFontInfo
->GetFontAttributes();
642 rTo
.mbScalableFont
= true;
644 rTo
.mbKernableFont
= FT_HAS_KERNING( maFaceFT
) != 0;
645 rTo
.mnOrientation
= GetFontSelData().mnOrientation
;
647 //Always consider [star]symbol as symbol fonts
648 if ( IsStarSymbol( rTo
.GetFamilyName() ) )
649 rTo
.SetSymbolFlag( true );
651 FT_Activate_Size( maSizeFT
);
655 const TT_OS2
* pOS2
= static_cast<const TT_OS2
*>(FT_Get_Sfnt_Table( maFaceFT
, ft_sfnt_os2
));
656 const double fScale
= (double)GetFontSelData().mnHeight
/ maFaceFT
->units_per_EM
;
660 rTo
.mnExtLeading
= 0;
662 rTo
.mnWidth
= mnWidth
;
664 // Calculating ascender and descender:
665 // FreeType >= 2.4.6 does the right thing, so we just use what it gives us,
666 // for earlier versions we emulate its behaviour;
667 // take them from 'hhea' table,
668 // if zero take them from 'OS/2' table,
669 // if zero take them from FreeType's font metrics
670 if (nFTVERSION
>= 2406)
672 const FT_Size_Metrics
& rMetrics
= maFaceFT
->size
->metrics
;
673 rTo
.mnAscent
= (rMetrics
.ascender
+ 32) >> 6;
674 rTo
.mnDescent
= (-rMetrics
.descender
+ 32) >> 6;
675 rTo
.mnExtLeading
= ((rMetrics
.height
+ 32) >> 6) - (rTo
.mnAscent
+ rTo
.mnDescent
);
679 const TT_HoriHeader
* pHHea
= static_cast<const TT_HoriHeader
*>(FT_Get_Sfnt_Table(maFaceFT
, ft_sfnt_hhea
));
682 rTo
.mnAscent
= pHHea
->Ascender
* fScale
+ 0.5;
683 rTo
.mnDescent
= -pHHea
->Descender
* fScale
+ 0.5;
684 rTo
.mnExtLeading
= pHHea
->Line_Gap
* fScale
+ 0.5;
687 if (!(rTo
.mnAscent
|| rTo
.mnDescent
))
689 if (pOS2
&& (pOS2
->version
!= 0xFFFF))
691 if (pOS2
->sTypoAscender
|| pOS2
->sTypoDescender
)
693 rTo
.mnAscent
= pOS2
->sTypoAscender
* fScale
+ 0.5;
694 rTo
.mnDescent
= -pOS2
->sTypoDescender
* fScale
+ 0.5;
695 rTo
.mnExtLeading
= pOS2
->sTypoLineGap
* fScale
+ 0.5;
699 rTo
.mnAscent
= pOS2
->usWinAscent
* fScale
+ 0.5;
700 rTo
.mnDescent
= pOS2
->usWinDescent
* fScale
+ 0.5;
701 rTo
.mnExtLeading
= 0;
706 if (!(rTo
.mnAscent
|| rTo
.mnDescent
))
708 const FT_Size_Metrics
& rMetrics
= maFaceFT
->size
->metrics
;
709 rTo
.mnAscent
= (rMetrics
.ascender
+ 32) >> 6;
710 rTo
.mnDescent
= (-rMetrics
.descender
+ 32) >> 6;
711 rTo
.mnExtLeading
= ((rMetrics
.height
+ 32) >> 6) - (rTo
.mnAscent
+ rTo
.mnDescent
);
715 rTo
.mnIntLeading
= rTo
.mnAscent
+ rTo
.mnDescent
- (maFaceFT
->units_per_EM
* fScale
+ 0.5);
717 if( pOS2
&& (pOS2
->version
!= 0xFFFF) )
719 // map the panose info from the OS2 table to their VCL counterparts
720 switch( pOS2
->panose
[0] )
722 case 1: rTo
.SetFamilyType( FAMILY_ROMAN
); break;
723 case 2: rTo
.SetFamilyType( FAMILY_SWISS
); break;
724 case 3: rTo
.SetFamilyType( FAMILY_MODERN
); break;
725 case 4: rTo
.SetFamilyType( FAMILY_SCRIPT
); break;
726 case 5: rTo
.SetFamilyType( FAMILY_DECORATIVE
); break;
727 // TODO: is it reasonable to override the attribute with DONTKNOW?
728 case 0: // fall through
729 default: rTo
.meFamilyType
= FAMILY_DONTKNOW
; break;
732 switch( pOS2
->panose
[3] )
734 case 2: // fall through
735 case 3: // fall through
736 case 4: // fall through
737 case 5: // fall through
738 case 6: // fall through
739 case 7: // fall through
740 case 8: rTo
.SetPitch( PITCH_VARIABLE
); break;
741 case 9: rTo
.SetPitch( PITCH_FIXED
); break;
742 // TODO: is it reasonable to override the attribute with DONTKNOW?
743 case 0: // fall through
744 case 1: // fall through
745 default: rTo
.SetPitch( PITCH_DONTKNOW
); break;
749 // initialize kashida width
750 // TODO: what if there are different versions of this glyph available
751 const int nKashidaGlyphId
= GetRawGlyphIndex( 0x0640 );
752 if( nKashidaGlyphId
)
754 GlyphData aGlyphData
;
755 InitGlyphData( nKashidaGlyphId
, aGlyphData
);
756 rTo
.mnMinKashida
= aGlyphData
.GetMetric().GetCharWidth();
760 static inline void SplitGlyphFlags( const ServerFont
& rFont
, sal_GlyphId
& rGlyphId
, int& nGlyphFlags
)
762 nGlyphFlags
= rGlyphId
& GF_FLAGMASK
;
763 rGlyphId
&= GF_IDXMASK
;
765 if( rGlyphId
& GF_ISCHAR
)
766 rGlyphId
= rFont
.GetRawGlyphIndex( rGlyphId
);
769 int ServerFont::ApplyGlyphTransform( int nGlyphFlags
,
770 FT_Glyph pGlyphFT
, bool bForBitmapProcessing
) const
772 int nAngle
= GetFontSelData().mnOrientation
;
773 // shortcut most common case
774 if( !nAngle
&& !nGlyphFlags
)
777 const FT_Size_Metrics
& rMetrics
= maFaceFT
->size
->metrics
;
781 bool bStretched
= false;
783 switch( nGlyphFlags
& GF_ROTMASK
)
793 case GF_ROTL
: // left
795 bStretched
= (mfStretch
!= 1.0);
796 aVector
.x
= (FT_Pos
)(+rMetrics
.descender
* mfStretch
);
797 aVector
.y
= -rMetrics
.ascender
;
798 aMatrix
.xx
= (FT_Pos
)(-mnSin
/ mfStretch
);
799 aMatrix
.yy
= (FT_Pos
)(-mnSin
* mfStretch
);
800 aMatrix
.xy
= (FT_Pos
)(-mnCos
* mfStretch
);
801 aMatrix
.yx
= (FT_Pos
)(+mnCos
/ mfStretch
);
803 case GF_ROTR
: // right
805 bStretched
= (mfStretch
!= 1.0);
806 aVector
.x
= -maFaceFT
->glyph
->metrics
.horiAdvance
;
807 aVector
.x
+= (FT_Pos
)(rMetrics
.descender
* mnSin
/65536.0);
808 aVector
.y
= (FT_Pos
)(-rMetrics
.descender
* mfStretch
* mnCos
/65536.0);
809 aMatrix
.xx
= (FT_Pos
)(+mnSin
/ mfStretch
);
810 aMatrix
.yy
= (FT_Pos
)(+mnSin
* mfStretch
);
811 aMatrix
.xy
= (FT_Pos
)(+mnCos
* mfStretch
);
812 aMatrix
.yx
= (FT_Pos
)(-mnCos
/ mfStretch
);
819 if( pGlyphFT
->format
!= FT_GLYPH_FORMAT_BITMAP
)
821 FT_Glyph_Transform( pGlyphFT
, NULL
, &aVector
);
823 // orthogonal transforms are better handled by bitmap operations
824 if( bStretched
|| (bForBitmapProcessing
&& (nAngle
% 900) != 0) )
826 // apply non-orthogonal or stretch transformations
827 FT_Glyph_Transform( pGlyphFT
, &aMatrix
, NULL
);
833 // FT<=2005 ignores transforms for bitmaps, so do it manually
834 FT_BitmapGlyph pBmpGlyphFT
= reinterpret_cast<FT_BitmapGlyph
>(pGlyphFT
);
835 pBmpGlyphFT
->left
+= (aVector
.x
+ 32) >> 6;
836 pBmpGlyphFT
->top
+= (aVector
.y
+ 32) >> 6;
842 sal_GlyphId
ServerFont::GetRawGlyphIndex(sal_UCS4 aChar
, sal_UCS4 aVS
) const
844 if( mpFontInfo
->IsSymbolFont() )
846 if( !FT_IS_SFNT( maFaceFT
) )
848 if( (aChar
& 0xFF00) == 0xF000 )
849 aChar
&= 0xFF; // PS font symbol mapping
850 else if( aChar
> 0xFF )
856 #if HAVE_FT_FACE_GETCHARVARIANTINDEX
857 // If asked, check first for variant glyph with the given Unicode variation
858 // selector. This is quite uncommon so we don't bother with caching here.
859 // Disabled for buggy FreeType versions:
860 // https://bugzilla.mozilla.org/show_bug.cgi?id=618406#c8
861 if (aVS
&& nFTVERSION
>= 2404)
862 nGlyphIndex
= FT_Face_GetCharVariantIndex(maFaceFT
, aChar
, aVS
);
865 if (nGlyphIndex
== 0)
867 // cache glyph indexes in font info to share between different sizes
868 nGlyphIndex
= mpFontInfo
->GetGlyphIndex( aChar
);
869 if( nGlyphIndex
< 0 )
871 nGlyphIndex
= FT_Get_Char_Index( maFaceFT
, aChar
);
874 // check if symbol aliasing helps
875 if( (aChar
<= 0x00FF) && mpFontInfo
->IsSymbolFont() )
876 nGlyphIndex
= FT_Get_Char_Index( maFaceFT
, aChar
| 0xF000 );
878 mpFontInfo
->CacheGlyphIndex( aChar
, nGlyphIndex
);
882 return sal_GlyphId( nGlyphIndex
);
885 sal_GlyphId
ServerFont::FixupGlyphIndex( sal_GlyphId aGlyphId
, sal_UCS4 aChar
) const
887 int nGlyphFlags
= GF_NONE
;
889 // do glyph substitution if necessary
890 // CJK vertical writing needs special treatment
891 if( GetFontSelData().mbVertical
)
893 // TODO: rethink when GSUB is used for non-vertical case
894 GlyphSubstitution::const_iterator it
= maGlyphSubstitution
.find( aGlyphId
);
895 if( it
== maGlyphSubstitution
.end() )
897 nGlyphFlags
|= GetVerticalFlags( aChar
);
901 // for vertical GSUB also compensate for nOrientation=2700
902 aGlyphId
= (*it
).second
;
903 nGlyphFlags
|= GF_GSUB
| GF_ROTL
;
908 aGlyphId
|= nGlyphFlags
;
913 sal_GlyphId
ServerFont::GetGlyphIndex( sal_UCS4 aChar
) const
915 sal_GlyphId aGlyphId
= GetRawGlyphIndex( aChar
);
916 aGlyphId
= FixupGlyphIndex( aGlyphId
, aChar
);
920 static int lcl_GetCharWidth( FT_FaceRec_
* pFaceFT
, double fStretch
, int nGlyphFlags
)
922 int nCharWidth
= pFaceFT
->glyph
->metrics
.horiAdvance
;
924 if( nGlyphFlags
& GF_ROTMASK
) // for bVertical rotated glyphs
926 const FT_Size_Metrics
& rMetrics
= pFaceFT
->size
->metrics
;
927 nCharWidth
= (int)((rMetrics
.height
+ rMetrics
.descender
) * fStretch
);
930 return (nCharWidth
+ 32) >> 6;
933 void ServerFont::InitGlyphData( sal_GlyphId aGlyphId
, GlyphData
& rGD
) const
935 FT_Activate_Size( maSizeFT
);
938 SplitGlyphFlags( *this, aGlyphId
, nGlyphFlags
);
940 int nLoadFlags
= mnLoadFlags
;
943 // nLoadFlags |= FT_LOAD_NO_BITMAP;
945 FT_Error rc
= FT_Load_Glyph( maFaceFT
, aGlyphId
, nLoadFlags
);
947 if( rc
!= FT_Err_Ok
)
949 // we get here e.g. when a PS font lacks the default glyph
950 rGD
.SetCharWidth( 0 );
951 rGD
.SetDelta( 0, 0 );
952 rGD
.SetOffset( 0, 0 );
953 rGD
.SetSize( Size( 0, 0 ) );
957 const bool bOriginallyZeroWidth
= (maFaceFT
->glyph
->metrics
.horiAdvance
== 0);
959 FT_GlyphSlot_Embolden(maFaceFT
->glyph
);
961 const int nCharWidth
= bOriginallyZeroWidth
? 0 : lcl_GetCharWidth( maFaceFT
, mfStretch
, nGlyphFlags
);
962 rGD
.SetCharWidth( nCharWidth
);
965 rc
= FT_Get_Glyph( maFaceFT
->glyph
, &pGlyphFT
);
967 ApplyGlyphTransform( nGlyphFlags
, pGlyphFT
, false );
968 rGD
.SetDelta( (pGlyphFT
->advance
.x
+ 0x8000) >> 16, -((pGlyphFT
->advance
.y
+ 0x8000) >> 16) );
971 FT_Glyph_Get_CBox( pGlyphFT
, FT_GLYPH_BBOX_PIXELS
, &aBbox
);
972 if( aBbox
.yMin
> aBbox
.yMax
) // circumvent freetype bug
974 int t
=aBbox
.yMin
; aBbox
.yMin
=aBbox
.yMax
, aBbox
.yMax
=t
;
977 rGD
.SetOffset( aBbox
.xMin
, -aBbox
.yMax
);
978 rGD
.SetSize( Size( (aBbox
.xMax
-aBbox
.xMin
+1), (aBbox
.yMax
-aBbox
.yMin
) ) );
980 FT_Done_Glyph( pGlyphFT
);
983 bool ServerFont::GetAntialiasAdvice() const
985 if( GetFontSelData().mbNonAntialiased
|| (mnPrioAntiAlias
<=0) )
987 bool bAdviseAA
= true;
988 // TODO: also use GASP info
992 bool ServerFont::GetGlyphBitmap1( sal_GlyphId aGlyphId
, RawBitmap
& rRawBitmap
) const
994 FT_Activate_Size( maSizeFT
);
997 SplitGlyphFlags( *this, aGlyphId
, nGlyphFlags
);
999 FT_Int nLoadFlags
= mnLoadFlags
;
1000 // #i70930# force mono-hinting for monochrome text
1001 nLoadFlags
&= ~0xF0000;
1002 nLoadFlags
|= FT_LOAD_TARGET_MONO
;
1005 nLoadFlags
|= FT_LOAD_NO_BITMAP
;
1007 // for 0/90/180/270 degree fonts enable hinting even if not advisable
1008 // non-hinted and non-antialiased bitmaps just look too ugly
1009 if( (mnCos
==0 || mnSin
==0) && (mnPrioAutoHint
> 0) )
1010 nLoadFlags
&= ~FT_LOAD_NO_HINTING
;
1012 if( mnPrioEmbedded
<= mnPrioAutoHint
)
1013 nLoadFlags
|= FT_LOAD_NO_BITMAP
;
1015 FT_Error rc
= FT_Load_Glyph( maFaceFT
, aGlyphId
, nLoadFlags
);
1017 if( rc
!= FT_Err_Ok
)
1021 FT_GlyphSlot_Embolden(maFaceFT
->glyph
);
1024 rc
= FT_Get_Glyph( maFaceFT
->glyph
, &pGlyphFT
);
1025 if( rc
!= FT_Err_Ok
)
1028 int nAngle
= ApplyGlyphTransform( nGlyphFlags
, pGlyphFT
, true );
1033 aMatrix
.xx
= aMatrix
.yy
= 0x10000L
;
1034 aMatrix
.xy
= 0x6000L
, aMatrix
.yx
= 0;
1035 FT_Glyph_Transform( pGlyphFT
, &aMatrix
, NULL
);
1038 // Check for zero area bounding boxes as this crashes some versions of FT.
1039 // This also provides a handy short cut as much of the code following
1040 // becomes an expensive nop when a glyph covers no pixels.
1042 FT_Glyph_Get_CBox(pGlyphFT
, ft_glyph_bbox_unscaled
, &cbox
);
1044 if( (cbox
.xMax
- cbox
.xMin
) == 0 || (cbox
.yMax
- cbox
.yMin
== 0) )
1047 memset(&rRawBitmap
, 0, sizeof rRawBitmap
);
1048 FT_Done_Glyph( pGlyphFT
);
1052 if( pGlyphFT
->format
!= FT_GLYPH_FORMAT_BITMAP
)
1054 if( pGlyphFT
->format
== FT_GLYPH_FORMAT_OUTLINE
)
1055 reinterpret_cast<FT_OutlineGlyphRec
*>(pGlyphFT
)->outline
.flags
|= FT_OUTLINE_HIGH_PRECISION
;
1056 FT_Render_Mode nRenderMode
= FT_RENDER_MODE_MONO
;
1058 rc
= FT_Glyph_To_Bitmap( &pGlyphFT
, nRenderMode
, NULL
, true );
1059 if( rc
!= FT_Err_Ok
)
1061 FT_Done_Glyph( pGlyphFT
);
1066 const FT_BitmapGlyph pBmpGlyphFT
= reinterpret_cast<const FT_BitmapGlyph
>(pGlyphFT
);
1067 // NOTE: autohinting in FT<=2.0.2 miscalculates the offsets below by +-1
1068 rRawBitmap
.mnXOffset
= +pBmpGlyphFT
->left
;
1069 rRawBitmap
.mnYOffset
= -pBmpGlyphFT
->top
;
1071 const FT_Bitmap
& rBitmapFT
= pBmpGlyphFT
->bitmap
;
1072 rRawBitmap
.mnHeight
= rBitmapFT
.rows
;
1073 rRawBitmap
.mnBitCount
= 1;
1074 rRawBitmap
.mnWidth
= rBitmapFT
.width
;
1075 rRawBitmap
.mnScanlineSize
= rBitmapFT
.pitch
;
1077 const sal_uLong nNeededSize
= rRawBitmap
.mnScanlineSize
* rRawBitmap
.mnHeight
;
1079 if( rRawBitmap
.mnAllocated
< nNeededSize
)
1081 rRawBitmap
.mnAllocated
= 2*nNeededSize
;
1082 rRawBitmap
.mpBits
.reset(new unsigned char[ rRawBitmap
.mnAllocated
]);
1087 memcpy( rRawBitmap
.mpBits
.get(), rBitmapFT
.buffer
, nNeededSize
);
1091 memset( rRawBitmap
.mpBits
.get(), 0, nNeededSize
);
1092 const unsigned char* pSrcLine
= rBitmapFT
.buffer
;
1093 unsigned char* pDstLine
= rRawBitmap
.mpBits
.get();
1094 for( int h
= rRawBitmap
.mnHeight
; --h
>= 0; )
1096 memcpy( pDstLine
, pSrcLine
, rBitmapFT
.pitch
);
1097 pDstLine
+= rRawBitmap
.mnScanlineSize
;
1098 pSrcLine
+= rBitmapFT
.pitch
;
1101 unsigned char* p
= rRawBitmap
.mpBits
.get();
1102 for( sal_uLong y
=0; y
< rRawBitmap
.mnHeight
; y
++ )
1104 unsigned char nLastByte
= 0;
1105 for( sal_uLong x
=0; x
< rRawBitmap
.mnScanlineSize
; x
++ )
1107 unsigned char nTmp
= p
[x
] << 7;
1108 p
[x
] |= (p
[x
] >> 1) | nLastByte
;
1111 p
+= rRawBitmap
.mnScanlineSize
;
1115 FT_Done_Glyph( pGlyphFT
);
1117 // special case for 0/90/180/270 degree orientation
1124 rRawBitmap
.Rotate( nAngle
);
1131 bool ServerFont::GetGlyphBitmap8( sal_GlyphId aGlyphId
, RawBitmap
& rRawBitmap
) const
1133 FT_Activate_Size( maSizeFT
);
1136 SplitGlyphFlags( *this, aGlyphId
, nGlyphFlags
);
1138 FT_Int nLoadFlags
= mnLoadFlags
;
1141 nLoadFlags
|= FT_LOAD_NO_BITMAP
;
1143 if( (nGlyphFlags
& GF_UNHINTED
) || (mnPrioAutoHint
< mnPrioAntiAlias
) )
1144 nLoadFlags
|= FT_LOAD_NO_HINTING
;
1146 if( mnPrioEmbedded
<= mnPrioAntiAlias
)
1147 nLoadFlags
|= FT_LOAD_NO_BITMAP
;
1149 FT_Error rc
= FT_Load_Glyph( maFaceFT
, aGlyphId
, nLoadFlags
);
1151 if( rc
!= FT_Err_Ok
)
1155 FT_GlyphSlot_Embolden(maFaceFT
->glyph
);
1158 rc
= FT_Get_Glyph( maFaceFT
->glyph
, &pGlyphFT
);
1159 if( rc
!= FT_Err_Ok
)
1162 int nAngle
= ApplyGlyphTransform( nGlyphFlags
, pGlyphFT
, true );
1167 aMatrix
.xx
= aMatrix
.yy
= 0x10000L
;
1168 aMatrix
.xy
= 0x6000L
, aMatrix
.yx
= 0;
1169 FT_Glyph_Transform( pGlyphFT
, &aMatrix
, NULL
);
1172 if( pGlyphFT
->format
== FT_GLYPH_FORMAT_OUTLINE
)
1173 reinterpret_cast<FT_OutlineGlyph
>(pGlyphFT
)->outline
.flags
|= FT_OUTLINE_HIGH_PRECISION
;
1175 bool bEmbedded
= (pGlyphFT
->format
== FT_GLYPH_FORMAT_BITMAP
);
1178 rc
= FT_Glyph_To_Bitmap( &pGlyphFT
, FT_RENDER_MODE_NORMAL
, NULL
, true );
1179 if( rc
!= FT_Err_Ok
)
1181 FT_Done_Glyph( pGlyphFT
);
1186 const FT_BitmapGlyph pBmpGlyphFT
= reinterpret_cast<const FT_BitmapGlyph
>(pGlyphFT
);
1187 rRawBitmap
.mnXOffset
= +pBmpGlyphFT
->left
;
1188 rRawBitmap
.mnYOffset
= -pBmpGlyphFT
->top
;
1190 const FT_Bitmap
& rBitmapFT
= pBmpGlyphFT
->bitmap
;
1191 rRawBitmap
.mnHeight
= rBitmapFT
.rows
;
1192 rRawBitmap
.mnWidth
= rBitmapFT
.width
;
1193 rRawBitmap
.mnBitCount
= 8;
1194 rRawBitmap
.mnScanlineSize
= bEmbedded
? rBitmapFT
.width
: rBitmapFT
.pitch
;
1195 rRawBitmap
.mnScanlineSize
= (rRawBitmap
.mnScanlineSize
+ 3) & -4;
1197 const sal_uLong nNeededSize
= rRawBitmap
.mnScanlineSize
* rRawBitmap
.mnHeight
;
1198 if( rRawBitmap
.mnAllocated
< nNeededSize
)
1200 rRawBitmap
.mnAllocated
= 2*nNeededSize
;
1201 rRawBitmap
.mpBits
.reset(new unsigned char[ rRawBitmap
.mnAllocated
]);
1204 const unsigned char* pSrc
= rBitmapFT
.buffer
;
1205 unsigned char* pDest
= rRawBitmap
.mpBits
.get();
1209 for( int y
= rRawBitmap
.mnHeight
; --y
>= 0 ; )
1211 for( x
= 0; x
< static_cast<unsigned int>(rBitmapFT
.width
); ++x
)
1212 *(pDest
++) = *(pSrc
++);
1213 for(; x
< rRawBitmap
.mnScanlineSize
; ++x
)
1220 for( int y
= rRawBitmap
.mnHeight
; --y
>= 0 ; )
1222 unsigned char nSrc
= 0;
1223 for( x
= 0; x
< static_cast<unsigned int>(rBitmapFT
.width
); ++x
, nSrc
+=nSrc
)
1227 *(pDest
++) = (0x7F - nSrc
) >> 8;
1229 for(; x
< rRawBitmap
.mnScanlineSize
; ++x
)
1234 if( !bEmbedded
&& mbUseGamma
)
1236 unsigned char* p
= rRawBitmap
.mpBits
.get();
1237 for( sal_uLong y
=0; y
< rRawBitmap
.mnHeight
; y
++ )
1239 for( sal_uLong x
=0; x
< rRawBitmap
.mnWidth
; x
++ )
1241 p
[x
] = aGammaTable
[ p
[x
] ];
1243 p
+= rRawBitmap
.mnScanlineSize
;
1247 FT_Done_Glyph( pGlyphFT
);
1249 // special case for 0/90/180/270 degree orientation
1256 rRawBitmap
.Rotate( nAngle
);
1263 // determine unicode ranges in font
1265 const FontCharMapPtr
ServerFont::GetFontCharMap() const
1267 const FontCharMapPtr pFCMap
= mpFontInfo
->GetFontCharMap();
1271 const FontCharMapPtr
FtFontInfo::GetFontCharMap()
1273 // check if the charmap is already cached
1275 return mpFontCharMap
;
1277 // get the charmap and cache it
1278 CmapResult aCmapResult
;
1279 bool bOK
= GetFontCodeRanges( aCmapResult
);
1282 FontCharMapPtr
pFontCharMap( new FontCharMap ( aCmapResult
) );
1283 mpFontCharMap
= pFontCharMap
;
1287 FontCharMapPtr
pFontCharMap( new FontCharMap() );
1288 mpFontCharMap
= pFontCharMap
;
1290 // mpFontCharMap on either branch now has a refcount of 1
1291 return mpFontCharMap
;
1294 // TODO: merge into method GetFontCharMap()
1295 bool FtFontInfo::GetFontCodeRanges( CmapResult
& rResult
) const
1297 rResult
.mbSymbolic
= IsSymbolFont();
1299 // TODO: is the full CmapResult needed on platforms calling this?
1300 if( FT_IS_SFNT( maFaceFT
) )
1302 sal_uLong nLength
= 0;
1303 const unsigned char* pCmap
= GetTable( "cmap", &nLength
);
1304 if( pCmap
&& (nLength
> 0) )
1305 if( ParseCMAP( pCmap
, nLength
, rResult
) )
1309 typedef std::vector
<sal_uInt32
> U32Vector
;
1312 // FT's coverage is available since FT>=2.1.0 (OOo-baseline>=2.1.4 => ok)
1313 aCodes
.reserve( 0x1000 );
1314 FT_UInt nGlyphIndex
;
1315 for( sal_uInt32 cCode
= FT_Get_First_Char( maFaceFT
, &nGlyphIndex
);; )
1319 aCodes
.push_back( cCode
); // first code inside range
1320 sal_uInt32 cNext
= cCode
;
1321 do cNext
= FT_Get_Next_Char( maFaceFT
, cCode
, &nGlyphIndex
); while( cNext
== ++cCode
);
1322 aCodes
.push_back( cCode
); // first code outside range
1326 const int nCount
= aCodes
.size();
1328 if( !rResult
.mbSymbolic
)
1331 // we usually get here for Type1 symbol fonts
1332 aCodes
.push_back( 0xF020 );
1333 aCodes
.push_back( 0xF100 );
1336 sal_uInt32
* pCodes
= new sal_uInt32
[ nCount
];
1337 for( int i
= 0; i
< nCount
; ++i
)
1338 pCodes
[i
] = aCodes
[i
];
1339 rResult
.mpRangeCodes
= pCodes
;
1340 rResult
.mnRangeCount
= nCount
/ 2;
1344 bool ServerFont::GetFontCapabilities(vcl::FontCapabilities
&rFontCapabilities
) const
1348 sal_uLong nLength
= 0;
1350 const FT_Byte
* pGSUB
= mpFontInfo
->GetTable("GSUB", &nLength
);
1352 vcl::getTTScripts(rFontCapabilities
.maGSUBScriptTags
, pGSUB
, nLength
);
1355 const FT_Byte
* pOS2
= mpFontInfo
->GetTable("OS/2", &nLength
);
1358 bRet
= vcl::getTTCoverage(
1359 rFontCapabilities
.maUnicodeRange
,
1360 rFontCapabilities
.maCodePageRange
,
1372 PolyArgs( tools::PolyPolygon
& rPolyPoly
, sal_uInt16 nMaxPoints
);
1375 void AddPoint( long nX
, long nY
, PolyFlags
);
1376 void ClosePolygon();
1378 long GetPosX() const { return maPosition
.x
;}
1379 long GetPosY() const { return maPosition
.y
;}
1382 tools::PolyPolygon
& mrPolyPoly
;
1385 sal_uInt8
* mpFlagAry
;
1387 FT_Vector maPosition
;
1388 sal_uInt16 mnMaxPoints
;
1389 sal_uInt16 mnPoints
;
1394 PolyArgs::PolyArgs( tools::PolyPolygon
& rPolyPoly
, sal_uInt16 nMaxPoints
)
1395 : mrPolyPoly(rPolyPoly
),
1396 mnMaxPoints(nMaxPoints
),
1401 mpPointAry
= new Point
[ mnMaxPoints
];
1402 mpFlagAry
= new sal_uInt8
[ mnMaxPoints
];
1403 maPosition
.x
= maPosition
.y
= 0;
1406 PolyArgs::~PolyArgs()
1409 delete[] mpPointAry
;
1412 void PolyArgs::AddPoint( long nX
, long nY
, PolyFlags aFlag
)
1414 DBG_ASSERT( (mnPoints
< mnMaxPoints
), "FTGlyphOutline: AddPoint overflow!" );
1415 if( mnPoints
>= mnMaxPoints
)
1420 mpPointAry
[ mnPoints
] = Point( nX
, nY
);
1421 mpFlagAry
[ mnPoints
++ ]= aFlag
;
1422 bHasOffline
|= (aFlag
!= POLY_NORMAL
);
1425 void PolyArgs::ClosePolygon()
1430 // freetype seems to always close the polygon with an ON_CURVE point
1431 // PolyPoly wants to close the polygon itself => remove last point
1432 DBG_ASSERT( (mnPoints
>= 2), "FTGlyphOutline: PolyFinishNum failed!" );
1434 DBG_ASSERT( (mpPointAry
[0]==mpPointAry
[mnPoints
]), "FTGlyphOutline: PolyFinishEq failed!" );
1435 DBG_ASSERT( (mpFlagAry
[0]==POLY_NORMAL
), "FTGlyphOutline: PolyFinishFE failed!" );
1436 DBG_ASSERT( (mpFlagAry
[mnPoints
]==POLY_NORMAL
), "FTGlyphOutline: PolyFinishFS failed!" );
1438 Polygon
aPoly( mnPoints
, mpPointAry
, (bHasOffline
? mpFlagAry
: NULL
) );
1441 // This may be a invalid polygons, e.g. the last point is a control point.
1442 // So close the polygon (and add the first point again) if the last point
1443 // is a control point or different from first.
1445 // Now really duplicating the first point, to close or correct the
1446 // polygon. Also no longer duplicating the flags, but enforcing
1447 // POLY_NORMAL for the newly added last point.
1448 const sal_uInt16
nPolySize(aPoly
.GetSize());
1451 if((aPoly
.HasFlags() && POLY_CONTROL
== aPoly
.GetFlags(nPolySize
- 1))
1452 || (aPoly
.GetPoint(nPolySize
- 1) != aPoly
.GetPoint(0)))
1454 aPoly
.SetSize(nPolySize
+ 1);
1455 aPoly
.SetPoint(aPoly
.GetPoint(0), nPolySize
);
1457 if(aPoly
.HasFlags())
1459 aPoly
.SetFlags(nPolySize
, POLY_NORMAL
);
1464 mrPolyPoly
.Insert( aPoly
);
1466 bHasOffline
= false;
1471 // TODO: wait till all compilers accept that calling conventions
1472 // for functions are the same independent of implementation constness,
1473 // then uncomment the const-tokens in the function interfaces below
1474 static int FT_move_to( FT_Vector_CPtr p0
, void* vpPolyArgs
)
1476 PolyArgs
& rA
= *static_cast<PolyArgs
*>(vpPolyArgs
);
1478 // move_to implies a new polygon => finish old polygon first
1481 rA
.AddPoint( p0
->x
, p0
->y
, POLY_NORMAL
);
1485 static int FT_line_to( FT_Vector_CPtr p1
, void* vpPolyArgs
)
1487 PolyArgs
& rA
= *static_cast<PolyArgs
*>(vpPolyArgs
);
1488 rA
.AddPoint( p1
->x
, p1
->y
, POLY_NORMAL
);
1492 static int FT_conic_to( FT_Vector_CPtr p1
, FT_Vector_CPtr p2
, void* vpPolyArgs
)
1494 PolyArgs
& rA
= *static_cast<PolyArgs
*>(vpPolyArgs
);
1496 // VCL's Polygon only knows cubic beziers
1497 const long nX1
= (2 * rA
.GetPosX() + 4 * p1
->x
+ 3) / 6;
1498 const long nY1
= (2 * rA
.GetPosY() + 4 * p1
->y
+ 3) / 6;
1499 rA
.AddPoint( nX1
, nY1
, POLY_CONTROL
);
1501 const long nX2
= (2 * p2
->x
+ 4 * p1
->x
+ 3) / 6;
1502 const long nY2
= (2 * p2
->y
+ 4 * p1
->y
+ 3) / 6;
1503 rA
.AddPoint( nX2
, nY2
, POLY_CONTROL
);
1505 rA
.AddPoint( p2
->x
, p2
->y
, POLY_NORMAL
);
1509 static int FT_cubic_to( FT_Vector_CPtr p1
, FT_Vector_CPtr p2
, FT_Vector_CPtr p3
, void* vpPolyArgs
)
1511 PolyArgs
& rA
= *static_cast<PolyArgs
*>(vpPolyArgs
);
1512 rA
.AddPoint( p1
->x
, p1
->y
, POLY_CONTROL
);
1513 rA
.AddPoint( p2
->x
, p2
->y
, POLY_CONTROL
);
1514 rA
.AddPoint( p3
->x
, p3
->y
, POLY_NORMAL
);
1520 bool ServerFont::GetGlyphOutline( sal_GlyphId aGlyphId
,
1521 ::basegfx::B2DPolyPolygon
& rB2DPolyPoly
) const
1524 FT_Activate_Size( maSizeFT
);
1526 rB2DPolyPoly
.clear();
1529 SplitGlyphFlags( *this, aGlyphId
, nGlyphFlags
);
1531 FT_Int nLoadFlags
= FT_LOAD_DEFAULT
| FT_LOAD_IGNORE_TRANSFORM
;
1533 #ifdef FT_LOAD_TARGET_LIGHT
1534 // enable "light hinting" if available
1535 nLoadFlags
|= FT_LOAD_TARGET_LIGHT
;
1538 FT_Error rc
= FT_Load_Glyph( maFaceFT
, aGlyphId
, nLoadFlags
);
1539 if( rc
!= FT_Err_Ok
)
1543 FT_GlyphSlot_Embolden(maFaceFT
->glyph
);
1546 rc
= FT_Get_Glyph( maFaceFT
->glyph
, &pGlyphFT
);
1547 if( rc
!= FT_Err_Ok
)
1550 if( pGlyphFT
->format
!= FT_GLYPH_FORMAT_OUTLINE
)
1552 FT_Done_Glyph( pGlyphFT
);
1559 aMatrix
.xx
= aMatrix
.yy
= 0x10000L
;
1560 aMatrix
.xy
= 0x6000L
, aMatrix
.yx
= 0;
1561 FT_Glyph_Transform( pGlyphFT
, &aMatrix
, NULL
);
1564 FT_Outline
& rOutline
= reinterpret_cast<FT_OutlineGlyphRec
*>(pGlyphFT
)->outline
;
1565 if( !rOutline
.n_points
) // blank glyphs are ok
1567 FT_Done_Glyph( pGlyphFT
);
1571 long nMaxPoints
= 1 + rOutline
.n_points
* 3;
1572 tools::PolyPolygon aToolPolyPolygon
;
1573 PolyArgs
aPolyArg( aToolPolyPolygon
, nMaxPoints
);
1575 /*int nAngle =*/ ApplyGlyphTransform( nGlyphFlags
, pGlyphFT
, false );
1577 FT_Outline_Funcs aFuncs
;
1578 aFuncs
.move_to
= &FT_move_to
;
1579 aFuncs
.line_to
= &FT_line_to
;
1580 aFuncs
.conic_to
= &FT_conic_to
;
1581 aFuncs
.cubic_to
= &FT_cubic_to
;
1584 rc
= FT_Outline_Decompose( &rOutline
, &aFuncs
, (void*)&aPolyArg
);
1585 aPolyArg
.ClosePolygon(); // close last polygon
1586 FT_Done_Glyph( pGlyphFT
);
1588 // convert to basegfx polypolygon
1589 // TODO: get rid of the intermediate tools polypolygon
1590 rB2DPolyPoly
= aToolPolyPolygon
.getB2DPolyPolygon();
1591 rB2DPolyPoly
.transform(basegfx::tools::createScaleB2DHomMatrix( +1.0/(1<<6), -1.0/(1<<6) ));
1596 bool ServerFont::ApplyGSUB( const FontSelectPattern
& rFSD
)
1598 #define MKTAG(s) ((((((s[0]<<8)+s[1])<<8)+s[2])<<8)+s[3])
1600 typedef std::vector
<sal_uLong
> ReqFeatureTagList
;
1601 ReqFeatureTagList aReqFeatureTagList
;
1602 if( rFSD
.mbVertical
)
1603 aReqFeatureTagList
.push_back( MKTAG("vert") );
1604 // TODO: request more features depending on script and language system
1606 if( aReqFeatureTagList
.empty()) // nothing to do
1609 // load GSUB table into memory
1610 sal_uLong nLength
= 0;
1611 const FT_Byte
* const pGsubBase
= mpFontInfo
->GetTable( "GSUB", &nLength
);
1615 // parse GSUB header
1616 const FT_Byte
* pGsubHeader
= pGsubBase
;
1617 const sal_uInt16 nOfsScriptList
= GetUShort( pGsubHeader
+4 );
1618 const sal_uInt16 nOfsFeatureTable
= GetUShort( pGsubHeader
+6 );
1619 const sal_uInt16 nOfsLookupList
= GetUShort( pGsubHeader
+8 );
1622 typedef std::vector
<sal_uInt16
> UshortList
;
1623 UshortList aFeatureIndexList
;
1625 // parse Script Table
1626 const FT_Byte
* pScriptHeader
= pGsubBase
+ nOfsScriptList
;
1627 const sal_uInt16 nCntScript
= GetUShort( pScriptHeader
+0 );
1629 for( sal_uInt16 nScriptIndex
= 0; nScriptIndex
< nCntScript
; ++nScriptIndex
)
1631 const sal_uInt16 nOfsScriptTable
= GetUShort( pScriptHeader
+4 );
1634 const FT_Byte
* pScriptTable
= pGsubBase
+ nOfsScriptList
+ nOfsScriptTable
;
1635 const sal_uInt16 nDefaultLangsysOfs
= GetUShort( pScriptTable
+0 );
1636 const sal_uInt16 nCntLangSystem
= GetUShort( pScriptTable
+2 );
1638 sal_uInt16 nLangsysOffset
= 0;
1640 if (nCntLangSystem
!= 0)
1642 nLangsysOffset
= GetUShort( pScriptTable
+4 );
1645 if (nDefaultLangsysOfs
!= 0 && nDefaultLangsysOfs
!= nLangsysOffset
)
1647 const FT_Byte
* pLangSys
= pGsubBase
+ nOfsScriptList
+ nOfsScriptTable
+ nDefaultLangsysOfs
;
1648 const sal_uInt16 nReqFeatureIdx
= GetUShort( pLangSys
+2 );
1649 const sal_uInt16 nCntFeature
= GetUShort( pLangSys
+4 );
1651 aFeatureIndexList
.push_back( nReqFeatureIdx
);
1652 for( sal_uInt16 i
= 0; i
< nCntFeature
; ++i
)
1654 const sal_uInt16 nFeatureIndex
= GetUShort( pLangSys
);
1656 aFeatureIndexList
.push_back( nFeatureIndex
);
1660 if( nLangsysOffset
!= 0 )
1662 const FT_Byte
* pLangSys
= pGsubBase
+ nOfsScriptList
+ nOfsScriptTable
+ nLangsysOffset
;
1663 const sal_uInt16 nReqFeatureIdx
= GetUShort( pLangSys
+2 );
1664 const sal_uInt16 nCntFeature
= GetUShort( pLangSys
+4 );
1666 aFeatureIndexList
.push_back( nReqFeatureIdx
);
1667 for( sal_uInt16 i
= 0; i
< nCntFeature
; ++i
)
1669 const sal_uInt16 nFeatureIndex
= GetUShort( pLangSys
);
1671 aFeatureIndexList
.push_back( nFeatureIndex
);
1676 if( aFeatureIndexList
.empty() )
1679 UshortList aLookupIndexList
;
1680 UshortList aLookupOffsetList
;
1682 // parse Feature Table
1683 const FT_Byte
* pFeatureHeader
= pGsubBase
+ nOfsFeatureTable
;
1684 const sal_uInt16 nCntFeature
= GetUShort( pFeatureHeader
);
1685 pFeatureHeader
+= 2;
1686 for( sal_uInt16 nFeatureIndex
= 0; nFeatureIndex
< nCntFeature
; ++nFeatureIndex
)
1688 const sal_uLong nTag
= GetUInt( pFeatureHeader
+0 ); // e.g. locl/vert/trad/smpl/liga/fina/...
1689 const sal_uInt16 nOffset
= GetUShort( pFeatureHeader
+4 );
1690 pFeatureHeader
+= 6;
1692 // short circuit some feature lookups
1693 if( aFeatureIndexList
[0] != nFeatureIndex
) // required feature?
1695 const int nRequested
= std::count( aFeatureIndexList
.begin(), aFeatureIndexList
.end(), nFeatureIndex
);
1696 if( !nRequested
) // ignore features that are not requested
1698 const int nAvailable
= std::count( aReqFeatureTagList
.begin(), aReqFeatureTagList
.end(), nTag
);
1699 if( !nAvailable
) // some fonts don't provide features they request!
1703 const FT_Byte
* pFeatureTable
= pGsubBase
+ nOfsFeatureTable
+ nOffset
;
1704 const sal_uInt16 nCntLookups
= GetUShort( pFeatureTable
+0 );
1706 for( sal_uInt16 i
= 0; i
< nCntLookups
; ++i
)
1708 const sal_uInt16 nLookupIndex
= GetUShort( pFeatureTable
);
1710 aLookupIndexList
.push_back( nLookupIndex
);
1712 if( nCntLookups
== 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
1713 aLookupIndexList
.push_back( 0 );
1716 // parse Lookup List
1717 const FT_Byte
* pLookupHeader
= pGsubBase
+ nOfsLookupList
;
1718 const sal_uInt16 nCntLookupTable
= GetUShort( pLookupHeader
);
1720 for( sal_uInt16 nLookupIdx
= 0; nLookupIdx
< nCntLookupTable
; ++nLookupIdx
)
1722 const sal_uInt16 nOffset
= GetUShort( pLookupHeader
);
1724 if( std::count( aLookupIndexList
.begin(), aLookupIndexList
.end(), nLookupIdx
) )
1725 aLookupOffsetList
.push_back( nOffset
);
1728 UshortList::const_iterator lookup_it
= aLookupOffsetList
.begin();
1729 for(; lookup_it
!= aLookupOffsetList
.end(); ++lookup_it
)
1731 const sal_uInt16 nOfsLookupTable
= *lookup_it
;
1732 const FT_Byte
* pLookupTable
= pGsubBase
+ nOfsLookupList
+ nOfsLookupTable
;
1733 const sal_uInt16 eLookupType
= GetUShort( pLookupTable
+0 );
1734 const sal_uInt16 nCntLookupSubtable
= GetUShort( pLookupTable
+4 );
1737 // TODO: switch( eLookupType )
1738 if( eLookupType
!= 1 ) // TODO: once we go beyond SingleSubst
1741 for( sal_uInt16 nSubTableIdx
= 0; nSubTableIdx
< nCntLookupSubtable
; ++nSubTableIdx
)
1743 const sal_uInt16 nOfsSubLookupTable
= GetUShort( pLookupTable
);
1745 const FT_Byte
* pSubLookup
= pGsubBase
+ nOfsLookupList
+ nOfsLookupTable
+ nOfsSubLookupTable
;
1747 const sal_uInt16 nFmtSubstitution
= GetUShort( pSubLookup
+0 );
1748 const sal_uInt16 nOfsCoverage
= GetUShort( pSubLookup
+2 );
1751 typedef std::pair
<sal_uInt16
,sal_uInt16
> GlyphSubst
;
1752 typedef std::vector
<GlyphSubst
> SubstVector
;
1753 SubstVector aSubstVector
;
1755 const FT_Byte
* pCoverage
= pGsubBase
+ nOfsLookupList
+ nOfsLookupTable
+ nOfsSubLookupTable
+ nOfsCoverage
;
1756 const sal_uInt16 nFmtCoverage
= GetUShort( pCoverage
+0 );
1758 switch( nFmtCoverage
)
1760 case 1: // Coverage Format 1
1762 const sal_uInt16 nCntGlyph
= GetUShort( pCoverage
);
1764 aSubstVector
.reserve( nCntGlyph
);
1765 for( sal_uInt16 i
= 0; i
< nCntGlyph
; ++i
)
1767 const sal_uInt16 nGlyphId
= GetUShort( pCoverage
);
1769 aSubstVector
.push_back( GlyphSubst( nGlyphId
, 0 ) );
1774 case 2: // Coverage Format 2
1776 const sal_uInt16 nCntRange
= GetUShort( pCoverage
);
1778 for( int i
= nCntRange
; --i
>= 0; )
1780 const sal_uInt32 nGlyph0
= GetUShort( pCoverage
+0 );
1781 const sal_uInt32 nGlyph1
= GetUShort( pCoverage
+2 );
1782 const sal_uInt16 nCovIdx
= GetUShort( pCoverage
+4 );
1784 for( sal_uInt32 j
= nGlyph0
; j
<= nGlyph1
; ++j
)
1785 aSubstVector
.push_back( GlyphSubst( static_cast<sal_uInt16
>(j
+ nCovIdx
), 0 ) );
1791 SubstVector::iterator
it( aSubstVector
.begin() );
1793 switch( nFmtSubstitution
)
1795 case 1: // Single Substitution Format 1
1797 const sal_uInt16 nDeltaGlyphId
= GetUShort( pSubLookup
);
1798 for(; it
!= aSubstVector
.end(); ++it
)
1799 (*it
).second
= (*it
).first
+ nDeltaGlyphId
;
1803 case 2: // Single Substitution Format 2
1805 const sal_uInt16 nCntGlyph
= GetUShort( pSubLookup
);
1807 for( int i
= nCntGlyph
; (it
!= aSubstVector
.end()) && (--i
>=0); ++it
)
1809 const sal_uInt16 nGlyphId
= GetUShort( pSubLookup
);
1811 (*it
).second
= nGlyphId
;
1817 DBG_ASSERT( (it
== aSubstVector
.end()), "lookup<->coverage table mismatch" );
1818 // now apply the glyph substitutions that have been collected in this subtable
1819 for( it
= aSubstVector
.begin(); it
!= aSubstVector
.end(); ++it
)
1820 maGlyphSubstitution
[ (*it
).first
] = (*it
).second
;
1827 const unsigned char* ServerFont::GetTable(const char* pName
, sal_uLong
* pLength
)
1829 return mpFontInfo
->GetTable( pName
, pLength
);
1833 GraphiteFaceWrapper
* ServerFont::GetGraphiteFace() const
1835 return mpFontInfo
->GetGraphiteFace();
1839 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */