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