xref: /aoo41x/main/vcl/source/glyphs/gcach_ftyp.cxx (revision 1759aa31)
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;
92cdf0e10cSrcweir inline sal_uInt16 NEXT_U16( CPU8& p ) { p+=2; return (p[-2]<<8)|p[-1]; }
93cdf0e10cSrcweir inline sal_Int16  NEXT_S16( CPU8& p ) { return (sal_Int16)NEXT_U16(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 
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 
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 
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 
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 
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 
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 
316cdf0e10cSrcweir FtFontInfo::~FtFontInfo()
317cdf0e10cSrcweir {
318cdf0e10cSrcweir     if( mpFontCharMap )
319cdf0e10cSrcweir         mpFontCharMap->DeReference();
320cdf0e10cSrcweir     delete mpExtraKernInfo;
321cdf0e10cSrcweir     delete mpChar2Glyph;
322cdf0e10cSrcweir     delete mpGlyph2Char;
323cdf0e10cSrcweir }
324cdf0e10cSrcweir 
325cdf0e10cSrcweir 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 
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 
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 
366cdf0e10cSrcweir 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 
378cdf0e10cSrcweir int FtFontInfo::GetExtraKernPairs( ImplKernPairData** ppKernPairs ) const
379cdf0e10cSrcweir {
380cdf0e10cSrcweir     if( !mpExtraKernInfo )
381cdf0e10cSrcweir         return 0;
382cdf0e10cSrcweir     return mpExtraKernInfo->GetUnscaledKernPairs( ppKernPairs );
383cdf0e10cSrcweir }
384cdf0e10cSrcweir 
385cdf0e10cSrcweir // -----------------------------------------------------------------------
386cdf0e10cSrcweir 
387cdf0e10cSrcweir 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 
400cdf0e10cSrcweir static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
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 
406cdf0e10cSrcweir 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 
443cdf0e10cSrcweir void FtFontInfo::AnnounceFont( ImplDevFontList* pFontList )
444cdf0e10cSrcweir {
445cdf0e10cSrcweir     ImplFTSFontData* pFD = new ImplFTSFontData( this, maDevFontAttributes );
446cdf0e10cSrcweir     pFontList->Add( pFD );
447cdf0e10cSrcweir }
448cdf0e10cSrcweir 
449cdf0e10cSrcweir // =======================================================================
450cdf0e10cSrcweir 
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 
510cdf0e10cSrcweir void* FreetypeServerFont::GetFtFace() const
511cdf0e10cSrcweir {
512cdf0e10cSrcweir     if( maSizeFT )
513cdf0e10cSrcweir         pFTActivateSize( maSizeFT );
514cdf0e10cSrcweir 
515cdf0e10cSrcweir     return maFaceFT;
516cdf0e10cSrcweir }
517cdf0e10cSrcweir 
518cdf0e10cSrcweir // -----------------------------------------------------------------------
519cdf0e10cSrcweir 
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 
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 
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 
646cdf0e10cSrcweir 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 
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 
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 
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 
699cdf0e10cSrcweir ImplFontEntry* ImplFTSFontData::CreateFontInstance( ImplFontSelectData& rFSD ) const
700cdf0e10cSrcweir {
701cdf0e10cSrcweir     ImplServerFontEntry* pEntry = new ImplServerFontEntry( rFSD );
702cdf0e10cSrcweir     return pEntry;
703cdf0e10cSrcweir }
704cdf0e10cSrcweir 
705cdf0e10cSrcweir // =======================================================================
706cdf0e10cSrcweir // FreetypeServerFont
707cdf0e10cSrcweir // =======================================================================
708cdf0e10cSrcweir 
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
724cdf0e10cSrcweir     fprintf( stderr, "FTSF::FTSF(\"%s\", h=%d, w=%d, sy=%d) => %d\n",
725cdf0e10cSrcweir         pFI->GetFontFileName()->getStr(), rFSD.mnHeight, rFSD.mnWidth, 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 
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 
919cdf0e10cSrcweir bool FreetypeServerFont::TestFont() const
920cdf0e10cSrcweir {
921cdf0e10cSrcweir     return mbFaceOk;
922cdf0e10cSrcweir }
923cdf0e10cSrcweir 
924cdf0e10cSrcweir // -----------------------------------------------------------------------
925cdf0e10cSrcweir 
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 
942cdf0e10cSrcweir int FreetypeServerFont::GetEmUnits() const
943cdf0e10cSrcweir {
944cdf0e10cSrcweir     return maFaceFT->units_per_EM;
945cdf0e10cSrcweir }
946cdf0e10cSrcweir 
947cdf0e10cSrcweir // -----------------------------------------------------------------------
948cdf0e10cSrcweir 
949cdf0e10cSrcweir 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 
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 
1094cdf0e10cSrcweir 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 
1177248a599fSHerbert 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 
1240248a599fSHerbert 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 
1288248a599fSHerbert 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 
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 
1316248a599fSHerbert 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 );
1364*1759aa31SMatthias Seidel     if( rc != FT_Err_Ok )
1365*1759aa31SMatthias Seidel     {
1366*1759aa31SMatthias Seidel         // we get here e.g. when a PS font lacks the default glyph
1367*1759aa31SMatthias Seidel         rGD.SetCharWidth( 0 );
1368*1759aa31SMatthias Seidel         rGD.SetDelta( 0, 0 );
1369*1759aa31SMatthias Seidel         rGD.SetOffset( 0, 0 );
1370*1759aa31SMatthias Seidel         rGD.SetSize( Size( 0, 0 ) );
1371*1759aa31SMatthias Seidel         return;
1372*1759aa31SMatthias 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 
1394cdf0e10cSrcweir 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 
1405248a599fSHerbert 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 
1579248a599fSHerbert 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 
1759cdf0e10cSrcweir const ImplFontCharMap* FreetypeServerFont::GetImplFontCharMap( void ) const
1760cdf0e10cSrcweir {
1761cdf0e10cSrcweir 	const ImplFontCharMap* pIFCMap = mpFontInfo->GetImplFontCharMap();
1762cdf0e10cSrcweir 	return pIFCMap;
1763cdf0e10cSrcweir }
1764cdf0e10cSrcweir 
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()
1783cdf0e10cSrcweir 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 
1836cdf0e10cSrcweir 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 
1866cdf0e10cSrcweir 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 
2130cdf0e10cSrcweir     long        GetPosX() const { return maPosition.x;}
2131cdf0e10cSrcweir     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 
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 
2163cdf0e10cSrcweir PolyArgs::~PolyArgs()
2164cdf0e10cSrcweir {
2165cdf0e10cSrcweir     delete[] mpFlagAry;
2166cdf0e10cSrcweir     delete[] mpPointAry;
2167cdf0e10cSrcweir }
2168cdf0e10cSrcweir 
2169cdf0e10cSrcweir // -----------------------------------------------------------------------
2170cdf0e10cSrcweir 
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 
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
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 
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 
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 
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 
2285248a599fSHerbert 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 
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;
2481cdf0e10cSrcweir         const sal_uInt16 nCntLookups = GetUShort( pFeatureTable+0 );
2482cdf0e10cSrcweir         pFeatureTable += 2;
2483cdf0e10cSrcweir         for( sal_uInt16 i = 0; i < nCntLookups; ++i )
2484cdf0e10cSrcweir         {
2485cdf0e10cSrcweir             const sal_uInt16 nLookupIndex = GetUShort( pFeatureTable );
2486cdf0e10cSrcweir             pFeatureTable += 2;
2487cdf0e10cSrcweir             aLookupIndexList.push_back( nLookupIndex );
2488cdf0e10cSrcweir         }
2489cdf0e10cSrcweir         if( nCntLookups == 0 ) //### hack needed by Mincho/Gothic/Mingliu/Simsun/...
2490cdf0e10cSrcweir             aLookupIndexList.push_back( 0 );
2491cdf0e10cSrcweir     }
2492cdf0e10cSrcweir 
2493cdf0e10cSrcweir     // parse Lookup List
2494cdf0e10cSrcweir     const FT_Byte* pLookupHeader = pGsubBase + nOfsLookupList;
2495cdf0e10cSrcweir     const sal_uInt16 nCntLookupTable = GetUShort( pLookupHeader );
2496cdf0e10cSrcweir     pLookupHeader += 2;
2497cdf0e10cSrcweir     for( sal_uInt16 nLookupIdx = 0; nLookupIdx < nCntLookupTable; ++nLookupIdx )
2498cdf0e10cSrcweir     {
2499cdf0e10cSrcweir         const sal_uInt16 nOffset = GetUShort( pLookupHeader );
2500cdf0e10cSrcweir         pLookupHeader += 2;
2501cdf0e10cSrcweir         if( std::count( aLookupIndexList.begin(), aLookupIndexList.end(), nLookupIdx ) )
2502cdf0e10cSrcweir             aLookupOffsetList.push_back( nOffset );
2503cdf0e10cSrcweir     }
2504cdf0e10cSrcweir 
2505cdf0e10cSrcweir     UshortList::const_iterator lookup_it = aLookupOffsetList.begin();
2506cdf0e10cSrcweir     for(; lookup_it != aLookupOffsetList.end(); ++lookup_it )
2507cdf0e10cSrcweir     {
2508cdf0e10cSrcweir         const sal_uInt16 nOfsLookupTable = *lookup_it;
2509cdf0e10cSrcweir         const FT_Byte* pLookupTable = pGsubBase + nOfsLookupList + nOfsLookupTable;
2510cdf0e10cSrcweir         const sal_uInt16 eLookupType        = GetUShort( pLookupTable+0 );
2511cdf0e10cSrcweir         const sal_uInt16 nCntLookupSubtable = GetUShort( pLookupTable+4 );
2512cdf0e10cSrcweir         pLookupTable += 6;
2513cdf0e10cSrcweir 
2514cdf0e10cSrcweir         // TODO: switch( eLookupType )
2515cdf0e10cSrcweir         if( eLookupType != 1 )  // TODO: once we go beyond SingleSubst
2516cdf0e10cSrcweir             continue;
2517cdf0e10cSrcweir 
2518cdf0e10cSrcweir         for( sal_uInt16 nSubTableIdx = 0; nSubTableIdx < nCntLookupSubtable; ++nSubTableIdx )
2519cdf0e10cSrcweir         {
2520cdf0e10cSrcweir             const sal_uInt16 nOfsSubLookupTable = GetUShort( pLookupTable );
2521cdf0e10cSrcweir             pLookupTable += 2;
2522cdf0e10cSrcweir             const FT_Byte* pSubLookup = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable;
2523cdf0e10cSrcweir 
2524cdf0e10cSrcweir             const sal_uInt16 nFmtSubstitution   = GetUShort( pSubLookup+0 );
2525cdf0e10cSrcweir             const sal_uInt16 nOfsCoverage       = GetUShort( pSubLookup+2 );
2526cdf0e10cSrcweir             pSubLookup += 4;
2527cdf0e10cSrcweir 
2528cdf0e10cSrcweir             typedef std::pair<sal_uInt16,sal_uInt16> GlyphSubst;
2529cdf0e10cSrcweir             typedef std::vector<GlyphSubst> SubstVector;
2530cdf0e10cSrcweir             SubstVector aSubstVector;
2531cdf0e10cSrcweir 
2532cdf0e10cSrcweir             const FT_Byte* pCoverage    = pGsubBase + nOfsLookupList + nOfsLookupTable + nOfsSubLookupTable + nOfsCoverage;
2533cdf0e10cSrcweir             const sal_uInt16 nFmtCoverage   = GetUShort( pCoverage+0 );
2534cdf0e10cSrcweir             pCoverage += 2;
2535cdf0e10cSrcweir             switch( nFmtCoverage )
2536cdf0e10cSrcweir             {
2537cdf0e10cSrcweir                 case 1:         // Coverage Format 1
2538cdf0e10cSrcweir                     {
2539cdf0e10cSrcweir                         const sal_uInt16 nCntGlyph = GetUShort( pCoverage );
2540cdf0e10cSrcweir                         pCoverage += 2;
2541cdf0e10cSrcweir                         aSubstVector.reserve( nCntGlyph );
2542cdf0e10cSrcweir                         for( sal_uInt16 i = 0; i < nCntGlyph; ++i )
2543cdf0e10cSrcweir                         {
2544cdf0e10cSrcweir                             const sal_uInt16 nGlyphId = GetUShort( pCoverage );
2545cdf0e10cSrcweir                             pCoverage += 2;
2546cdf0e10cSrcweir                             aSubstVector.push_back( GlyphSubst( nGlyphId, 0 ) );
2547cdf0e10cSrcweir                         }
2548cdf0e10cSrcweir                     }
2549cdf0e10cSrcweir                     break;
2550cdf0e10cSrcweir 
2551cdf0e10cSrcweir                 case 2:         // Coverage Format 2
2552cdf0e10cSrcweir                     {
2553cdf0e10cSrcweir                         const sal_uInt16 nCntRange = GetUShort( pCoverage );
2554cdf0e10cSrcweir                         pCoverage += 2;
2555cdf0e10cSrcweir                         for( int i = nCntRange; --i >= 0; )
2556cdf0e10cSrcweir                         {
2557cdf0e10cSrcweir                             const sal_uInt32 nGlyph0 = GetUShort( pCoverage+0 );
2558cdf0e10cSrcweir                             const sal_uInt32 nGlyph1 = GetUShort( pCoverage+2 );
2559cdf0e10cSrcweir                             const sal_uInt16 nCovIdx = GetUShort( pCoverage+4 );
2560cdf0e10cSrcweir                             pCoverage += 6;
2561cdf0e10cSrcweir                             for( sal_uInt32 j = nGlyph0; j <= nGlyph1; ++j )
2562cdf0e10cSrcweir                                 aSubstVector.push_back( GlyphSubst( static_cast<sal_uInt16>(j + nCovIdx), 0 ) );
2563cdf0e10cSrcweir                         }
2564cdf0e10cSrcweir                     }
2565cdf0e10cSrcweir                     break;
2566cdf0e10cSrcweir             }
2567cdf0e10cSrcweir 
2568cdf0e10cSrcweir             SubstVector::iterator it( aSubstVector.begin() );
2569cdf0e10cSrcweir 
2570cdf0e10cSrcweir             switch( nFmtSubstitution )
2571cdf0e10cSrcweir             {
2572cdf0e10cSrcweir                 case 1:     // Single Substitution Format 1
2573cdf0e10cSrcweir                     {
2574cdf0e10cSrcweir                         const sal_uInt16 nDeltaGlyphId = GetUShort( pSubLookup );
2575cdf0e10cSrcweir                         pSubLookup += 2;
2576cdf0e10cSrcweir                         for(; it != aSubstVector.end(); ++it )
2577cdf0e10cSrcweir                             (*it).second = (*it).first + nDeltaGlyphId;
2578cdf0e10cSrcweir                     }
2579cdf0e10cSrcweir                     break;
2580cdf0e10cSrcweir 
2581cdf0e10cSrcweir                 case 2:     // Single Substitution Format 2
2582cdf0e10cSrcweir                     {
2583cdf0e10cSrcweir                         const sal_uInt16 nCntGlyph = GetUShort( pSubLookup );
2584cdf0e10cSrcweir                         pSubLookup += 2;
2585cdf0e10cSrcweir                         for( int i = nCntGlyph; (it != aSubstVector.end()) && (--i>=0); ++it )
2586cdf0e10cSrcweir                         {
2587cdf0e10cSrcweir                             const sal_uInt16 nGlyphId = GetUShort( pSubLookup );
2588cdf0e10cSrcweir                             pSubLookup += 2;
2589cdf0e10cSrcweir                             (*it).second = nGlyphId;
2590cdf0e10cSrcweir                         }
2591cdf0e10cSrcweir                     }
2592cdf0e10cSrcweir                     break;
2593cdf0e10cSrcweir             }
2594cdf0e10cSrcweir 
2595cdf0e10cSrcweir             DBG_ASSERT( (it == aSubstVector.end()), "lookup<->coverage table mismatch" );
2596cdf0e10cSrcweir             // now apply the glyph substitutions that have been collected in this subtable
2597cdf0e10cSrcweir             for( it = aSubstVector.begin(); it != aSubstVector.end(); ++it )
2598cdf0e10cSrcweir                 maGlyphSubstitution[ (*it).first ] =  (*it).second;
2599cdf0e10cSrcweir         }
2600cdf0e10cSrcweir     }
2601cdf0e10cSrcweir 
2602cdf0e10cSrcweir     return true;
2603cdf0e10cSrcweir }
2604cdf0e10cSrcweir 
2605cdf0e10cSrcweir // =======================================================================
2606cdf0e10cSrcweir 
2607