xref: /AOO41X/main/vcl/win/source/gdi/salgdi3.cxx (revision 707fc0d4d52eb4f69d89a98ffec6918ca5de6326)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include <string.h>
28 #include <malloc.h>
29 
30 #include "rtl/logfile.hxx"
31 #include "rtl/tencinfo.h"
32 #include "rtl/textcvt.h"
33 #include "rtl/bootstrap.hxx"
34 
35 #include "i18npool/mslangid.hxx"
36 
37 #include "osl/module.h"
38 #include "osl/file.hxx"
39 #include "osl/thread.hxx"
40 #include "osl/process.h"
41 
42 #include "basegfx/polygon/b2dpolygon.hxx"
43 #include "basegfx/polygon/b2dpolypolygon.hxx"
44 #include "basegfx/matrix/b2dhommatrix.hxx"
45 #include "basegfx/matrix/b2dhommatrixtools.hxx"
46 
47 #include "unotools/fontcfg.hxx" // for IMPL_FONT_ATTR_SYMBOL
48 
49 #include "vcl/font.hxx"
50 #include "vcl/svapp.hxx"
51 
52 #include "tools/poly.hxx"
53 #include "tools/debug.hxx"
54 #include "tools/stream.hxx"
55 
56 #include <tools/prewin.h>
57 #include <windows.h>
58 #include <tools/postwin.h>
59 
60 #include <vcl/sysdata.hxx>
61 
62 #include "win/wincomp.hxx"
63 #include "win/saldata.hxx"
64 #include "win/salgdi.h"
65 
66 #include "outfont.hxx"
67 #include "fontsubset.hxx"
68 #include "sallayout.hxx"
69 #include "outdev.h"         // for ImplGlyphFallbackFontSubstitution
70 #include "sft.hxx"
71 
72 #ifdef GCP_KERN_HACK
73 #include <algorithm>
74 #endif
75 
76 #ifdef ENABLE_GRAPHITE
77 #include <graphite/GrClient.h>
78 #include <graphite/WinFont.h>
79 #endif
80 
81 #include <vector>
82 #include <set>
83 #include <map>
84 
85 using namespace vcl;
86 
87 static const int MAXFONTHEIGHT = 2048;
88 
89 // -----------
90 // - Inlines -
91 // -----------
92 
93 inline FIXED FixedFromDouble( double d )
94 {
95     const long l = (long) ( d * 65536. );
96     return *(FIXED*) &l;
97 }
98 
99 // -----------------------------------------------------------------------
100 
101 inline int IntTimes256FromFixed(FIXED f)
102 {
103     int nFixedTimes256 = (f.value << 8) + ((f.fract+0x80) >> 8);
104     return nFixedTimes256;
105 }
106 
107 // =======================================================================
108 
109 // these variables can be static because they store system wide settings
110 static bool bImplSalCourierScalable = false;
111 static bool bImplSalCourierNew = false;
112 
113 
114 // =======================================================================
115 
116 // -----------------------------------------------------------------------
117 
118 // TODO: also support temporary TTC font files
119 typedef std::map< String, ImplDevFontAttributes > FontAttrMap;
120 
121 class ImplFontAttrCache
122 {
123 private:
124     FontAttrMap     aFontAttributes;
125     rtl::OUString   aCacheFileName;
126     String          aBaseURL;
127     sal_Bool            bModified;
128 
129 protected:
130     String  OptimizeURL( const String& rURL ) const;
131 
132     enum{ MAGIC = 0x12349876 }; // change if fontattrcache format changes
133 
134 public:
135             ImplFontAttrCache( const String& rCacheFileName, const String& rBaseURL );
136             ~ImplFontAttrCache();
137 
138     ImplDevFontAttributes  GetFontAttr( const String& rFontFileName ) const;
139     void                   AddFontAttr( const String& rFontFileName, const ImplDevFontAttributes& );
140 };
141 
142 ImplFontAttrCache::ImplFontAttrCache( const String& rFileNameURL, const String& rBaseURL ) : aBaseURL( rBaseURL )
143 {
144     bModified = FALSE;
145     aBaseURL.ToLowerAscii();    // Windows only, no problem...
146 
147     // open the cache file
148     osl::FileBase::getSystemPathFromFileURL( rFileNameURL, aCacheFileName );
149     SvFileStream aCacheFile( aCacheFileName, STREAM_READ );
150     if( !aCacheFile.IsOpen() )
151         return;
152 
153     // check the cache version
154     sal_uInt32 nCacheMagic;
155     aCacheFile >> nCacheMagic;
156     if( nCacheMagic != ImplFontAttrCache::MAGIC )
157         return;  // ignore cache and rewrite if no match
158 
159     // read the cache entries from the file
160     String aFontFileURL, aFontName;
161     ImplDevFontAttributes aDFA;
162     for(;;)
163     {
164         aCacheFile.ReadByteString( aFontFileURL, RTL_TEXTENCODING_UTF8 );
165         if( !aFontFileURL.Len() )
166             break;
167         aCacheFile.ReadByteString( aDFA.maName, RTL_TEXTENCODING_UTF8 );
168 
169         short n;
170         aCacheFile >> n; aDFA.meWeight     = static_cast<FontWeight>(n);
171         aCacheFile >> n; aDFA.meItalic     = static_cast<FontItalic>(n);
172         aCacheFile >> n; aDFA.mePitch      = static_cast<FontPitch>(n);
173         aCacheFile >> n; aDFA.meWidthType  = static_cast<FontWidth>(n);
174         aCacheFile >> n; aDFA.meFamily     = static_cast<FontFamily>(n);
175         aCacheFile >> n; aDFA.mbSymbolFlag = (n != 0);
176 
177         aCacheFile.ReadByteStringLine( aDFA.maStyleName, RTL_TEXTENCODING_UTF8 );
178 
179         aFontAttributes[ aFontFileURL ] = aDFA;
180     }
181 }
182 
183 ImplFontAttrCache::~ImplFontAttrCache()
184 {
185     if ( bModified )
186     {
187         SvFileStream aCacheFile( aCacheFileName, STREAM_WRITE|STREAM_TRUNC );
188         if ( aCacheFile.IsWritable() )
189         {
190             sal_uInt32 nCacheMagic = ImplFontAttrCache::MAGIC;
191             aCacheFile << nCacheMagic;
192 
193             // write the cache entries to the file
194             FontAttrMap::const_iterator aIter = aFontAttributes.begin();
195             while ( aIter != aFontAttributes.end() )
196             {
197                 const String rFontFileURL( (*aIter).first );
198                 const ImplDevFontAttributes& rDFA( (*aIter).second );
199                 aCacheFile.WriteByteString( rFontFileURL, RTL_TEXTENCODING_UTF8 );
200                 aCacheFile.WriteByteString( rDFA.maName, RTL_TEXTENCODING_UTF8 );
201 
202                 aCacheFile << static_cast<short>(rDFA.meWeight);
203                 aCacheFile << static_cast<short>(rDFA.meItalic);
204                 aCacheFile << static_cast<short>(rDFA.mePitch);
205                 aCacheFile << static_cast<short>(rDFA.meWidthType);
206                 aCacheFile << static_cast<short>(rDFA.meFamily);
207                 aCacheFile << static_cast<short>(rDFA.mbSymbolFlag != false);
208 
209                 aCacheFile.WriteByteStringLine( rDFA.maStyleName, RTL_TEXTENCODING_UTF8 );
210 
211                 aIter++;
212             }
213             // EOF Marker
214             String aEmptyStr;
215             aCacheFile.WriteByteString( aEmptyStr, RTL_TEXTENCODING_UTF8 );
216         }
217     }
218 }
219 
220 String ImplFontAttrCache::OptimizeURL( const String& rURL ) const
221 {
222     String aOptimizedFontFileURL( rURL );
223     aOptimizedFontFileURL.ToLowerAscii();   // Windows only, no problem...
224     if ( aOptimizedFontFileURL.CompareTo( aBaseURL, aBaseURL.Len() ) == COMPARE_EQUAL )
225         aOptimizedFontFileURL = aOptimizedFontFileURL.Copy( aBaseURL.Len() );
226     return aOptimizedFontFileURL;
227 }
228 
229 ImplDevFontAttributes ImplFontAttrCache::GetFontAttr( const String& rFontFileName ) const
230 {
231     ImplDevFontAttributes aDFA;
232     FontAttrMap::const_iterator it = aFontAttributes.find( OptimizeURL( rFontFileName ) );
233     if( it != aFontAttributes.end() )
234     {
235         aDFA = it->second;
236     }
237     return aDFA;
238 }
239 
240 void ImplFontAttrCache::AddFontAttr( const String& rFontFileName, const ImplDevFontAttributes& rDFA )
241 {
242     DBG_ASSERT( rFontFileName.Len() && rDFA.maName.Len(), "ImplFontNameCache::AddFontName - invalid data!" );
243     if ( rFontFileName.Len() && rDFA.maName.Len() )
244     {
245         aFontAttributes.insert( FontAttrMap::value_type( OptimizeURL( rFontFileName ), rDFA ) );
246         bModified = TRUE;
247     }
248 }
249 
250 // =======================================================================
251 
252 // raw font data with a scoped lifetime
253 class RawFontData
254 {
255 public:
256     explicit    RawFontData( HDC, DWORD nTableTag=0 );
257                 ~RawFontData() { delete[] mpRawBytes; }
258     const unsigned char*    get() const { return mpRawBytes; }
259     const unsigned char*    steal() { unsigned char* p = mpRawBytes; mpRawBytes = NULL; return p; }
260     const int               size() const { return mnByteCount; }
261 
262 private:
263     unsigned char*  mpRawBytes;
264     int             mnByteCount;
265 };
266 
267 RawFontData::RawFontData( HDC hDC, DWORD nTableTag )
268 :   mpRawBytes( NULL )
269 ,   mnByteCount( 0 )
270 {
271     // get required size in bytes
272     mnByteCount = ::GetFontData( hDC, nTableTag, 0, NULL, 0 );
273     if( mnByteCount == GDI_ERROR )
274         return;
275     else if( !mnByteCount )
276         return;
277 
278     // allocate the array
279     mpRawBytes = new unsigned char[ mnByteCount ];
280 
281     // get raw data in chunks small enough for GetFontData()
282     int nRawDataOfs = 0;
283     DWORD nMaxChunkSize = 0x100000;
284     for(;;)
285     {
286         // calculate remaining raw data to get
287         DWORD nFDGet = mnByteCount - nRawDataOfs;
288         if( nFDGet <= 0 )
289             break;
290         // #i56745# limit GetFontData requests
291         if( nFDGet > nMaxChunkSize )
292             nFDGet = nMaxChunkSize;
293         const DWORD nFDGot = ::GetFontData( hDC, nTableTag, nRawDataOfs,
294             (void*)(mpRawBytes + nRawDataOfs), nFDGet );
295         if( !nFDGot )
296             break;
297         else if( nFDGot != GDI_ERROR )
298             nRawDataOfs += nFDGot;
299         else
300         {
301             // was the chunk too big? reduce it
302             nMaxChunkSize /= 2;
303             if( nMaxChunkSize < 0x10000 )
304                 break;
305         }
306     }
307 
308     // cleanup if the raw data is incomplete
309     if( nRawDataOfs != mnByteCount )
310     {
311         delete[] mpRawBytes;
312         mpRawBytes = NULL;
313     }
314 }
315 
316 // ===========================================================================
317 // platform specific font substitution hooks for glyph fallback enhancement
318 // TODO: move into i18n module (maybe merge with svx/ucsubset.*
319 //       or merge with i18nutil/source/utility/unicode_data.h)
320 struct Unicode2LangType
321 {
322     sal_UCS4 mnMinCode;
323     sal_UCS4 mnMaxCode;
324     LanguageType mnLangID;
325 };
326 
327 // entries marked with default-CJK get replaced with the default-CJK language
328 #define LANGUAGE_DEFAULT_CJK 0xFFF0
329 
330 // map unicode ranges to languages supported by OOo
331 // NOTE: due to the binary search used this list must be sorted by mnMinCode
332 static Unicode2LangType aLangFromCodeChart[]= {
333     {0x0000, 0x007F, LANGUAGE_ENGLISH},             // Basic Latin
334     {0x0080, 0x024F, LANGUAGE_ENGLISH},             // Latin Extended-A and Latin Extended-B
335     {0x0250, 0x02AF, LANGUAGE_SYSTEM},              // IPA Extensions
336     {0x0370, 0x03FF, LANGUAGE_GREEK},               // Greek
337     {0x0590, 0x05FF, LANGUAGE_HEBREW},              // Hebrew
338     {0x0600, 0x06FF, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic
339     {0x0900, 0x097F, LANGUAGE_HINDI},               // Devanagari
340     {0x0980, 0x09FF, LANGUAGE_BENGALI},             // Bengali
341     {0x0A80, 0x0AFF, LANGUAGE_GUJARATI},            // Gujarati
342     {0x0B00, 0x0B7F, LANGUAGE_ORIYA},               // Oriya
343     {0x0B80, 0x0BFF, LANGUAGE_TAMIL},               // Tamil
344     {0x0C00, 0x0C7F, LANGUAGE_TELUGU},              // Telugu
345     {0x0C80, 0x0CFF, LANGUAGE_KANNADA},             // Kannada
346     {0x0D00, 0x0D7F, LANGUAGE_MALAYALAM},           // Malayalam
347     {0x0D80, 0x0D7F, LANGUAGE_SINHALESE_SRI_LANKA}, // Sinhala
348     {0x0E00, 0x0E7F, LANGUAGE_THAI},                // Thai
349     {0x0E80, 0x0EFF, LANGUAGE_LAO},                 // Lao
350     {0x0F00, 0x0FFF, LANGUAGE_TIBETAN},             // Tibetan
351     {0x1000, 0x109F, LANGUAGE_BURMESE},             // Burmese
352     {0x10A0, 0x10FF, LANGUAGE_GEORGIAN},            // Georgian
353     {0x1100, 0x11FF, LANGUAGE_KOREAN},              // Hangul Jamo, Korean-specific
354 //  {0x1200, 0x139F, LANGUAGE_AMHARIC_ETHIOPIA},    // Ethiopic
355 //  {0x1200, 0x139F, LANGUAGE_TIGRIGNA_ETHIOPIA},   // Ethiopic
356     {0x13A0, 0x13FF, LANGUAGE_CHEROKEE_UNITED_STATES}, // Cherokee
357 //  {0x1400, 0x167F, LANGUAGE_CANADIAN_ABORIGINAL}, // Canadian Aboriginial Syllabics
358 //  {0x1680, 0x169F, LANGUAGE_OGHAM},               // Ogham
359 //  {0x16A0, 0x16F0, LANGUAGE_RUNIC},               // Runic
360 //  {0x1700, 0x171F, LANGUAGE_TAGALOG},             // Tagalog
361 //  {0x1720, 0x173F, LANGUAGE_HANUNOO},             // Hanunoo
362 //  {0x1740, 0x175F, LANGUAGE_BUHID},               // Buhid
363 //  {0x1760, 0x177F, LANGUAGE_TAGBANWA},            // Tagbanwa
364     {0x1780, 0x17FF, LANGUAGE_KHMER},               // Khmer
365     {0x18A0, 0x18AF, LANGUAGE_MONGOLIAN},           // Mongolian
366 //  {0x1900, 0x194F, LANGUAGE_LIMBU},               // Limbu
367 //  {0x1950, 0x197F, LANGUAGE_TAILE},               // Tai Le
368 //  {0x1980, 0x19DF, LANGUAGE_TAILUE},              // Tai Lue
369     {0x19E0, 0x19FF, LANGUAGE_KHMER},               // Khmer Symbols
370 //  {0x1A00, 0x1A1F, LANGUAGE_BUGINESE},            // Buginese/Lontara
371 //  {0x1B00, 0x1B7F, LANGUAGE_BALINESE},            // Balinese
372 //  {0x1D00, 0x1DFF, LANGUAGE_NONE},                // Phonetic Symbols
373     {0x1E00, 0x1EFF, LANGUAGE_ENGLISH},             // Latin Extended Additional
374     {0x1F00, 0x1FFF, LANGUAGE_GREEK},               // Greek Extended
375     {0x2C60, 0x2C7F, LANGUAGE_ENGLISH},             // Latin Extended-C
376     {0x2E80, 0x2FFf, LANGUAGE_CHINESE_SIMPLIFIED},  // CJK Radicals Supplement + Kangxi Radical + Ideographic Description Characters
377     {0x3000, 0x303F, LANGUAGE_DEFAULT_CJK},         // CJK Symbols and punctuation
378     {0x3040, 0x30FF, LANGUAGE_JAPANESE},            // Japanese Hiragana + Katakana
379     {0x3100, 0x312F, LANGUAGE_CHINESE_TRADITIONAL}, // Bopomofo
380     {0x3130, 0x318F, LANGUAGE_KOREAN},              // Hangul Compatibility Jamo, Kocrean-specific
381     {0x3190, 0x319F, LANGUAGE_JAPANESE},            // Kanbun
382     {0x31A0, 0x31BF, LANGUAGE_CHINESE_TRADITIONAL}, // Bopomofo Extended
383     {0x31C0, 0x31EF, LANGUAGE_DEFAULT_CJK},         // CJK Ideographs
384     {0x31F0, 0x31FF, LANGUAGE_JAPANESE},            // Japanese Katakana Phonetic Extensions
385     {0x3200, 0x321F, LANGUAGE_KOREAN},              // Parenthesized Hangul
386     {0x3220, 0x325F, LANGUAGE_DEFAULT_CJK},         // Parenthesized Ideographs
387     {0x3260, 0x327F, LANGUAGE_KOREAN},              // Circled Hangul
388     {0x3280, 0x32CF, LANGUAGE_DEFAULT_CJK},         // Circled Ideographs
389     {0x32d0, 0x32FF, LANGUAGE_JAPANESE},            // Japanese Circled Katakana
390     {0x3400, 0x4DBF, LANGUAGE_DEFAULT_CJK},         // CJK Unified Ideographs Extension A
391     {0x4E00, 0x9FCF, LANGUAGE_DEFAULT_CJK},         // Unified CJK Ideographs
392     {0xA720, 0xA7FF, LANGUAGE_ENGLISH},             // Latin Extended-D
393     {0xAC00, 0xD7AF, LANGUAGE_KOREAN},              // Hangul Syllables, Korean-specific
394     {0xF900, 0xFAFF, LANGUAGE_DEFAULT_CJK},         // CJK Compatibility Ideographs
395     {0xFB00, 0xFB4F, LANGUAGE_HEBREW},              // Hebrew Presentation Forms
396     {0xFB50, 0xFDFF, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic Presentation Forms-A
397     {0xFE70, 0xFEFE, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic Presentation Forms-B
398     {0xFF65, 0xFF9F, LANGUAGE_JAPANESE},            // Japanese Halfwidth Katakana variant
399     {0xFFA0, 0xFFDC, LANGUAGE_KOREAN},              // Kocrean halfwidth hangual variant
400     {0x10140, 0x1018F, LANGUAGE_GREEK},             // Ancient Greak numbers
401     {0x1D200, 0x1D24F, LANGUAGE_GREEK},             // Ancient Greek Musical
402     {0x20000, 0x2A6DF, LANGUAGE_DEFAULT_CJK},       // CJK Unified Ideographs Extension B
403     {0x2F800, 0x2FA1F, LANGUAGE_DEFAULT_CJK}        // CJK Compatibility Ideographs Supplement
404 };
405 
406 // get language matching to the missing char
407 LanguageType MapCharToLanguage( sal_UCS4 uChar )
408 {
409     // entries marked with default-CJK get replaced with the prefered CJK language
410     static bool bFirst = true;
411     if( bFirst )
412     {
413         bFirst = false;
414 
415         // use method suggested in #i97086# to determnine the systems default language
416         // TODO: move into i18npool or sal/osl/w32/nlsupport.c
417         LanguageType nDefaultLang = 0;
418         HKEY hKey = NULL;
419         LONG lResult = ::RegOpenKeyExA( HKEY_LOCAL_MACHINE,
420             "SYSTEM\\CurrentControlSet\\Control\\Nls\\Language",
421             0, KEY_QUERY_VALUE, &hKey );
422         char aKeyValBuf[16];
423         DWORD nKeyValSize = sizeof(aKeyValBuf);
424         if( ERROR_SUCCESS == lResult )
425             lResult = RegQueryValueExA( hKey, "Default", NULL, NULL, (LPBYTE)aKeyValBuf, &nKeyValSize );
426         aKeyValBuf[ sizeof(aKeyValBuf)-1 ] = '\0';
427         if( ERROR_SUCCESS == lResult )
428             nDefaultLang = (LanguageType)rtl_str_toInt32( aKeyValBuf, 16 );
429 
430         // TODO: use the default-CJK language selected in
431         //  Tools->Options->LangSettings->Languages when it becomes available here
432         if( !nDefaultLang )
433             nDefaultLang = Application::GetSettings().GetUILanguage();
434 
435         LanguageType nDefaultCJK = LANGUAGE_CHINESE;
436         switch( nDefaultLang )
437         {
438             case LANGUAGE_JAPANESE:
439             case LANGUAGE_KOREAN:
440             case LANGUAGE_KOREAN_JOHAB:
441             case LANGUAGE_CHINESE_SIMPLIFIED:
442             case LANGUAGE_CHINESE_TRADITIONAL:
443             case LANGUAGE_CHINESE_SINGAPORE:
444             case LANGUAGE_CHINESE_HONGKONG:
445             case LANGUAGE_CHINESE_MACAU:
446                 nDefaultCJK = nDefaultLang;
447                 break;
448             default:
449                 nDefaultCJK = LANGUAGE_CHINESE;
450                 break;
451         }
452 
453         // change the marked entries to prefered language
454         static const int nCount = (sizeof(aLangFromCodeChart) / sizeof(*aLangFromCodeChart));
455         for( int i = 0; i < nCount; ++i )
456         {
457             if( aLangFromCodeChart[ i].mnLangID == LANGUAGE_DEFAULT_CJK )
458                 aLangFromCodeChart[ i].mnLangID = nDefaultCJK;
459         }
460     }
461 
462     // binary search
463     int nLow = 0;
464     int nHigh = (sizeof(aLangFromCodeChart) / sizeof(*aLangFromCodeChart)) - 1;
465     while( nLow <= nHigh )
466     {
467         int nMiddle = (nHigh + nLow) / 2;
468         if( uChar < aLangFromCodeChart[ nMiddle].mnMinCode )
469             nHigh = nMiddle - 1;
470         else if( uChar > aLangFromCodeChart[ nMiddle].mnMaxCode )
471             nLow = nMiddle + 1;
472         else
473             return aLangFromCodeChart[ nMiddle].mnLangID;
474     }
475 
476     return LANGUAGE_DONTKNOW;
477 }
478 
479 class WinGlyphFallbackSubstititution
480 :    public ImplGlyphFallbackFontSubstitution
481 {
482 public:
483     explicit    WinGlyphFallbackSubstititution( HDC );
484 
485     bool FindFontSubstitute( ImplFontSelectData&, rtl::OUString& rMissingChars ) const;
486 private:
487     HDC mhDC;
488     bool HasMissingChars( const ImplFontData*, const rtl::OUString& rMissingChars ) const;
489 };
490 
491 inline WinGlyphFallbackSubstititution::WinGlyphFallbackSubstititution( HDC hDC )
492 :   mhDC( hDC )
493 {}
494 
495 void ImplGetLogFontFromFontSelect( HDC, const ImplFontSelectData*,
496     LOGFONTW&, bool /*bTestVerticalAvail*/ );
497 
498 // does a font face hold the given missing characters?
499 bool WinGlyphFallbackSubstititution::HasMissingChars( const ImplFontData* pFace, const rtl::OUString& rMissingChars ) const
500 {
501     const ImplWinFontData* pWinFont = static_cast<const ImplWinFontData*>(pFace);
502     const ImplFontCharMap* pCharMap = pWinFont->GetImplFontCharMap();
503     if( !pCharMap )
504     {
505         // construct a Size structure as the parameter of constructor of class ImplFontSelectData
506         const Size aSize( pFace->GetWidth(), pFace->GetHeight() );
507         // create a ImplFontSelectData object for getting s LOGFONT
508         const ImplFontSelectData aFSD( *pFace, aSize, (float)aSize.Height(), 0, false );
509         // construct log font
510         LOGFONTW aLogFont;
511         ImplGetLogFontFromFontSelect( mhDC, &aFSD, aLogFont, true );
512 
513         // create HFONT from log font
514         HFONT hNewFont = ::CreateFontIndirectW( &aLogFont );
515         // select the new font into device
516         HFONT hOldFont = ::SelectFont( mhDC, hNewFont );
517 
518         // read CMAP table to update their pCharMap
519         pWinFont->UpdateFromHDC( mhDC );;
520 
521         // cleanup temporary font
522         ::SelectFont( mhDC, hOldFont );
523         ::DeleteFont( hNewFont );
524 
525         // get the new charmap
526         pCharMap = pWinFont->GetImplFontCharMap();
527     }
528 
529     // avoid fonts with unknown CMAP subtables for glyph fallback
530     if( !pCharMap || pCharMap->IsDefaultMap() )
531         return false;
532         pCharMap->AddReference();
533 
534     int nMatchCount = 0;
535     // static const int nMaxMatchCount = 1; // TODO: tolerate more missing characters?
536     const sal_Int32 nStrLen = rMissingChars.getLength();
537     for( sal_Int32 nStrIdx = 0; nStrIdx < nStrLen; ++nStrIdx )
538     {
539         const sal_UCS4 uChar = rMissingChars.iterateCodePoints( &nStrIdx );
540         nMatchCount += pCharMap->HasChar( uChar );
541         break; // for now
542     }
543         pCharMap->DeReference();
544 
545     const bool bHasMatches = (nMatchCount > 0);
546     return bHasMatches;
547 }
548 
549 // find a fallback font for missing characters
550 // TODO: should stylistic matches be searched and prefered?
551 bool WinGlyphFallbackSubstititution::FindFontSubstitute( ImplFontSelectData& rFontSelData, rtl::OUString& rMissingChars ) const
552 {
553     // guess a locale matching to the missing chars
554     com::sun::star::lang::Locale aLocale;
555 
556     sal_Int32 nStrIdx = 0;
557     const sal_Int32 nStrLen = rMissingChars.getLength();
558     while( nStrIdx < nStrLen )
559     {
560         const sal_UCS4 uChar = rMissingChars.iterateCodePoints( &nStrIdx );
561         const LanguageType eLang = MapCharToLanguage( uChar );
562         if( eLang == LANGUAGE_DONTKNOW )
563             continue;
564         MsLangId::convertLanguageToLocale( eLang, aLocale );
565         break;
566     }
567 
568     // fall back to default UI locale if the missing characters are inconclusive
569     if( nStrIdx >= nStrLen )
570         aLocale = Application::GetSettings().GetUILocale();
571 
572     // first level fallback:
573     // try use the locale specific default fonts defined in VCL.xcu
574     const ImplDevFontList* pDevFontList = ImplGetSVData()->maGDIData.mpScreenFontList;
575     /*const*/ ImplDevFontListData* pDevFont = pDevFontList->ImplFindByLocale( aLocale );
576     if( pDevFont )
577     {
578         const ImplFontData* pFace = pDevFont->FindBestFontFace( rFontSelData );
579         if( HasMissingChars( pFace, rMissingChars ) )
580         {
581             rFontSelData.maSearchName = pDevFont->GetSearchName();
582             return true;
583         }
584     }
585 
586     // are the missing characters symbols?
587     pDevFont = pDevFontList->ImplFindByAttributes( IMPL_FONT_ATTR_SYMBOL,
588                     rFontSelData.meWeight, rFontSelData.meWidthType,
589                     rFontSelData.meFamily, rFontSelData.meItalic, rFontSelData.maSearchName );
590     if( pDevFont )
591     {
592         const ImplFontData* pFace = pDevFont->FindBestFontFace( rFontSelData );
593         if( HasMissingChars( pFace, rMissingChars ) )
594         {
595             rFontSelData.maSearchName = pDevFont->GetSearchName();
596             return true;
597         }
598     }
599 
600     // last level fallback, check each font type face one by one
601     const ImplGetDevFontList* pTestFontList = pDevFontList->GetDevFontList();
602     // limit the count of fonts to be checked to prevent hangs
603     static const int MAX_GFBFONT_COUNT = 600;
604     int nTestFontCount = pTestFontList->Count();
605     if( nTestFontCount > MAX_GFBFONT_COUNT )
606         nTestFontCount = MAX_GFBFONT_COUNT;
607 
608     for( int i = 0; i < nTestFontCount; ++i )
609     {
610         const ImplFontData* pFace = pTestFontList->Get( i );
611         if( !HasMissingChars( pFace, rMissingChars ) )
612             continue;
613         rFontSelData.maSearchName = pFace->maName;
614         return true;
615     }
616 
617     return false;
618 }
619 
620 // =======================================================================
621 
622 struct ImplEnumInfo
623 {
624     HDC                 mhDC;
625     ImplDevFontList*    mpList;
626     String*             mpName;
627     LOGFONTA*           mpLogFontA;
628     LOGFONTW*           mpLogFontW;
629     UINT                mnPreferedCharSet;
630     bool                mbCourier;
631     bool                mbImplSalCourierScalable;
632     bool                mbImplSalCourierNew;
633     bool                mbPrinter;
634     int                 mnFontCount;
635 };
636 
637 // =======================================================================
638 
639 static CharSet ImplCharSetToSal( BYTE nCharSet )
640 {
641     rtl_TextEncoding eTextEncoding;
642 
643     if ( nCharSet == OEM_CHARSET )
644     {
645         UINT nCP = (sal_uInt16)GetOEMCP();
646         switch ( nCP )
647         {
648             // It is unclear why these two (undefined?) code page numbers are
649             // handled specially here:
650             case 1004:  eTextEncoding = RTL_TEXTENCODING_MS_1252; break;
651             case 65400: eTextEncoding = RTL_TEXTENCODING_SYMBOL; break;
652             default:
653                 eTextEncoding = rtl_getTextEncodingFromWindowsCodePage(nCP);
654                 break;
655         };
656     }
657     else
658     {
659         if( nCharSet )
660             eTextEncoding = rtl_getTextEncodingFromWindowsCharset( nCharSet );
661         else
662             eTextEncoding = RTL_TEXTENCODING_UNICODE;
663     }
664 
665     return eTextEncoding;
666 }
667 
668 // -----------------------------------------------------------------------
669 
670 static FontFamily ImplFamilyToSal( BYTE nFamily )
671 {
672     switch ( nFamily & 0xF0 )
673     {
674         case FF_DECORATIVE:
675             return FAMILY_DECORATIVE;
676 
677         case FF_MODERN:
678             return FAMILY_MODERN;
679 
680         case FF_ROMAN:
681             return FAMILY_ROMAN;
682 
683         case FF_SCRIPT:
684             return FAMILY_SCRIPT;
685 
686         case FF_SWISS:
687             return FAMILY_SWISS;
688 
689         default:
690             break;
691     }
692 
693     return FAMILY_DONTKNOW;
694 }
695 
696 // -----------------------------------------------------------------------
697 
698 static BYTE ImplFamilyToWin( FontFamily eFamily )
699 {
700     switch ( eFamily )
701     {
702         case FAMILY_DECORATIVE:
703             return FF_DECORATIVE;
704 
705         case FAMILY_MODERN:
706             return FF_MODERN;
707 
708         case FAMILY_ROMAN:
709             return FF_ROMAN;
710 
711         case FAMILY_SCRIPT:
712             return FF_SCRIPT;
713 
714         case FAMILY_SWISS:
715             return FF_SWISS;
716 
717         case FAMILY_SYSTEM:
718             return FF_SWISS;
719 
720         default:
721             break;
722     }
723 
724     return FF_DONTCARE;
725 }
726 
727 // -----------------------------------------------------------------------
728 
729 static FontWeight ImplWeightToSal( int nWeight )
730 {
731     if ( nWeight <= FW_THIN )
732         return WEIGHT_THIN;
733     else if ( nWeight <= FW_ULTRALIGHT )
734         return WEIGHT_ULTRALIGHT;
735     else if ( nWeight <= FW_LIGHT )
736         return WEIGHT_LIGHT;
737     else if ( nWeight < FW_MEDIUM )
738         return WEIGHT_NORMAL;
739     else if ( nWeight == FW_MEDIUM )
740         return WEIGHT_MEDIUM;
741     else if ( nWeight <= FW_SEMIBOLD )
742         return WEIGHT_SEMIBOLD;
743     else if ( nWeight <= FW_BOLD )
744         return WEIGHT_BOLD;
745     else if ( nWeight <= FW_ULTRABOLD )
746         return WEIGHT_ULTRABOLD;
747     else
748         return WEIGHT_BLACK;
749 }
750 
751 // -----------------------------------------------------------------------
752 
753 static int ImplWeightToWin( FontWeight eWeight )
754 {
755     switch ( eWeight )
756     {
757         case WEIGHT_THIN:
758             return FW_THIN;
759 
760         case WEIGHT_ULTRALIGHT:
761             return FW_ULTRALIGHT;
762 
763         case WEIGHT_LIGHT:
764             return FW_LIGHT;
765 
766         case WEIGHT_SEMILIGHT:
767         case WEIGHT_NORMAL:
768             return FW_NORMAL;
769 
770         case WEIGHT_MEDIUM:
771             return FW_MEDIUM;
772 
773         case WEIGHT_SEMIBOLD:
774             return FW_SEMIBOLD;
775 
776         case WEIGHT_BOLD:
777             return FW_BOLD;
778 
779         case WEIGHT_ULTRABOLD:
780             return FW_ULTRABOLD;
781 
782         case WEIGHT_BLACK:
783             return FW_BLACK;
784 
785         default:
786             break;
787     }
788 
789     return 0;
790 }
791 
792 // -----------------------------------------------------------------------
793 
794 inline FontPitch ImplLogPitchToSal( BYTE nPitch )
795 {
796     if ( nPitch & FIXED_PITCH )
797         return PITCH_FIXED;
798     else
799         return PITCH_VARIABLE;
800 }
801 
802 // -----------------------------------------------------------------------
803 
804 inline FontPitch ImplMetricPitchToSal( BYTE nPitch )
805 {
806     // Sausaecke bei MS !! siehe NT Hilfe
807     if ( !(nPitch & TMPF_FIXED_PITCH) )
808         return PITCH_FIXED;
809     else
810         return PITCH_VARIABLE;
811 }
812 
813 // -----------------------------------------------------------------------
814 
815 inline BYTE ImplPitchToWin( FontPitch ePitch )
816 {
817     if ( ePitch == PITCH_FIXED )
818         return FIXED_PITCH;
819     else if ( ePitch == PITCH_VARIABLE )
820         return VARIABLE_PITCH;
821     else
822         return DEFAULT_PITCH;
823 }
824 
825 // -----------------------------------------------------------------------
826 
827 static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXA& rEnumFont,
828     const NEWTEXTMETRICA& rMetric, DWORD nFontType )
829 {
830     ImplDevFontAttributes aDFA;
831 
832     const LOGFONTA rLogFont = rEnumFont.elfLogFont;
833 
834     // get font face attributes
835     aDFA.meFamily       = ImplFamilyToSal( rLogFont.lfPitchAndFamily );
836     aDFA.meWidthType    = WIDTH_DONTKNOW;
837     aDFA.meWeight       = ImplWeightToSal( rLogFont.lfWeight );
838     aDFA.meItalic       = (rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE;
839     aDFA.mePitch        = ImplLogPitchToSal( rLogFont.lfPitchAndFamily );
840     aDFA.mbSymbolFlag   = (rLogFont.lfCharSet == SYMBOL_CHARSET);
841 
842     // get the font face name
843     aDFA.maName = ImplSalGetUniString( rLogFont.lfFaceName );
844 
845     // use the face's style name only if it looks reasonable
846     const char* pStyleName = (const char*)rEnumFont.elfStyle;
847     const char* pEnd = pStyleName + sizeof( rEnumFont.elfStyle );
848     const char* p = pStyleName;
849     for(; *p && (p < pEnd); ++p )
850         if( (0x00 < *p) && (*p < 0x20) )
851             break;
852     if( p < pEnd )
853         aDFA.maStyleName = ImplSalGetUniString( pStyleName );
854 
855     // get device specific font attributes
856     aDFA.mbOrientation  = (nFontType & RASTER_FONTTYPE) == 0;
857     aDFA.mbDevice       = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
858 
859     aDFA.mbEmbeddable   = false;
860     aDFA.mbSubsettable  = false;
861     if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
862      || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
863         aDFA.mbSubsettable = true;
864     else if( 0 != (rMetric.ntmFlags & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
865         aDFA.mbEmbeddable = true;
866 
867     // heuristics for font quality
868     // -   standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
869     // -   subsetting > embedding > none
870     aDFA.mnQuality = 0;
871     if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
872         aDFA.mnQuality += 50;
873     if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
874         aDFA.mnQuality += 10;
875     if( aDFA.mbSubsettable )
876         aDFA.mnQuality += 200;
877     else if( aDFA.mbEmbeddable )
878         aDFA.mnQuality += 100;
879 
880     // #i38665# prefer Type1 versions of the standard postscript fonts
881     if( aDFA.mbEmbeddable )
882     {
883         if( aDFA.maName.EqualsAscii( "AvantGarde" )
884         ||  aDFA.maName.EqualsAscii( "Bookman" )
885         ||  aDFA.maName.EqualsAscii( "Courier" )
886         ||  aDFA.maName.EqualsAscii( "Helvetica" )
887         ||  aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
888         ||  aDFA.maName.EqualsAscii( "Palatino" )
889         ||  aDFA.maName.EqualsAscii( "Symbol" )
890         ||  aDFA.maName.EqualsAscii( "Times" )
891         ||  aDFA.maName.EqualsAscii( "ZapfChancery" )
892         ||  aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
893             aDFA.mnQuality += 500;
894     }
895 
896     // TODO: add alias names
897     return aDFA;
898 }
899 
900 // -----------------------------------------------------------------------
901 
902 static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXW& rEnumFont,
903     const NEWTEXTMETRICW& rMetric, DWORD nFontType )
904 {
905     ImplDevFontAttributes aDFA;
906 
907     const LOGFONTW rLogFont = rEnumFont.elfLogFont;
908 
909     // get font face attributes
910     aDFA.meFamily       = ImplFamilyToSal( rLogFont.lfPitchAndFamily );
911     aDFA.meWidthType    = WIDTH_DONTKNOW;
912     aDFA.meWeight       = ImplWeightToSal( rLogFont.lfWeight );
913     aDFA.meItalic       = (rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE;
914     aDFA.mePitch        = ImplLogPitchToSal( rLogFont.lfPitchAndFamily );
915     aDFA.mbSymbolFlag   = (rLogFont.lfCharSet == SYMBOL_CHARSET);
916 
917     // get the font face name
918     aDFA.maName = reinterpret_cast<const sal_Unicode*>(rLogFont.lfFaceName);
919 
920     // use the face's style name only if it looks reasonable
921     const wchar_t* pStyleName = rEnumFont.elfStyle;
922     const wchar_t* pEnd = pStyleName + sizeof(rEnumFont.elfStyle)/sizeof(*rEnumFont.elfStyle);
923     const wchar_t* p = pStyleName;
924     for(; *p && (p < pEnd); ++p )
925         if( *p < 0x0020 )
926             break;
927     if( p < pEnd )
928         aDFA.maStyleName = reinterpret_cast<const sal_Unicode*>(pStyleName);
929 
930     // get device specific font attributes
931     aDFA.mbOrientation  = (nFontType & RASTER_FONTTYPE) == 0;
932     aDFA.mbDevice       = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
933 
934     aDFA.mbEmbeddable   = false;
935     aDFA.mbSubsettable  = false;
936     if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
937      || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
938         aDFA.mbSubsettable = true;
939     else if( 0 != (rMetric.ntmFlags & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
940         aDFA.mbEmbeddable = true;
941 
942     // heuristics for font quality
943     // -   standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
944     // -   subsetting > embedding > none
945     aDFA.mnQuality = 0;
946     if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
947         aDFA.mnQuality += 50;
948     if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
949         aDFA.mnQuality += 10;
950     if( aDFA.mbSubsettable )
951         aDFA.mnQuality += 200;
952     else if( aDFA.mbEmbeddable )
953         aDFA.mnQuality += 100;
954 
955     // #i38665# prefer Type1 versions of the standard postscript fonts
956     if( aDFA.mbEmbeddable )
957     {
958         if( aDFA.maName.EqualsAscii( "AvantGarde" )
959         ||  aDFA.maName.EqualsAscii( "Bookman" )
960         ||  aDFA.maName.EqualsAscii( "Courier" )
961         ||  aDFA.maName.EqualsAscii( "Helvetica" )
962         ||  aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
963         ||  aDFA.maName.EqualsAscii( "Palatino" )
964         ||  aDFA.maName.EqualsAscii( "Symbol" )
965         ||  aDFA.maName.EqualsAscii( "Times" )
966         ||  aDFA.maName.EqualsAscii( "ZapfChancery" )
967         ||  aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
968             aDFA.mnQuality += 500;
969     }
970 
971     // TODO: add alias names
972     return aDFA;
973 }
974 
975 // -----------------------------------------------------------------------
976 
977 static ImplWinFontData* ImplLogMetricToDevFontDataA( const ENUMLOGFONTEXA* pLogFont,
978                                          const NEWTEXTMETRICA* pMetric,
979                                          DWORD nFontType )
980 {
981     int nHeight = 0;
982     if ( nFontType & RASTER_FONTTYPE )
983         nHeight = pMetric->tmHeight - pMetric->tmInternalLeading;
984 
985     ImplWinFontData* pData = new ImplWinFontData(
986         WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType),
987         nHeight,
988         pLogFont->elfLogFont.lfCharSet,
989         pMetric->tmPitchAndFamily );
990 
991     return pData;
992 }
993 
994 // -----------------------------------------------------------------------
995 
996 static ImplWinFontData* ImplLogMetricToDevFontDataW( const ENUMLOGFONTEXW* pLogFont,
997                                          const NEWTEXTMETRICW* pMetric,
998                                          DWORD nFontType )
999 {
1000     int nHeight = 0;
1001     if ( nFontType & RASTER_FONTTYPE )
1002         nHeight = pMetric->tmHeight - pMetric->tmInternalLeading;
1003 
1004     ImplWinFontData* pData = new ImplWinFontData(
1005         WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType),
1006         nHeight,
1007         pLogFont->elfLogFont.lfCharSet,
1008         pMetric->tmPitchAndFamily );
1009 
1010     return pData;
1011 }
1012 
1013 // -----------------------------------------------------------------------
1014 
1015 void ImplSalLogFontToFontA( HDC hDC, const LOGFONTA& rLogFont, Font& rFont )
1016 {
1017     String aFontName( ImplSalGetUniString( rLogFont.lfFaceName ) );
1018     if ( aFontName.Len() )
1019     {
1020         rFont.SetName( aFontName );
1021         rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) );
1022         rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) );
1023         rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) );
1024         rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) );
1025 
1026         long nFontHeight = rLogFont.lfHeight;
1027         if ( nFontHeight < 0 )
1028             nFontHeight = -nFontHeight;
1029         long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
1030         if( !nDPIY )
1031             nDPIY = 600;
1032         nFontHeight *= 72;
1033         nFontHeight += nDPIY/2;
1034         nFontHeight /= nDPIY;
1035         rFont.SetSize( Size( 0, nFontHeight ) );
1036         rFont.SetOrientation( (short)rLogFont.lfEscapement );
1037         if ( rLogFont.lfItalic )
1038             rFont.SetItalic( ITALIC_NORMAL );
1039         else
1040             rFont.SetItalic( ITALIC_NONE );
1041         if ( rLogFont.lfUnderline )
1042             rFont.SetUnderline( UNDERLINE_SINGLE );
1043         else
1044             rFont.SetUnderline( UNDERLINE_NONE );
1045         if ( rLogFont.lfStrikeOut )
1046             rFont.SetStrikeout( STRIKEOUT_SINGLE );
1047         else
1048             rFont.SetStrikeout( STRIKEOUT_NONE );
1049     }
1050 }
1051 
1052 // -----------------------------------------------------------------------
1053 
1054 void ImplSalLogFontToFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont )
1055 {
1056     XubString aFontName( reinterpret_cast<const xub_Unicode*>(rLogFont.lfFaceName) );
1057     if ( aFontName.Len() )
1058     {
1059         rFont.SetName( aFontName );
1060         rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) );
1061         rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) );
1062         rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) );
1063         rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) );
1064 
1065         long nFontHeight = rLogFont.lfHeight;
1066         if ( nFontHeight < 0 )
1067             nFontHeight = -nFontHeight;
1068         long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
1069         if( !nDPIY )
1070             nDPIY = 600;
1071         nFontHeight *= 72;
1072         nFontHeight += nDPIY/2;
1073         nFontHeight /= nDPIY;
1074         rFont.SetSize( Size( 0, nFontHeight ) );
1075         rFont.SetOrientation( (short)rLogFont.lfEscapement );
1076         if ( rLogFont.lfItalic )
1077             rFont.SetItalic( ITALIC_NORMAL );
1078         else
1079             rFont.SetItalic( ITALIC_NONE );
1080         if ( rLogFont.lfUnderline )
1081             rFont.SetUnderline( UNDERLINE_SINGLE );
1082         else
1083             rFont.SetUnderline( UNDERLINE_NONE );
1084         if ( rLogFont.lfStrikeOut )
1085             rFont.SetStrikeout( STRIKEOUT_SINGLE );
1086         else
1087             rFont.SetStrikeout( STRIKEOUT_NONE );
1088     }
1089 }
1090 
1091 // =======================================================================
1092 
1093 ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes& rDFS,
1094     int nHeight, BYTE eWinCharSet, BYTE nPitchAndFamily )
1095 :   ImplFontData( rDFS, 0 ),
1096     meWinCharSet( eWinCharSet ),
1097     mnPitchAndFamily( nPitchAndFamily ),
1098     mpFontCharSets( NULL ),
1099     mpUnicodeMap( NULL ),
1100     mbGsubRead( false ),
1101     mbDisableGlyphApi( false ),
1102     mbHasKoreanRange( false ),
1103     mbHasCJKSupport( false ),
1104 #ifdef ENABLE_GRAPHITE
1105     mbHasGraphiteSupport( false ),
1106 #endif
1107     mbHasArabicSupport ( false ),
1108     mbAliasSymbolsLow( false ),
1109     mbAliasSymbolsHigh( false ),
1110     mnId( 0 ),
1111     mpEncodingVector( NULL )
1112 {
1113     SetBitmapSize( 0, nHeight );
1114 
1115     if( eWinCharSet == SYMBOL_CHARSET )
1116     {
1117         if( (nPitchAndFamily & TMPF_TRUETYPE) != 0 )
1118         {
1119             // truetype fonts need their symbols as U+F0xx
1120             mbAliasSymbolsHigh = true;
1121         }
1122         else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_DEVICE))
1123                                  == (TMPF_VECTOR|TMPF_DEVICE) )
1124         {
1125             // scalable device fonts (e.g. builtin printer fonts)
1126             // need their symbols as U+00xx
1127             mbAliasSymbolsLow  = true;
1128         }
1129         else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) == 0 )
1130         {
1131             // bitmap fonts need their symbols as U+F0xx
1132             mbAliasSymbolsHigh = true;
1133         }
1134     }
1135 }
1136 
1137 // -----------------------------------------------------------------------
1138 
1139 ImplWinFontData::~ImplWinFontData()
1140 {
1141     delete[] mpFontCharSets;
1142 
1143     if( mpUnicodeMap )
1144         mpUnicodeMap->DeReference();
1145     delete mpEncodingVector;
1146 }
1147 
1148 // -----------------------------------------------------------------------
1149 
1150 sal_IntPtr ImplWinFontData::GetFontId() const
1151 {
1152     return mnId;
1153 }
1154 
1155 // -----------------------------------------------------------------------
1156 
1157 void ImplWinFontData::UpdateFromHDC( HDC hDC ) const
1158 {
1159     // short circuit if already initialized
1160     if( mpUnicodeMap != NULL )
1161         return;
1162 
1163     ReadCmapTable( hDC );
1164     ReadOs2Table( hDC );
1165 #ifdef ENABLE_GRAPHITE
1166     static const char* pDisableGraphiteText = getenv( "SAL_DISABLE_GRAPHITE" );
1167     if( !pDisableGraphiteText || (pDisableGraphiteText[0] == '0') )
1168     {
1169         mbHasGraphiteSupport = gr::WinFont::FontHasGraphiteTables(hDC);
1170     }
1171 #endif
1172 
1173     // even if the font works some fonts have problems with the glyph API
1174     // => the heuristic below tries to figure out which fonts have the problem
1175     TEXTMETRICA aTextMetric;
1176     if( ::GetTextMetricsA( hDC, &aTextMetric ) )
1177         if( !(aTextMetric.tmPitchAndFamily & TMPF_TRUETYPE)
1178         ||   (aTextMetric.tmPitchAndFamily & TMPF_DEVICE) )
1179             mbDisableGlyphApi = true;
1180 
1181 #if 0
1182     // #110548# more important than #107885# => TODO: better solution
1183     DWORD nFLI = GetFontLanguageInfo( hDC );
1184     if( 0 == (nFLI & GCP_GLYPHSHAPE) )
1185         mbDisableGlyphApi = true;
1186 #endif
1187 }
1188 
1189 // -----------------------------------------------------------------------
1190 
1191 bool ImplWinFontData::HasGSUBstitutions( HDC hDC ) const
1192 {
1193     if( !mbGsubRead )
1194         ReadGsubTable( hDC );
1195     return !maGsubTable.empty();
1196 }
1197 
1198 // -----------------------------------------------------------------------
1199 
1200 bool ImplWinFontData::IsGSUBstituted( sal_UCS4 cChar ) const
1201 {
1202     return( maGsubTable.find( cChar ) != maGsubTable.end() );
1203 }
1204 
1205 // -----------------------------------------------------------------------
1206 
1207 const ImplFontCharMap* ImplWinFontData::GetImplFontCharMap() const
1208 {
1209     if( !mpUnicodeMap )
1210         return NULL;
1211     return mpUnicodeMap;
1212 }
1213 
1214 // -----------------------------------------------------------------------
1215 
1216 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
1217 static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
1218 //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
1219 static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); }
1220 
1221 void ImplWinFontData::ReadOs2Table( HDC hDC ) const
1222 {
1223     const DWORD Os2Tag = CalcTag( "OS/2" );
1224     DWORD nLength = ::GetFontData( hDC, Os2Tag, 0, NULL, 0 );
1225     if( (nLength == GDI_ERROR) || !nLength )
1226         return;
1227     std::vector<unsigned char> aOS2map( nLength );
1228     unsigned char* pOS2map = &aOS2map[0];
1229     ::GetFontData( hDC, Os2Tag, 0, pOS2map, nLength );
1230     sal_uInt32 nVersion = GetUShort( pOS2map );
1231     if ( nVersion >= 0x0001 && nLength >= 58 )
1232     {
1233         // We need at least version 0x0001 (TrueType rev 1.66)
1234         // to have access to the needed struct members.
1235         sal_uInt32 ulUnicodeRange1 = GetUInt( pOS2map + 42 );
1236         sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
1237 #if 0
1238         sal_uInt32 ulUnicodeRange3 = GetUInt( pOS2map + 50 );
1239         sal_uInt32 ulUnicodeRange4 = GetUInt( pOS2map + 54 );
1240 #endif
1241 
1242         // Check for CJK capabilities of the current font
1243         mbHasCJKSupport = (ulUnicodeRange2 & 0x2DF00000);
1244         mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000)
1245                         | (ulUnicodeRange2 & 0x01100000);
1246         mbHasArabicSupport = (ulUnicodeRange1 & 0x00002000);
1247    }
1248 }
1249 
1250 // -----------------------------------------------------------------------
1251 
1252 void ImplWinFontData::ReadGsubTable( HDC hDC ) const
1253 {
1254     mbGsubRead = true;
1255 
1256     // check the existence of a GSUB table
1257     const DWORD GsubTag = CalcTag( "GSUB" );
1258     DWORD nRC = ::GetFontData( hDC, GsubTag, 0, NULL, 0 );
1259     if( (nRC == GDI_ERROR) || !nRC )
1260         return;
1261 
1262     // parse the GSUB table through sft
1263     // TODO: parse it directly
1264 
1265     // sft needs the full font file data => get it
1266     const RawFontData aRawFontData( hDC );
1267     if( !aRawFontData.get() )
1268         return;
1269 
1270     // open font file
1271     sal_uInt32 nFaceNum = 0;
1272     if( !*aRawFontData.get() )  // TTC candidate
1273         nFaceNum = ~0U;  // indicate "TTC font extracts only"
1274 
1275     TrueTypeFont* pTTFont = NULL;
1276     ::OpenTTFontBuffer( (void*)aRawFontData.get(), aRawFontData.size(), nFaceNum, &pTTFont );
1277     if( !pTTFont )
1278         return;
1279 
1280     // add vertically substituted characters to list
1281     static const sal_Unicode aGSUBCandidates[] = {
1282         0x0020, 0x0080, // ASCII
1283         0x2000, 0x2600, // misc
1284         0x3000, 0x3100, // CJK punctutation
1285         0x3300, 0x3400, // squared words
1286         0xFF00, 0xFFF0, // halfwidth|fullwidth forms
1287     0 };
1288 
1289     for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
1290         for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
1291             if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
1292                 maGsubTable.insert( cChar ); // insert GSUBbed unicodes
1293 
1294     CloseTTFont( pTTFont );
1295 }
1296 
1297 // -----------------------------------------------------------------------
1298 
1299 void ImplWinFontData::ReadCmapTable( HDC hDC ) const
1300 {
1301     if( mpUnicodeMap != NULL )
1302         return;
1303 
1304     bool bIsSymbolFont = (meWinCharSet == SYMBOL_CHARSET);
1305     // get the CMAP table from the font which is selected into the DC
1306     const DWORD nCmapTag = CalcTag( "cmap" );
1307     const RawFontData aRawFontData( hDC, nCmapTag );
1308     // parse the CMAP table if available
1309     if( aRawFontData.get() ) {
1310         CmapResult aResult;
1311         ParseCMAP( aRawFontData.get(), aRawFontData.size(), aResult );
1312         mbDisableGlyphApi |= aResult.mbRecoded;
1313         aResult.mbSymbolic = bIsSymbolFont;
1314         if( aResult.mnRangeCount > 0 )
1315             mpUnicodeMap = new ImplFontCharMap( aResult );
1316     }
1317 
1318     if( !mpUnicodeMap )
1319         mpUnicodeMap = ImplFontCharMap::GetDefaultMap( bIsSymbolFont );
1320     mpUnicodeMap->AddReference();
1321 }
1322 
1323 // =======================================================================
1324 
1325 void WinSalGraphics::SetTextColor( SalColor nSalColor )
1326 {
1327     COLORREF aCol = PALETTERGB( SALCOLOR_RED( nSalColor ),
1328                                 SALCOLOR_GREEN( nSalColor ),
1329                                 SALCOLOR_BLUE( nSalColor ) );
1330 
1331     if( !mbPrinter &&
1332         GetSalData()->mhDitherPal &&
1333         ImplIsSysColorEntry( nSalColor ) )
1334     {
1335         aCol = PALRGB_TO_RGB( aCol );
1336     }
1337 
1338     ::SetTextColor( mhDC, aCol );
1339 }
1340 
1341 // -----------------------------------------------------------------------
1342 
1343 int CALLBACK SalEnumQueryFontProcExW( const ENUMLOGFONTEXW*,
1344                                       const NEWTEXTMETRICEXW*,
1345                                       DWORD, LPARAM lParam )
1346 {
1347     *((bool*)(void*)lParam) = true;
1348     return 0;
1349 }
1350 
1351 // -----------------------------------------------------------------------
1352 
1353 int CALLBACK SalEnumQueryFontProcExA( const ENUMLOGFONTEXA*,
1354                                       const NEWTEXTMETRICEXA*,
1355                                       DWORD, LPARAM lParam )
1356 {
1357     *((bool*)(void*)lParam) = true;
1358     return 0;
1359 }
1360 
1361 // -----------------------------------------------------------------------
1362 
1363 bool ImplIsFontAvailable( HDC hDC, const UniString& rName )
1364 {
1365         // Test, if Font available
1366         LOGFONTW aLogFont;
1367         memset( &aLogFont, 0, sizeof( aLogFont ) );
1368         aLogFont.lfCharSet = DEFAULT_CHARSET;
1369 
1370         UINT nNameLen = rName.Len();
1371         if ( nNameLen > (sizeof( aLogFont.lfFaceName )/sizeof( wchar_t ))-1 )
1372             nNameLen = (sizeof( aLogFont.lfFaceName )/sizeof( wchar_t ))-1;
1373         memcpy( aLogFont.lfFaceName, rName.GetBuffer(), nNameLen*sizeof( wchar_t ) );
1374         aLogFont.lfFaceName[nNameLen] = 0;
1375 
1376     bool bAvailable = false;
1377     EnumFontFamiliesExW( hDC, &aLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW,
1378                              (LPARAM)(void*)&bAvailable, 0 );
1379 
1380     return bAvailable;
1381 }
1382 
1383 // -----------------------------------------------------------------------
1384 
1385 void ImplGetLogFontFromFontSelect( HDC hDC,
1386                                    const ImplFontSelectData* pFont,
1387                                    LOGFONTW& rLogFont,
1388                                    bool /*bTestVerticalAvail*/ )
1389 {
1390     UniString   aName;
1391     if ( pFont->mpFontData )
1392         aName = pFont->mpFontData->maName;
1393     else
1394         aName = pFont->maName.GetToken( 0 );
1395 
1396     UINT nNameLen = aName.Len();
1397     if ( nNameLen > (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1 )
1398         nNameLen = (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1;
1399     memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen*sizeof( wchar_t ) );
1400     rLogFont.lfFaceName[nNameLen] = 0;
1401 
1402     if( !pFont->mpFontData )
1403     {
1404         rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET;
1405         rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->mePitch )
1406                                   | ImplFamilyToWin( pFont->meFamily );
1407     }
1408     else
1409     {
1410         const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData );
1411         rLogFont.lfCharSet        = pWinFontData->GetCharSet();
1412         rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily();
1413     }
1414 
1415     rLogFont.lfWeight          = ImplWeightToWin( pFont->meWeight );
1416     rLogFont.lfHeight          = (LONG)-pFont->mnHeight;
1417     rLogFont.lfWidth           = (LONG)pFont->mnWidth;
1418     rLogFont.lfUnderline       = 0;
1419     rLogFont.lfStrikeOut       = 0;
1420     rLogFont.lfItalic          = (pFont->meItalic) != ITALIC_NONE;
1421     rLogFont.lfEscapement      = pFont->mnOrientation;
1422     rLogFont.lfOrientation     = rLogFont.lfEscapement;
1423     rLogFont.lfClipPrecision   = CLIP_DEFAULT_PRECIS;
1424     rLogFont.lfQuality         = DEFAULT_QUALITY;
1425     rLogFont.lfOutPrecision    = OUT_TT_PRECIS;
1426     if ( pFont->mnOrientation )
1427         rLogFont.lfClipPrecision |= CLIP_LH_ANGLES;
1428 
1429     // disable antialiasing if requested
1430     if ( pFont->mbNonAntialiased )
1431         rLogFont.lfQuality = NONANTIALIASED_QUALITY;
1432 
1433     // select vertical mode if requested and available
1434     if( pFont->mbVertical && nNameLen )
1435     {
1436         // vertical fonts start with an '@'
1437         memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0],
1438             sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) );
1439         rLogFont.lfFaceName[0] = '@';
1440 
1441         // check availability of vertical mode for this font
1442         bool bAvailable = false;
1443         EnumFontFamiliesExW( hDC, &rLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW,
1444                          (LPARAM)&bAvailable, 0 );
1445 
1446         if( !bAvailable )
1447         {
1448             // restore non-vertical name if not vertical mode isn't available
1449             memcpy( &rLogFont.lfFaceName[0], aName.GetBuffer(), nNameLen*sizeof(wchar_t) );
1450             if( nNameLen < LF_FACESIZE )
1451                 rLogFont.lfFaceName[nNameLen] = '\0';
1452         }
1453     }
1454 }
1455 
1456 // -----------------------------------------------------------------------
1457 
1458 static void ImplGetLogFontFromFontSelect( HDC hDC,
1459                                    const ImplFontSelectData* pFont,
1460                                    LOGFONTA& rLogFont,
1461                                    bool /*bTestVerticalAvail*/ )
1462 {
1463     ByteString aName;
1464     if( pFont->mpFontData )
1465         aName = ImplSalGetWinAnsiString( pFont->mpFontData->maName );
1466     else
1467         aName = ImplSalGetWinAnsiString( pFont->maName.GetToken( 0 ) );
1468 
1469     int nNameLen = aName.Len();
1470     if( nNameLen > LF_FACESIZE )
1471         nNameLen = LF_FACESIZE;
1472     memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen );
1473     if( nNameLen < LF_FACESIZE )
1474         rLogFont.lfFaceName[nNameLen] = '\0';
1475 
1476     if( !pFont->mpFontData )
1477     {
1478         rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET;
1479         rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->mePitch )
1480                                   | ImplFamilyToWin( pFont->meFamily );
1481     }
1482     else
1483     {
1484         const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData );
1485         rLogFont.lfCharSet        = pWinFontData->GetCharSet();
1486         rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily();
1487     }
1488 
1489     rLogFont.lfWeight           = ImplWeightToWin( pFont->meWeight );
1490     rLogFont.lfHeight           = (LONG)-pFont->mnHeight;
1491     rLogFont.lfWidth            = (LONG)pFont->mnWidth;
1492     rLogFont.lfUnderline        = 0;
1493     rLogFont.lfStrikeOut        = 0;
1494     rLogFont.lfItalic           = (pFont->meItalic) != ITALIC_NONE;
1495     rLogFont.lfEscapement       = pFont->mnOrientation;
1496     rLogFont.lfOrientation      = rLogFont.lfEscapement; // ignored by W98
1497     rLogFont.lfClipPrecision    = CLIP_DEFAULT_PRECIS;
1498     rLogFont.lfQuality          = DEFAULT_QUALITY;
1499     rLogFont.lfOutPrecision     = OUT_TT_PRECIS;
1500     if( pFont->mnOrientation )
1501         rLogFont.lfClipPrecision |= CLIP_LH_ANGLES;
1502 
1503     // disable antialiasing if requested
1504     if( pFont->mbNonAntialiased )
1505         rLogFont.lfQuality = NONANTIALIASED_QUALITY;
1506 
1507     // select vertical mode if requested and available
1508     if( pFont->mbVertical && nNameLen )
1509     {
1510         // vertical fonts start with an '@'
1511         memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0],
1512                     sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) );
1513         rLogFont.lfFaceName[0] = '@';
1514 
1515         // check availability of vertical mode for this font
1516         bool bAvailable = false;
1517         EnumFontFamiliesExA( hDC, &rLogFont, (FONTENUMPROCA)SalEnumQueryFontProcExA,
1518                          (LPARAM)&bAvailable, 0 );
1519 
1520         if( !bAvailable )
1521         {
1522             // restore non-vertical name if vertical mode is not supported
1523             memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen );
1524             if( nNameLen < LF_FACESIZE )
1525                 rLogFont.lfFaceName[nNameLen] = '\0';
1526         }
1527     }
1528 }
1529 
1530 // -----------------------------------------------------------------------
1531 
1532 HFONT WinSalGraphics::ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, HFONT& o_rOldFont )
1533 {
1534     HFONT hNewFont = 0;
1535 
1536     HDC hdcScreen = 0;
1537     if( mbVirDev )
1538         // only required for virtual devices, see below for details
1539         hdcScreen = GetDC(0);
1540 
1541     if( true/*aSalShlData.mbWNT*/ )
1542     {
1543         LOGFONTW aLogFont;
1544         ImplGetLogFontFromFontSelect( mhDC, i_pFont, aLogFont, true );
1545 
1546         // on the display we prefer Courier New when Courier is a
1547         // bitmap only font and we need to stretch or rotate it
1548         if( mbScreen
1549         &&  (i_pFont->mnWidth != 0
1550           || i_pFont->mnOrientation != 0
1551           || i_pFont->mpFontData == NULL
1552           || (i_pFont->mpFontData->GetHeight() != i_pFont->mnHeight))
1553         && !bImplSalCourierScalable
1554         && bImplSalCourierNew
1555         && (ImplSalWICompareAscii( aLogFont.lfFaceName, "Courier" ) == 0) )
1556             lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 );
1557 
1558         // #i47675# limit font requests to MAXFONTHEIGHT
1559         // TODO: share MAXFONTHEIGHT font instance
1560         if( (-aLogFont.lfHeight <= MAXFONTHEIGHT)
1561         &&  (+aLogFont.lfWidth <= MAXFONTHEIGHT) )
1562         {
1563             o_rFontScale = 1.0;
1564         }
1565         else if( -aLogFont.lfHeight >= +aLogFont.lfWidth )
1566         {
1567             o_rFontScale = -aLogFont.lfHeight / (float)MAXFONTHEIGHT;
1568             aLogFont.lfHeight = -MAXFONTHEIGHT;
1569             aLogFont.lfWidth = FRound( aLogFont.lfWidth / o_rFontScale );
1570         }
1571         else // #i95867# also limit font widths
1572         {
1573             o_rFontScale = +aLogFont.lfWidth / (float)MAXFONTHEIGHT;
1574             aLogFont.lfWidth = +MAXFONTHEIGHT;
1575             aLogFont.lfHeight = FRound( aLogFont.lfHeight / o_rFontScale );
1576         }
1577 
1578         hNewFont = ::CreateFontIndirectW( &aLogFont );
1579         if( hdcScreen )
1580         {
1581             // select font into screen hdc first to get an antialiased font
1582             // see knowledge base article 305290:
1583             // "PRB: Fonts Not Drawn Antialiased on Device Context for DirectDraw Surface"
1584             SelectFont( hdcScreen, SelectFont( hdcScreen , hNewFont ) );
1585         }
1586         o_rOldFont = ::SelectFont( mhDC, hNewFont );
1587 
1588         TEXTMETRICW aTextMetricW;
1589         if( !::GetTextMetricsW( mhDC, &aTextMetricW ) )
1590         {
1591             // the selected font doesn't work => try a replacement
1592             // TODO: use its font fallback instead
1593             lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 );
1594             aLogFont.lfPitchAndFamily = FIXED_PITCH;
1595             HFONT hNewFont2 = CreateFontIndirectW( &aLogFont );
1596             SelectFont( mhDC, hNewFont2 );
1597             DeleteFont( hNewFont );
1598             hNewFont = hNewFont2;
1599         }
1600     }
1601 
1602     if( hdcScreen )
1603         ::ReleaseDC( NULL, hdcScreen );
1604 
1605     return hNewFont;
1606 }
1607 
1608 sal_uInt16 WinSalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel )
1609 {
1610     // return early if there is no new font
1611     if( !pFont )
1612     {
1613         // deselect still active font
1614         if( mhDefFont )
1615             ::SelectFont( mhDC, mhDefFont );
1616         // release no longer referenced font handles
1617         for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
1618         {
1619             if( mhFonts[i] )
1620                 ::DeleteFont( mhFonts[i] );
1621             mhFonts[ i ] = 0;
1622         }
1623         mhDefFont = 0;
1624         return 0;
1625     }
1626 
1627     DBG_ASSERT( pFont->mpFontData, "WinSalGraphics mpFontData==NULL");
1628     mpWinFontEntry[ nFallbackLevel ] = reinterpret_cast<ImplWinFontEntry*>( pFont->mpFontEntry );
1629     mpWinFontData[ nFallbackLevel ] = static_cast<const ImplWinFontData*>( pFont->mpFontData );
1630 
1631     HFONT hOldFont = 0;
1632     HFONT hNewFont = ImplDoSetFont( pFont, mfFontScale, hOldFont );
1633 
1634     if( !mhDefFont )
1635     {
1636         // keep default font
1637         mhDefFont = hOldFont;
1638     }
1639     else
1640     {
1641         // release no longer referenced font handles
1642         for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
1643         {
1644             if( mhFonts[i] )
1645             {
1646                 ::DeleteFont( mhFonts[i] );
1647                 mhFonts[i] = 0;
1648             }
1649         }
1650     }
1651 
1652     // store new font in correct layer
1653     mhFonts[ nFallbackLevel ] = hNewFont;
1654     // now the font is live => update font face
1655     if( mpWinFontData[ nFallbackLevel ] )
1656         mpWinFontData[ nFallbackLevel ]->UpdateFromHDC( mhDC );
1657 
1658     if( !nFallbackLevel )
1659     {
1660         mbFontKernInit = TRUE;
1661         if ( mpFontKernPairs )
1662         {
1663             delete[] mpFontKernPairs;
1664             mpFontKernPairs = NULL;
1665         }
1666         mnFontKernPairCount = 0;
1667     }
1668 
1669     mnFontCharSetCount = 0;
1670 
1671     // some printers have higher internal resolution, so their
1672     // text output would be different from what we calculated
1673     // => suggest DrawTextArray to workaround this problem
1674     if ( mbPrinter )
1675         return SAL_SETFONT_USEDRAWTEXTARRAY;
1676     else
1677         return 0;
1678 }
1679 
1680 // -----------------------------------------------------------------------
1681 
1682 void WinSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel )
1683 {
1684     // temporarily change the HDC to the font in the fallback level
1685     HFONT hOldFont = SelectFont( mhDC, mhFonts[nFallbackLevel] );
1686 
1687         wchar_t aFaceName[LF_FACESIZE+60];
1688         if( ::GetTextFaceW( mhDC, sizeof(aFaceName)/sizeof(wchar_t), aFaceName ) )
1689             pMetric->maName = reinterpret_cast<const sal_Unicode*>(aFaceName);
1690 
1691     // get the font metric
1692     TEXTMETRICA aWinMetric;
1693     const bool bOK = GetTextMetricsA( mhDC, &aWinMetric );
1694     // restore the HDC to the font in the base level
1695     SelectFont( mhDC, hOldFont );
1696     if( !bOK )
1697         return;
1698 
1699     // device independent font attributes
1700     pMetric->meFamily       = ImplFamilyToSal( aWinMetric.tmPitchAndFamily );;
1701     pMetric->mbSymbolFlag   = (aWinMetric.tmCharSet == SYMBOL_CHARSET);
1702     pMetric->meWeight       = ImplWeightToSal( aWinMetric.tmWeight );
1703     pMetric->mePitch        = ImplMetricPitchToSal( aWinMetric.tmPitchAndFamily );
1704     pMetric->meItalic       = aWinMetric.tmItalic ? ITALIC_NORMAL : ITALIC_NONE;
1705     pMetric->mnSlant        = 0;
1706 
1707     // device dependend font attributes
1708     pMetric->mbDevice       = (aWinMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
1709     pMetric->mbScalableFont = (aWinMetric.tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) != 0;
1710     if( pMetric->mbScalableFont )
1711     {
1712         // check if there are kern pairs
1713         // TODO: does this work with GPOS kerning?
1714         DWORD nKernPairs = ::GetKerningPairsA( mhDC, 0, NULL );
1715         pMetric->mbKernableFont = (nKernPairs > 0);
1716     }
1717     else
1718     {
1719         // bitmap fonts cannot be rotated directly
1720         pMetric->mnOrientation  = 0;
1721         // bitmap fonts have no kerning
1722         pMetric->mbKernableFont = false;
1723     }
1724 
1725     // transformation dependend font metrics
1726     pMetric->mnWidth        = static_cast<int>( mfFontScale * aWinMetric.tmAveCharWidth );
1727     pMetric->mnIntLeading   = static_cast<int>( mfFontScale * aWinMetric.tmInternalLeading );
1728     pMetric->mnExtLeading   = static_cast<int>( mfFontScale * aWinMetric.tmExternalLeading );
1729     pMetric->mnAscent       = static_cast<int>( mfFontScale * aWinMetric.tmAscent );
1730     pMetric->mnDescent      = static_cast<int>( mfFontScale * aWinMetric.tmDescent );
1731 
1732     // #107888# improved metric compatibility for Asian fonts...
1733     // TODO: assess workaround below for CWS >= extleading
1734     // TODO: evaluate use of aWinMetric.sTypo* members for CJK
1735     if( mpWinFontData[nFallbackLevel] && mpWinFontData[nFallbackLevel]->SupportsCJK() )
1736     {
1737         pMetric->mnIntLeading += pMetric->mnExtLeading;
1738 
1739         // #109280# The line height for Asian fonts is too small.
1740         // Therefore we add half of the external leading to the
1741         // ascent, the other half is added to the descent.
1742         const long nHalfTmpExtLeading = pMetric->mnExtLeading / 2;
1743         const long nOtherHalfTmpExtLeading = pMetric->mnExtLeading - nHalfTmpExtLeading;
1744 
1745         // #110641# external leading for Asian fonts.
1746         // The factor 0.3 has been confirmed with experiments.
1747         long nCJKExtLeading = static_cast<long>(0.30 * (pMetric->mnAscent + pMetric->mnDescent));
1748         nCJKExtLeading -= pMetric->mnExtLeading;
1749         pMetric->mnExtLeading = (nCJKExtLeading > 0) ? nCJKExtLeading : 0;
1750 
1751         pMetric->mnAscent   += nHalfTmpExtLeading;
1752         pMetric->mnDescent  += nOtherHalfTmpExtLeading;
1753     }
1754 
1755     pMetric->mnMinKashida = GetMinKashidaWidth();
1756 }
1757 
1758 // -----------------------------------------------------------------------
1759 
1760 int CALLBACK SalEnumCharSetsProcExA( const ENUMLOGFONTEXA* pLogFont,
1761                                      const NEWTEXTMETRICEXA* /*pMetric*/,
1762                                      DWORD /*nFontType*/, LPARAM lParam )
1763 {
1764     WinSalGraphics* pData = (WinSalGraphics*)lParam;
1765     // Charset already in the list?
1766     for ( BYTE i = 0; i < pData->mnFontCharSetCount; i++ )
1767     {
1768         if ( pData->mpFontCharSets[i] == pLogFont->elfLogFont.lfCharSet )
1769             return 1;
1770     }
1771     pData->mpFontCharSets[pData->mnFontCharSetCount] = pLogFont->elfLogFont.lfCharSet;
1772     pData->mnFontCharSetCount++;
1773     return 1;
1774 }
1775 
1776 // -----------------------------------------------------------------------
1777 
1778 static void ImplGetAllFontCharSets( WinSalGraphics* pData )
1779 {
1780     if ( !pData->mpFontCharSets )
1781         pData->mpFontCharSets = new BYTE[256];
1782 
1783     LOGFONTA aLogFont;
1784     memset( &aLogFont, 0, sizeof( aLogFont ) );
1785     aLogFont.lfCharSet = DEFAULT_CHARSET;
1786     GetTextFaceA( pData->mhDC, sizeof( aLogFont.lfFaceName ), aLogFont.lfFaceName );
1787     EnumFontFamiliesExA( pData->mhDC, &aLogFont, (FONTENUMPROCA)SalEnumCharSetsProcExA,
1788                          (LPARAM)(void*)pData, 0 );
1789 }
1790 
1791 // -----------------------------------------------------------------------
1792 
1793 static void ImplAddKerningPairs( WinSalGraphics* pData )
1794 {
1795     sal_uLong nPairs = ::GetKerningPairsA( pData->mhDC, 0, NULL );
1796     if ( !nPairs )
1797         return;
1798 
1799     CHARSETINFO aInfo;
1800     if ( !TranslateCharsetInfo( (DWORD*)(sal_uLong)GetTextCharset( pData->mhDC ), &aInfo, TCI_SRCCHARSET ) )
1801         return;
1802 
1803     if ( !pData->mpFontKernPairs )
1804         pData->mpFontKernPairs = new KERNINGPAIR[nPairs];
1805     else
1806     {
1807         KERNINGPAIR* pOldPairs = pData->mpFontKernPairs;
1808         pData->mpFontKernPairs = new KERNINGPAIR[nPairs+pData->mnFontKernPairCount];
1809         memcpy( pData->mpFontKernPairs, pOldPairs,
1810                 pData->mnFontKernPairCount*sizeof( KERNINGPAIR ) );
1811         delete[] pOldPairs;
1812     }
1813 
1814     UINT            nCP = aInfo.ciACP;
1815     sal_uLong           nOldPairs = pData->mnFontKernPairCount;
1816     KERNINGPAIR*    pTempPair = pData->mpFontKernPairs+pData->mnFontKernPairCount;
1817     nPairs = ::GetKerningPairsA( pData->mhDC, nPairs, pTempPair );
1818     for ( sal_uLong i = 0; i < nPairs; i++ )
1819     {
1820         unsigned char   aBuf[2];
1821         wchar_t         nChar;
1822         int             nLen;
1823         sal_Bool            bAdd = TRUE;
1824 
1825         // None-ASCII?, then we must convert the char
1826         if ( (pTempPair->wFirst > 125) || (pTempPair->wFirst == 92) )
1827         {
1828             if ( pTempPair->wFirst < 256 )
1829             {
1830                 aBuf[0] = (unsigned char)pTempPair->wFirst;
1831                 nLen = 1;
1832             }
1833             else
1834             {
1835                 aBuf[0] = (unsigned char)(pTempPair->wFirst >> 8);
1836                 aBuf[1] = (unsigned char)(pTempPair->wFirst & 0xFF);
1837                 nLen = 2;
1838             }
1839             if ( MultiByteToWideChar( nCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
1840                                       (const char*)aBuf, nLen, &nChar, 1 ) )
1841                 pTempPair->wFirst = nChar;
1842             else
1843                 bAdd = FALSE;
1844         }
1845         if ( (pTempPair->wSecond > 125) || (pTempPair->wSecond == 92) )
1846         {
1847             if ( pTempPair->wSecond < 256 )
1848             {
1849                 aBuf[0] = (unsigned char)pTempPair->wSecond;
1850                 nLen = 1;
1851             }
1852             else
1853             {
1854                 aBuf[0] = (unsigned char)(pTempPair->wSecond >> 8);
1855                 aBuf[1] = (unsigned char)(pTempPair->wSecond & 0xFF);
1856                 nLen = 2;
1857             }
1858             if ( MultiByteToWideChar( nCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
1859                                       (const char*)aBuf, nLen, &nChar, 1 ) )
1860                 pTempPair->wSecond = nChar;
1861             else
1862                 bAdd = FALSE;
1863         }
1864 
1865         // TODO: get rid of linear search!
1866         KERNINGPAIR* pTempPair2 = pData->mpFontKernPairs;
1867         for ( sal_uLong j = 0; j < nOldPairs; j++ )
1868         {
1869             if ( (pTempPair2->wFirst == pTempPair->wFirst) &&
1870                  (pTempPair2->wSecond == pTempPair->wSecond) )
1871             {
1872                 bAdd = FALSE;
1873                 break;
1874             }
1875             pTempPair2++;
1876         }
1877 
1878         if ( bAdd )
1879         {
1880             KERNINGPAIR* pDestPair = pData->mpFontKernPairs+pData->mnFontKernPairCount;
1881             if ( pDestPair != pTempPair )
1882                 memcpy( pDestPair, pTempPair, sizeof( KERNINGPAIR ) );
1883             pData->mnFontKernPairCount++;
1884         }
1885 
1886         pTempPair++;
1887     }
1888 }
1889 
1890 // -----------------------------------------------------------------------
1891 
1892 sal_uLong WinSalGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData* pKernPairs )
1893 {
1894     DBG_ASSERT( sizeof( KERNINGPAIR ) == sizeof( ImplKernPairData ),
1895                 "WinSalGraphics::GetKernPairs(): KERNINGPAIR != ImplKernPairData" );
1896 
1897     if ( mbFontKernInit )
1898     {
1899         if( mpFontKernPairs )
1900         {
1901             delete[] mpFontKernPairs;
1902             mpFontKernPairs = NULL;
1903         }
1904         mnFontKernPairCount = 0;
1905 
1906         KERNINGPAIR* pPairs = NULL;
1907         int nCount = ::GetKerningPairsW( mhDC, 0, NULL );
1908         if( nCount )
1909         {
1910             #ifdef GCP_KERN_HACK
1911             pPairs = new KERNINGPAIR[ nCount+1 ];
1912             mpFontKernPairs = pPairs;
1913             mnFontKernPairCount = nCount;
1914             ::GetKerningPairsW( mhDC, nCount, pPairs );
1915             #else // GCP_KERN_HACK
1916             pPairs = pKernPairs;
1917             nCount = (nCount < nPairs) : nCount : nPairs;
1918             ::GetKerningPairsW( mhDC, nCount, pPairs );
1919             return nCount;
1920             #endif // GCP_KERN_HACK
1921         }
1922 
1923         mbFontKernInit = FALSE;
1924 
1925         std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData );
1926     }
1927 
1928     if( !pKernPairs )
1929         return mnFontKernPairCount;
1930     else if( mpFontKernPairs )
1931     {
1932         if ( nPairs < mnFontKernPairCount )
1933             nPairs = mnFontKernPairCount;
1934         memcpy( pKernPairs, mpFontKernPairs,
1935                 nPairs*sizeof( ImplKernPairData ) );
1936         return nPairs;
1937     }
1938 
1939     return 0;
1940 }
1941 
1942 // -----------------------------------------------------------------------
1943 
1944 const ImplFontCharMap* WinSalGraphics::GetImplFontCharMap() const
1945 {
1946     if( !mpWinFontData[0] )
1947         return ImplFontCharMap::GetDefaultMap();
1948     return mpWinFontData[0]->GetImplFontCharMap();
1949 }
1950 
1951 // -----------------------------------------------------------------------
1952 
1953 int CALLBACK SalEnumFontsProcExA( const ENUMLOGFONTEXA* pLogFont,
1954                                   const NEWTEXTMETRICEXA* pMetric,
1955                                   DWORD nFontType, LPARAM lParam )
1956 {
1957     ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam;
1958     if ( !pInfo->mpName )
1959     {
1960         // Ignore vertical fonts
1961         if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
1962         {
1963             if ( !pInfo->mbImplSalCourierNew )
1964                 pInfo->mbImplSalCourierNew = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0;
1965             if ( !pInfo->mbImplSalCourierScalable )
1966                 pInfo->mbCourier = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0;
1967             else
1968                 pInfo->mbCourier = FALSE;
1969             String aName( ImplSalGetUniString( pLogFont->elfLogFont.lfFaceName ) );
1970             pInfo->mpName = &aName;
1971             strncpy( pInfo->mpLogFontA->lfFaceName, pLogFont->elfLogFont.lfFaceName, LF_FACESIZE );
1972             pInfo->mpLogFontA->lfCharSet = pLogFont->elfLogFont.lfCharSet;
1973             EnumFontFamiliesExA( pInfo->mhDC, pInfo->mpLogFontA, (FONTENUMPROCA)SalEnumFontsProcExA,
1974                                  (LPARAM)(void*)pInfo, 0 );
1975             pInfo->mpLogFontA->lfFaceName[0] = '\0';
1976             pInfo->mpLogFontA->lfCharSet = DEFAULT_CHARSET;
1977             pInfo->mpName = NULL;
1978             pInfo->mbCourier = FALSE;
1979         }
1980     }
1981     else
1982     {
1983         // ignore non-scalable non-device font on printer
1984         if( pInfo->mbPrinter )
1985             if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) )
1986                 return 1;
1987 
1988         ImplWinFontData* pData = ImplLogMetricToDevFontDataA( pLogFont, &(pMetric->ntmTm), nFontType );
1989         pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
1990 
1991         // prefer the system character set, so that we get as much as
1992         // possible important characters. In the other case we could only
1993         // display a limited set of characters (#87309#)
1994         if ( pInfo->mnPreferedCharSet == pLogFont->elfLogFont.lfCharSet )
1995             pData->mnQuality += 100;
1996 
1997         // knowing Courier to be scalable is nice
1998         if( pInfo->mbCourier )
1999             pInfo->mbImplSalCourierScalable |= pData->IsScalable();
2000 
2001         pInfo->mpList->Add( pData );
2002     }
2003 
2004     return 1;
2005 }
2006 
2007 // -----------------------------------------------------------------------
2008 
2009 int CALLBACK SalEnumFontsProcExW( const ENUMLOGFONTEXW* pLogFont,
2010                                   const NEWTEXTMETRICEXW* pMetric,
2011                                   DWORD nFontType, LPARAM lParam )
2012 {
2013     ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam;
2014     if ( !pInfo->mpName )
2015     {
2016         // Ignore vertical fonts
2017         if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
2018         {
2019             if ( !pInfo->mbImplSalCourierNew )
2020                 pInfo->mbImplSalCourierNew = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0;
2021             if ( !pInfo->mbImplSalCourierScalable )
2022                 pInfo->mbCourier = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0;
2023             else
2024                 pInfo->mbCourier = FALSE;
2025             String aName( reinterpret_cast<const sal_Unicode*>(pLogFont->elfLogFont.lfFaceName) );
2026             pInfo->mpName = &aName;
2027             memcpy( pInfo->mpLogFontW->lfFaceName, pLogFont->elfLogFont.lfFaceName, (aName.Len()+1)*sizeof( wchar_t ) );
2028             pInfo->mpLogFontW->lfCharSet = pLogFont->elfLogFont.lfCharSet;
2029             EnumFontFamiliesExW( pInfo->mhDC, pInfo->mpLogFontW, (FONTENUMPROCW)SalEnumFontsProcExW,
2030                                  (LPARAM)(void*)pInfo, 0 );
2031             pInfo->mpLogFontW->lfFaceName[0] = '\0';
2032             pInfo->mpLogFontW->lfCharSet = DEFAULT_CHARSET;
2033             pInfo->mpName = NULL;
2034             pInfo->mbCourier = FALSE;
2035         }
2036     }
2037     else
2038     {
2039         // ignore non-scalable non-device font on printer
2040         if( pInfo->mbPrinter )
2041             if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) )
2042                 return 1;
2043 
2044         ImplWinFontData* pData = ImplLogMetricToDevFontDataW( pLogFont, &(pMetric->ntmTm), nFontType );
2045         pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
2046 
2047         // knowing Courier to be scalable is nice
2048         if( pInfo->mbCourier )
2049             pInfo->mbImplSalCourierScalable |= pData->IsScalable();
2050 
2051         pInfo->mpList->Add( pData );
2052     }
2053 
2054     return 1;
2055 }
2056 
2057 // -----------------------------------------------------------------------
2058 
2059 struct TempFontItem
2060 {
2061     ::rtl::OUString maFontFilePath;
2062     ::rtl::OString maResourcePath;
2063     TempFontItem* mpNextItem;
2064 };
2065 
2066 #ifdef FR_PRIVATE
2067 static int WINAPI __AddFontResourceExW( LPCWSTR lpszfileName, DWORD fl, PVOID pdv )
2068 {
2069     typedef int (WINAPI *AddFontResourceExW_FUNC)(LPCWSTR, DWORD, PVOID );
2070 
2071     static AddFontResourceExW_FUNC  pFunc = NULL;
2072     static HMODULE                  hmGDI = NULL;
2073 
2074     if ( !pFunc && !hmGDI )
2075     {
2076         hmGDI = GetModuleHandleA( "GDI32" );
2077         if ( hmGDI )
2078             pFunc = reinterpret_cast<AddFontResourceExW_FUNC>( GetProcAddress( hmGDI, "AddFontResourceExW" ) );
2079     }
2080 
2081     if ( pFunc )
2082         return pFunc( lpszfileName, fl, pdv );
2083     else
2084     {
2085         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
2086         return 0;
2087     }
2088 }
2089 #endif
2090 
2091 bool ImplAddTempFont( SalData& rSalData, const String& rFontFileURL )
2092 {
2093     int nRet = 0;
2094     ::rtl::OUString aUSytemPath;
2095     OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
2096 
2097 #ifdef FR_PRIVATE
2098     nRet = __AddFontResourceExW( reinterpret_cast<LPCWSTR>(aUSytemPath.getStr()), FR_PRIVATE, NULL );
2099 #endif
2100 
2101     if ( !nRet )
2102     {
2103         static int nCounter = 0;
2104         char aFileName[] = "soAA.fot";
2105         aFileName[2] = sal::static_int_cast<char>('A' + (15 & (nCounter>>4)));
2106         aFileName[3] = sal::static_int_cast<char>('A' + (15 & nCounter));
2107         char aResourceName[512];
2108         int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16;
2109         int nLen = ::GetTempPathA( nMaxLen, aResourceName );
2110         ::strncpy( aResourceName + nLen, aFileName, sizeof( aResourceName )- nLen );
2111         // security: end buffer in any case
2112         aResourceName[ (sizeof(aResourceName)/sizeof(*aResourceName))-1 ] = 0;
2113         ::DeleteFileA( aResourceName );
2114 
2115         rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
2116         ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
2117         // TODO: font should be private => need to investigate why it doesn't work then
2118         if( !::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL ) )
2119             return false;
2120         ++nCounter;
2121 
2122         nRet = ::AddFontResourceA( aResourceName );
2123         if( nRet > 0 )
2124         {
2125             TempFontItem* pNewItem = new TempFontItem;
2126             pNewItem->maResourcePath = rtl::OString( aResourceName );
2127             pNewItem->maFontFilePath = aUSytemPath.getStr();
2128             pNewItem->mpNextItem = rSalData.mpTempFontItem;
2129             rSalData.mpTempFontItem = pNewItem;
2130         }
2131     }
2132 
2133     return (nRet > 0);
2134 }
2135 
2136 // -----------------------------------------------------------------------
2137 
2138 void ImplReleaseTempFonts( SalData& rSalData )
2139 {
2140     int nCount = 0;
2141     while( TempFontItem* p = rSalData.mpTempFontItem )
2142     {
2143         ++nCount;
2144         if( p->maResourcePath.getLength() )
2145         {
2146             const char* pResourcePath = p->maResourcePath.getStr();
2147             ::RemoveFontResourceA( pResourcePath );
2148             ::DeleteFileA( pResourcePath );
2149         }
2150         else
2151         {
2152             ::RemoveFontResourceW( reinterpret_cast<LPCWSTR>(p->maFontFilePath.getStr()) );
2153         }
2154 
2155         rSalData.mpTempFontItem = p->mpNextItem;
2156         delete p;
2157     }
2158 
2159 #ifndef FR_PRIVATE
2160     // notify every other application
2161     // unless the temp fonts were installed as private fonts
2162     if( nCount > 0 )
2163         ::PostMessage( HWND_BROADCAST, WM_FONTCHANGE, 0, NULL );
2164 #endif // FR_PRIVATE
2165 }
2166 
2167 // -----------------------------------------------------------------------
2168 
2169 static bool ImplGetFontAttrFromFile( const String& rFontFileURL,
2170     ImplDevFontAttributes& rDFA )
2171 {
2172     ::rtl::OUString aUSytemPath;
2173     OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
2174 
2175     // get FontAttributes from a *fot file
2176     // TODO: use GetTTGlobalFontInfo() to access the font directly
2177     rDFA.mnQuality    = 1000;
2178     rDFA.mbDevice     = true;
2179     rDFA.meFamily     = FAMILY_DONTKNOW;
2180     rDFA.meWidthType  = WIDTH_DONTKNOW;
2181     rDFA.meWeight     = WEIGHT_DONTKNOW;
2182     rDFA.meItalic     = ITALIC_DONTKNOW;
2183     rDFA.mePitch      = PITCH_DONTKNOW;;
2184     rDFA.mbSubsettable= true;
2185     rDFA.mbEmbeddable = false;
2186 
2187     // Create temporary file name
2188     char aFileName[] = "soAAT.fot";
2189     char aResourceName[512];
2190     int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16;
2191     int nLen = ::GetTempPathA( nMaxLen, aResourceName );
2192     ::strncpy( aResourceName + nLen, aFileName, Max( 0, nMaxLen - nLen ));
2193     ::DeleteFileA( aResourceName );
2194 
2195     // Create font resource file (typically with a .fot file name extension).
2196     rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
2197     ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
2198     ::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL );
2199 
2200     // Open and read the font resource file
2201     rtl::OUString aFotFileName = rtl::OStringToOUString( aResourceName, osl_getThreadTextEncoding() );
2202     osl::FileBase::getFileURLFromSystemPath( aFotFileName, aFotFileName );
2203     osl::File aFotFile( aFotFileName );
2204     osl::FileBase::RC aError = aFotFile.open( osl_File_OpenFlag_Read );
2205     if( aError != osl::FileBase::E_None )
2206         return false;
2207 
2208     sal_uInt64  nBytesRead = 0;
2209     char        aBuffer[4096];
2210     aFotFile.read( aBuffer, sizeof( aBuffer ), nBytesRead );
2211     // clean up temporary resource file
2212     aFotFile.close();
2213     ::DeleteFileA( aResourceName );
2214 
2215     // retrieve font family name from byte offset 0x4F6
2216     int i = 0x4F6;
2217     int nNameOfs = i;
2218     while( (i < nBytesRead) && (aBuffer[i++] != 0) );
2219     // skip full name
2220     while( (i < nBytesRead) && (aBuffer[i++] != 0) );
2221     // retrieve font style name
2222     int nStyleOfs = i;
2223     while( (i < nBytesRead) && (aBuffer[i++] != 0) );
2224     if( i >= nBytesRead )
2225         return false;
2226 
2227     // convert byte strings to unicode
2228     rDFA.maName      = String( aBuffer + nNameOfs, osl_getThreadTextEncoding() );
2229     rDFA.maStyleName = String( aBuffer + nStyleOfs, osl_getThreadTextEncoding() );
2230 
2231     // byte offset 0x4C7: OS2_fsSelection
2232     const char nFSS = aBuffer[ 0x4C7 ];
2233     if( nFSS & 0x01 )   // italic
2234         rDFA.meItalic = ITALIC_NORMAL;
2235     //if( nFSS & 0x20 )   // bold
2236     //   rDFA.meWeight = WEIGHT_BOLD;
2237     if( nFSS & 0x40 )   // regular
2238     {
2239         rDFA.meWeight = WEIGHT_NORMAL;
2240         rDFA.meItalic = ITALIC_NONE;
2241     }
2242 
2243     // byte offsets 0x4D7/0x4D8: wingdi's FW_WEIGHT
2244     int nWinWeight = (aBuffer[0x4D7] & 0xFF) + ((aBuffer[0x4D8] & 0xFF) << 8);
2245     rDFA.meWeight = ImplWeightToSal( nWinWeight );
2246 
2247     rDFA.mbSymbolFlag = false;          // TODO
2248     rDFA.mePitch      = PITCH_DONTKNOW; // TODO
2249 
2250     // byte offset 0x4DE: pitch&family
2251     rDFA.meFamily = ImplFamilyToSal( aBuffer[0x4DE] );
2252 
2253     // byte offsets 0x4C8/0x4C9: emunits
2254     // byte offsets 0x4CE/0x4CF: winascent
2255     // byte offsets 0x4D0/0x4D1: winascent+windescent-emunits
2256     // byte offsets 0x4DF/0x4E0: avgwidth
2257     //...
2258 
2259     return true;
2260 }
2261 
2262 // -----------------------------------------------------------------------
2263 
2264 bool WinSalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
2265     const String& rFontFileURL, const String& rFontName )
2266 {
2267     RTL_LOGFILE_TRACE1( "WinSalGraphics::AddTempDevFont(): %s", rtl::OUStringToOString( rFontFileURL, RTL_TEXTENCODING_UTF8 ).getStr() );
2268 
2269     ImplDevFontAttributes aDFA;
2270     aDFA.maName = rFontName;
2271     aDFA.mnQuality    = 1000;
2272     aDFA.mbDevice     = true;
2273 
2274     // Search Font Name in Cache
2275     if( !rFontName.Len() && mpFontAttrCache )
2276         aDFA = mpFontAttrCache->GetFontAttr( rFontFileURL );
2277 
2278     // Retrieve font name from font resource
2279     if( !aDFA.maName.Len() )
2280     {
2281         ImplGetFontAttrFromFile( rFontFileURL, aDFA );
2282         if( mpFontAttrCache && aDFA.maName.Len() )
2283             mpFontAttrCache->AddFontAttr( rFontFileURL, aDFA );
2284     }
2285 
2286     if ( !aDFA.maName.Len() )
2287         return false;
2288 
2289     // remember temp font for cleanup later
2290     if( !ImplAddTempFont( *GetSalData(), rFontFileURL ) )
2291         return false;
2292 
2293     UINT nPreferedCharSet = DEFAULT_CHARSET;
2294 
2295     // create matching FontData struct
2296     aDFA.mbSymbolFlag = false; // TODO: how to know it without accessing the font?
2297     aDFA.meFamily     = FAMILY_DONTKNOW;
2298     aDFA.meWidthType  = WIDTH_DONTKNOW;
2299     aDFA.meWeight     = WEIGHT_DONTKNOW;
2300     aDFA.meItalic     = ITALIC_DONTKNOW;
2301     aDFA.mePitch      = PITCH_DONTKNOW;;
2302     aDFA.mbSubsettable= true;
2303     aDFA.mbEmbeddable = false;
2304 
2305     /*
2306     // TODO: improve ImplDevFontAttributes using the "font resource file"
2307     aDFS.maName = // using "FONTRES:" from file
2308     if( rFontName != aDFS.maName )
2309         aDFS.maMapName = aFontName;
2310     */
2311 
2312     ImplWinFontData* pFontData = new ImplWinFontData( aDFA, 0,
2313         sal::static_int_cast<BYTE>(nPreferedCharSet),
2314         sal::static_int_cast<BYTE>(TMPF_VECTOR|TMPF_TRUETYPE) );
2315     pFontData->SetFontId( reinterpret_cast<sal_IntPtr>(pFontData) );
2316     pFontList->Add( pFontData );
2317     return true;
2318 }
2319 
2320 // -----------------------------------------------------------------------
2321 
2322 void WinSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
2323 {
2324     // make sure all fonts are registered at least temporarily
2325     static bool bOnce = true;
2326     if( bOnce )
2327     {
2328         bOnce = false;
2329 
2330         // determine font path
2331         // since we are only interested in fonts that could not be
2332         // registered before because of missing administration rights
2333         // only the font path of the user installation is needed
2334         ::rtl::OUString aPath;
2335         osl_getExecutableFile( &aPath.pData );
2336         ::rtl::OUString aExecutableFile( aPath );
2337         aPath = aPath.copy( 0, aPath.lastIndexOf('/') );
2338         String aFontDirUrl = aPath.copy( 0, aPath.lastIndexOf('/') );
2339         aFontDirUrl += String( RTL_CONSTASCII_USTRINGPARAM("/Basis/share/fonts/truetype") );
2340 
2341         // collect fonts in font path that could not be registered
2342         osl::Directory aFontDir( aFontDirUrl );
2343         osl::FileBase::RC rcOSL = aFontDir.open();
2344         if( rcOSL == osl::FileBase::E_None )
2345         {
2346             osl::DirectoryItem aDirItem;
2347             String aEmptyString;
2348 
2349             ::rtl::OUString aBootStrap;
2350             rtl::Bootstrap::get( String( RTL_CONSTASCII_USTRINGPARAM( "BRAND_BASE_DIR" ) ), aBootStrap );
2351             aBootStrap += String( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
2352             rtl::Bootstrap aBootstrap( aBootStrap );
2353             ::rtl::OUString aUserPath;
2354             aBootstrap.getFrom( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserInstallation" ) ), aUserPath );
2355             aUserPath += String( RTL_CONSTASCII_USTRINGPARAM("/user/config/fontnames.dat") );
2356             String aBaseURL = aPath.copy( 0, aPath.lastIndexOf('/')+1 );
2357             mpFontAttrCache = new ImplFontAttrCache( aUserPath, aBaseURL );
2358 
2359             while( aFontDir.getNextItem( aDirItem, 10 ) == osl::FileBase::E_None )
2360             {
2361                 osl::FileStatus aFileStatus( FileStatusMask_FileURL );
2362                 rcOSL = aDirItem.getFileStatus( aFileStatus );
2363                 if ( rcOSL == osl::FileBase::E_None )
2364                     AddTempDevFont( pFontList, aFileStatus.getFileURL(), aEmptyString );
2365             }
2366 
2367             delete mpFontAttrCache; // destructor rewrites the cache file if needed
2368             mpFontAttrCache = NULL;
2369         }
2370     }
2371 
2372     ImplEnumInfo aInfo;
2373     aInfo.mhDC          = mhDC;
2374     aInfo.mpList        = pFontList;
2375     aInfo.mpName        = NULL;
2376     aInfo.mpLogFontA    = NULL;
2377     aInfo.mpLogFontW    = NULL;
2378     aInfo.mbCourier     = false;
2379     aInfo.mbPrinter     = mbPrinter;
2380     aInfo.mnFontCount   = 0;
2381     if ( !mbPrinter )
2382     {
2383         aInfo.mbImplSalCourierScalable  = false;
2384         aInfo.mbImplSalCourierNew       = false;
2385     }
2386     else
2387     {
2388         aInfo.mbImplSalCourierScalable  = true;
2389         aInfo.mbImplSalCourierNew       = true;
2390     }
2391 
2392     aInfo.mnPreferedCharSet = DEFAULT_CHARSET;
2393     DWORD nCP = GetACP();
2394     CHARSETINFO aCharSetInfo;
2395     if ( TranslateCharsetInfo( (DWORD*)nCP, &aCharSetInfo, TCI_SRCCODEPAGE ) )
2396         aInfo.mnPreferedCharSet = aCharSetInfo.ciCharset;
2397 
2398     LOGFONTW aLogFont;
2399     memset( &aLogFont, 0, sizeof( aLogFont ) );
2400     aLogFont.lfCharSet = DEFAULT_CHARSET;
2401     aInfo.mpLogFontW = &aLogFont;
2402     EnumFontFamiliesExW( mhDC, &aLogFont,
2403             (FONTENUMPROCW)SalEnumFontsProcExW, (LPARAM)(void*)&aInfo, 0 );
2404 
2405     // Feststellen, was es fuer Courier-Schriften auf dem Bildschirm gibt,
2406     // um in SetFont() evt. Courier auf Courier New zu mappen
2407     if ( !mbPrinter )
2408     {
2409         bImplSalCourierScalable = aInfo.mbImplSalCourierScalable;
2410         bImplSalCourierNew      = aInfo.mbImplSalCourierNew;
2411     }
2412 
2413     // set glyph fallback hook
2414     static WinGlyphFallbackSubstititution aSubstFallback( mhDC );
2415     pFontList->SetFallbackHook( &aSubstFallback );
2416 }
2417 
2418 // ----------------------------------------------------------------------------
2419 
2420 void WinSalGraphics::GetDevFontSubstList( OutputDevice* )
2421 {}
2422 
2423 // -----------------------------------------------------------------------
2424 
2425 sal_Bool WinSalGraphics::GetGlyphBoundRect( long nIndex, Rectangle& rRect )
2426 {
2427     HDC hDC = mhDC;
2428 
2429     // use unity matrix
2430     MAT2 aMat;
2431     aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
2432     aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
2433 
2434     UINT nGGOFlags = GGO_METRICS;
2435     if( !(nIndex & GF_ISCHAR) )
2436         nGGOFlags |= GGO_GLYPH_INDEX;
2437     nIndex &= GF_IDXMASK;
2438 
2439     GLYPHMETRICS aGM;
2440     aGM.gmptGlyphOrigin.x = aGM.gmptGlyphOrigin.y = 0;
2441     aGM.gmBlackBoxX = aGM.gmBlackBoxY = 0;
2442     DWORD nSize = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags, &aGM, 0, NULL, &aMat );
2443     if( nSize == GDI_ERROR )
2444         return false;
2445 
2446     rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
2447         Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
2448     rRect.Left()    = static_cast<int>( mfFontScale * rRect.Left() );
2449     rRect.Right()   = static_cast<int>( mfFontScale * rRect.Right() );
2450     rRect.Top()     = static_cast<int>( mfFontScale * rRect.Top() );
2451     rRect.Bottom()  = static_cast<int>( mfFontScale * rRect.Bottom() );
2452     return true;
2453 }
2454 
2455 // -----------------------------------------------------------------------
2456 
2457 sal_Bool WinSalGraphics::GetGlyphOutline( long nIndex,
2458     ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
2459 {
2460     rB2DPolyPoly.clear();
2461 
2462     HDC  hDC = mhDC;
2463 
2464     // use unity matrix
2465     MAT2 aMat;
2466     aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
2467     aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
2468 
2469     UINT nGGOFlags = GGO_NATIVE;
2470     if( !(nIndex & GF_ISCHAR) )
2471         nGGOFlags |= GGO_GLYPH_INDEX;
2472     nIndex &= GF_IDXMASK;
2473 
2474     GLYPHMETRICS aGlyphMetrics;
2475     const DWORD nSize1 = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
2476     if( !nSize1 )       // blank glyphs are ok
2477         return TRUE;
2478     else if( nSize1 == GDI_ERROR )
2479         return FALSE;
2480 
2481     BYTE*   pData = new BYTE[ nSize1 ];
2482     const DWORD nSize2 = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags,
2483               &aGlyphMetrics, nSize1, pData, &aMat );
2484 
2485     if( nSize1 != nSize2 )
2486         return FALSE;
2487 
2488     // TODO: avoid tools polygon by creating B2DPolygon directly
2489     int     nPtSize = 512;
2490     Point*  pPoints = new Point[ nPtSize ];
2491     BYTE*   pFlags = new BYTE[ nPtSize ];
2492 
2493     TTPOLYGONHEADER* pHeader = (TTPOLYGONHEADER*)pData;
2494     while( (BYTE*)pHeader < pData+nSize2 )
2495     {
2496         // only outline data is interesting
2497         if( pHeader->dwType != TT_POLYGON_TYPE )
2498             break;
2499 
2500         // get start point; next start points are end points
2501         // of previous segment
2502         USHORT nPnt = 0;
2503 
2504         long nX = IntTimes256FromFixed( pHeader->pfxStart.x );
2505         long nY = IntTimes256FromFixed( pHeader->pfxStart.y );
2506         pPoints[ nPnt ] = Point( nX, nY );
2507         pFlags[ nPnt++ ] = POLY_NORMAL;
2508 
2509         bool bHasOfflinePoints = false;
2510         TTPOLYCURVE* pCurve = (TTPOLYCURVE*)( pHeader + 1 );
2511         pHeader = (TTPOLYGONHEADER*)( (BYTE*)pHeader + pHeader->cb );
2512         while( (BYTE*)pCurve < (BYTE*)pHeader )
2513         {
2514             int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx;
2515             if( nPtSize < nNeededSize )
2516             {
2517                 Point* pOldPoints = pPoints;
2518                 BYTE* pOldFlags = pFlags;
2519                 nPtSize = 2 * nNeededSize;
2520                 pPoints = new Point[ nPtSize ];
2521                 pFlags = new BYTE[ nPtSize ];
2522                 for( USHORT i = 0; i < nPnt; ++i )
2523                 {
2524                     pPoints[ i ] = pOldPoints[ i ];
2525                     pFlags[ i ] = pOldFlags[ i ];
2526                 }
2527                 delete[] pOldPoints;
2528                 delete[] pOldFlags;
2529             }
2530 
2531             int i = 0;
2532             if( TT_PRIM_LINE == pCurve->wType )
2533             {
2534                 while( i < pCurve->cpfx )
2535                 {
2536                     nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2537                     nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2538                     ++i;
2539                     pPoints[ nPnt ] = Point( nX, nY );
2540                     pFlags[ nPnt ] = POLY_NORMAL;
2541                     ++nPnt;
2542                 }
2543             }
2544             else if( TT_PRIM_QSPLINE == pCurve->wType )
2545             {
2546                 bHasOfflinePoints = true;
2547                 while( i < pCurve->cpfx )
2548                 {
2549                     // get control point of quadratic bezier spline
2550                     nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2551                     nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2552                     ++i;
2553                     Point aControlP( nX, nY );
2554 
2555                     // calculate first cubic control point
2556                     // P0 = 1/3 * (PBeg + 2 * PQControl)
2557                     nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X();
2558                     nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y();
2559                     pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
2560                     pFlags[ nPnt+0 ] = POLY_CONTROL;
2561 
2562                     // calculate endpoint of segment
2563                     nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2564                     nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2565 
2566                     if ( i+1 >= pCurve->cpfx )
2567                     {
2568                         // endpoint is either last point in segment => advance
2569                         ++i;
2570                     }
2571                     else
2572                     {
2573                         // or endpoint is the middle of two control points
2574                         nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x );
2575                         nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y );
2576                         nX = (nX + 1) / 2;
2577                         nY = (nY + 1) / 2;
2578                         // no need to advance, because the current point
2579                         // is the control point in next bezier spline
2580                     }
2581 
2582                     pPoints[ nPnt+2 ] = Point( nX, nY );
2583                     pFlags[ nPnt+2 ] = POLY_NORMAL;
2584 
2585                     // calculate second cubic control point
2586                     // P1 = 1/3 * (PEnd + 2 * PQControl)
2587                     nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X();
2588                     nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y();
2589                     pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
2590                     pFlags[ nPnt+1 ] = POLY_CONTROL;
2591 
2592                     nPnt += 3;
2593                 }
2594             }
2595 
2596             // next curve segment
2597             pCurve = (TTPOLYCURVE*)&pCurve->apfx[ i ];
2598         }
2599 
2600         // end point is start point for closed contour
2601         // disabled, because Polygon class closes the contour itself
2602         // pPoints[nPnt++] = pPoints[0];
2603         // #i35928#
2604         // Added again, but add only when not yet closed
2605         if(pPoints[nPnt - 1] != pPoints[0])
2606         {
2607             if( bHasOfflinePoints )
2608                 pFlags[nPnt] = pFlags[0];
2609 
2610             pPoints[nPnt++] = pPoints[0];
2611         }
2612 
2613         // convert y-coordinates W32 -> VCL
2614         for( int i = 0; i < nPnt; ++i )
2615             pPoints[i].Y() = -pPoints[i].Y();
2616 
2617         // insert into polypolygon
2618         Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : NULL) );
2619         // convert to B2DPolyPolygon
2620         // TODO: get rid of the intermediate PolyPolygon
2621         rB2DPolyPoly.append( aPoly.getB2DPolygon() );
2622     }
2623 
2624     delete[] pPoints;
2625     delete[] pFlags;
2626 
2627     delete[] pData;
2628 
2629     // rescaling needed for the PolyPolygon conversion
2630     if( rB2DPolyPoly.count() )
2631     {
2632         const double fFactor(mfFontScale/256);
2633         rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fFactor, fFactor));
2634     }
2635 
2636     return TRUE;
2637 }
2638 
2639 // -----------------------------------------------------------------------
2640 
2641 class ScopedFont
2642 {
2643 public:
2644     explicit ScopedFont(WinSalGraphics & rData);
2645 
2646     ~ScopedFont();
2647 
2648 private:
2649     WinSalGraphics & m_rData;
2650     HFONT m_hOrigFont;
2651 };
2652 
2653 ScopedFont::ScopedFont(WinSalGraphics & rData): m_rData(rData)
2654 {
2655     m_hOrigFont = m_rData.mhFonts[0];
2656     m_rData.mhFonts[0] = 0; // avoid deletion of current font
2657 }
2658 
2659 ScopedFont::~ScopedFont()
2660 {
2661     if( m_hOrigFont )
2662     {
2663         // restore original font, destroy temporary font
2664         HFONT hTempFont = m_rData.mhFonts[0];
2665         m_rData.mhFonts[0] = m_hOrigFont;
2666         SelectObject( m_rData.mhDC, m_hOrigFont );
2667         DeleteObject( hTempFont );
2668     }
2669 }
2670 
2671 class ScopedTrueTypeFont
2672 {
2673 public:
2674     inline ScopedTrueTypeFont(): m_pFont(0) {}
2675 
2676     ~ScopedTrueTypeFont();
2677 
2678     int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum);
2679 
2680     inline TrueTypeFont * get() const { return m_pFont; }
2681 
2682 private:
2683     TrueTypeFont * m_pFont;
2684 };
2685 
2686 ScopedTrueTypeFont::~ScopedTrueTypeFont()
2687 {
2688     if (m_pFont != 0)
2689         CloseTTFont(m_pFont);
2690 }
2691 
2692 int ScopedTrueTypeFont::open(void * pBuffer, sal_uInt32 nLen,
2693                              sal_uInt32 nFaceNum)
2694 {
2695     OSL_ENSURE(m_pFont == 0, "already open");
2696     return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont);
2697 }
2698 
2699 sal_Bool WinSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
2700     const ImplFontData* pFont, long* pGlyphIDs, sal_uInt8* pEncoding,
2701     sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
2702 {
2703     // TODO: use more of the central font-subsetting code, move stuff there if needed
2704 
2705     // create matching ImplFontSelectData
2706     // we need just enough to get to the font file data
2707     // use height=1000 for easier debugging (to match psprint's font units)
2708     ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2709 
2710     // TODO: much better solution: move SetFont and restoration of old font to caller
2711     ScopedFont aOldFont(*this);
2712     float fScale = 1.0;
2713     HFONT hOldFont = 0;
2714     ImplDoSetFont( &aIFSD, fScale, hOldFont );
2715 
2716     ImplWinFontData* pWinFontData = (ImplWinFontData*)aIFSD.mpFontData;
2717 
2718 #if OSL_DEBUG_LEVEL > 1
2719     // get font metrics
2720     TEXTMETRICA aWinMetric;
2721     if( !::GetTextMetricsA( mhDC, &aWinMetric ) )
2722         return FALSE;
2723 
2724     DBG_ASSERT( !(aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "cannot subset device font" );
2725     DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" );
2726 #endif
2727 
2728     rtl::OUString aSysPath;
2729     if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
2730         return FALSE;
2731     const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
2732     const ByteString aToFile( aSysPath.getStr(), (xub_StrLen)aSysPath.getLength(), aThreadEncoding );
2733 
2734     // check if the font has a CFF-table
2735     const DWORD nCffTag = CalcTag( "CFF " );
2736     const RawFontData aRawCffData( mhDC, nCffTag );
2737     if( aRawCffData.get() )
2738     {
2739         pWinFontData->UpdateFromHDC( mhDC );
2740         const ImplFontCharMap* pCharMap = pWinFontData->GetImplFontCharMap();
2741         pCharMap->AddReference();
2742 
2743         long nRealGlyphIds[ 256 ];
2744         for( int i = 0; i < nGlyphCount; ++i )
2745         {
2746             // TODO: remap notdef glyph if needed
2747             // TODO: use GDI's GetGlyphIndices instead? Does it handle GSUB properly?
2748             sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
2749             if( pGlyphIDs[i] & GF_ISCHAR ) // remaining pseudo-glyphs need to be translated
2750                 nGlyphIdx = pCharMap->GetGlyphIndex( nGlyphIdx );
2751             if( (pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0) // TODO: vertical substitution
2752                 {/*####*/}
2753 
2754             nRealGlyphIds[i] = nGlyphIdx;
2755         }
2756 
2757         pCharMap->DeReference(); // TODO: and and use a RAII object
2758 
2759         // provide a font subset from the CFF-table
2760         FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
2761         rInfo.LoadFont( FontSubsetInfo::CFF_FONT, aRawCffData.get(), aRawCffData.size() );
2762         bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL,
2763                 nRealGlyphIds, pEncoding, nGlyphCount, pGlyphWidths );
2764         fclose( pOutFile );
2765         return bRC;
2766     }
2767 
2768     // get raw font file data
2769     const RawFontData xRawFontData( mhDC, NULL );
2770     if( !xRawFontData.get() )
2771         return FALSE;
2772 
2773     // open font file
2774     sal_uInt32 nFaceNum = 0;
2775     if( !*xRawFontData.get() )  // TTC candidate
2776         nFaceNum = ~0U;  // indicate "TTC font extracts only"
2777 
2778     ScopedTrueTypeFont aSftTTF;
2779     int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
2780     if( nRC != SF_OK )
2781         return FALSE;
2782 
2783     TTGlobalFontInfo aTTInfo;
2784     ::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
2785     rInfo.m_nFontType   = FontSubsetInfo::SFNT_TTF;
2786     rInfo.m_aPSName     = ImplSalGetUniString( aTTInfo.psname );
2787     rInfo.m_nAscent     = aTTInfo.winAscent;
2788     rInfo.m_nDescent    = aTTInfo.winDescent;
2789     rInfo.m_aFontBBox   = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
2790                                     Point( aTTInfo.xMax, aTTInfo.yMax ) );
2791     rInfo.m_nCapHeight  = aTTInfo.yMax; // Well ...
2792 
2793     // subset TTF-glyphs and get their properties
2794     // take care that subset fonts require the NotDef glyph in pos 0
2795     int nOrigCount = nGlyphCount;
2796     sal_uInt16    aShortIDs[ 256 ];
2797     sal_uInt8 aTempEncs[ 256 ];
2798 
2799     int nNotDef=-1, i;
2800     for( i = 0; i < nGlyphCount; ++i )
2801     {
2802         aTempEncs[i] = pEncoding[i];
2803         sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
2804         if( pGlyphIDs[i] & GF_ISCHAR )
2805         {
2806             sal_Unicode cChar = static_cast<sal_Unicode>(nGlyphIdx); // TODO: sal_UCS4
2807             const bool bVertical = ((pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0);
2808             nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical );
2809             if( (nGlyphIdx == 0) && pFont->IsSymbolFont() )
2810             {
2811                 // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
2812                 cChar = (cChar & 0xF000) ? (cChar & 0x00FF) : (cChar | 0xF000);
2813                 nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical );
2814             }
2815         }
2816         aShortIDs[i] = static_cast<sal_uInt16>( nGlyphIdx );
2817         if( !nGlyphIdx )
2818             if( nNotDef < 0 )
2819                 nNotDef = i; // first NotDef glyph found
2820     }
2821 
2822     if( nNotDef != 0 )
2823     {
2824         // add fake NotDef glyph if needed
2825         if( nNotDef < 0 )
2826             nNotDef = nGlyphCount++;
2827 
2828         // NotDef glyph must be in pos 0 => swap glyphids
2829         aShortIDs[ nNotDef ] = aShortIDs[0];
2830         aTempEncs[ nNotDef ] = aTempEncs[0];
2831         aShortIDs[0] = 0;
2832         aTempEncs[0] = 0;
2833     }
2834     DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
2835 
2836     // fill pWidth array
2837     TTSimpleGlyphMetrics* pMetrics =
2838         ::GetTTSimpleGlyphMetrics( aSftTTF.get(), aShortIDs, nGlyphCount, aIFSD.mbVertical );
2839     if( !pMetrics )
2840         return FALSE;
2841     sal_uInt16 nNotDefAdv   = pMetrics[0].adv;
2842     pMetrics[0].adv         = pMetrics[nNotDef].adv;
2843     pMetrics[nNotDef].adv   = nNotDefAdv;
2844     for( i = 0; i < nOrigCount; ++i )
2845         pGlyphWidths[i] = pMetrics[i].adv;
2846     free( pMetrics );
2847 
2848     // write subset into destination file
2849     nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.GetBuffer(), aShortIDs,
2850             aTempEncs, nGlyphCount, 0, NULL, 0 );
2851     return (nRC == SF_OK);
2852 }
2853 
2854 //--------------------------------------------------------------------------
2855 
2856 const void* WinSalGraphics::GetEmbedFontData( const ImplFontData* pFont,
2857     const sal_Unicode* pUnicodes, sal_Int32* pCharWidths,
2858     FontSubsetInfo& rInfo, long* pDataLen )
2859 {
2860     // create matching ImplFontSelectData
2861     // we need just enough to get to the font file data
2862     ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2863 
2864     // TODO: much better solution: move SetFont and restoration of old font to caller
2865     ScopedFont aOldFont(*this);
2866     SetFont( &aIFSD, 0 );
2867 
2868     // get the raw font file data
2869     RawFontData aRawFontData( mhDC );
2870     *pDataLen = aRawFontData.size();
2871     if( !aRawFontData.get() )
2872         return NULL;
2873 
2874     // get important font properties
2875     TEXTMETRICA aTm;
2876     if( !::GetTextMetricsA( mhDC, &aTm ) )
2877         *pDataLen = 0;
2878     const bool bPFA = (*aRawFontData.get() < 0x80);
2879     rInfo.m_nFontType = bPFA ? FontSubsetInfo::TYPE1_PFA : FontSubsetInfo::TYPE1_PFB;
2880     WCHAR aFaceName[64];
2881     int nFNLen = ::GetTextFaceW( mhDC, 64, aFaceName );
2882     // #i59854# strip eventual null byte
2883     while( nFNLen > 0 && aFaceName[nFNLen-1] == 0 )
2884         nFNLen--;
2885     if( nFNLen == 0 )
2886         *pDataLen = 0;
2887     rInfo.m_aPSName     = String( reinterpret_cast<const sal_Unicode*>(aFaceName), sal::static_int_cast<sal_uInt16>(nFNLen) );
2888     rInfo.m_nAscent     = +aTm.tmAscent;
2889     rInfo.m_nDescent    = -aTm.tmDescent;
2890     rInfo.m_aFontBBox   = Rectangle( Point( -aTm.tmOverhang, -aTm.tmDescent ),
2891               Point( aTm.tmMaxCharWidth, aTm.tmAscent+aTm.tmExternalLeading ) );
2892     rInfo.m_nCapHeight  = aTm.tmAscent; // Well ...
2893 
2894     // get individual character widths
2895     for( int i = 0; i < 256; ++i )
2896     {
2897         int nCharWidth = 0;
2898         const sal_Unicode cChar = pUnicodes[i];
2899         if( !::GetCharWidth32W( mhDC, cChar, cChar, &nCharWidth ) )
2900             *pDataLen = 0;
2901         pCharWidths[i] = nCharWidth;
2902     }
2903 
2904     if( !*pDataLen )
2905         return NULL;
2906 
2907     const unsigned char* pData = aRawFontData.steal();
2908     return (void*)pData;
2909 }
2910 
2911 //--------------------------------------------------------------------------
2912 
2913 void WinSalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ )
2914 {
2915     delete[] reinterpret_cast<char*>(const_cast<void*>(pData));
2916 }
2917 
2918 //--------------------------------------------------------------------------
2919 
2920 const Ucs2SIntMap* WinSalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
2921 {
2922     // TODO: even for builtin fonts we get here... why?
2923     if( !pFont->IsEmbeddable() )
2924         return NULL;
2925 
2926     // fill the encoding vector
2927     // currently no nonencoded vector
2928     if( pNonEncoded )
2929         *pNonEncoded = NULL;
2930 
2931     const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>(pFont);
2932     const Ucs2SIntMap* pEncoding = pWinFontData->GetEncodingVector();
2933     if( pEncoding == NULL )
2934     {
2935         Ucs2SIntMap* pNewEncoding = new Ucs2SIntMap;
2936         #if 0
2937         // TODO: get correct encoding vector
2938         GLYPHSET aGlyphSet;
2939         aGlyphSet.cbThis = sizeof(aGlyphSet);
2940         DWORD aW = ::GetFontUnicodeRanges( mhDC, &aGlyphSet);
2941         #else
2942         for( sal_Unicode i = 32; i < 256; ++i )
2943             (*pNewEncoding)[i] = i;
2944         #endif
2945         pWinFontData->SetEncodingVector( pNewEncoding );
2946     pEncoding = pNewEncoding;
2947     }
2948 
2949     return pEncoding;
2950 }
2951 
2952 //--------------------------------------------------------------------------
2953 
2954 void WinSalGraphics::GetGlyphWidths( const ImplFontData* pFont,
2955                                      bool bVertical,
2956                                      Int32Vector& rWidths,
2957                                      Ucs2UIntMap& rUnicodeEnc )
2958 {
2959     // create matching ImplFontSelectData
2960     // we need just enough to get to the font file data
2961     ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2962 
2963     // TODO: much better solution: move SetFont and restoration of old font to caller
2964     ScopedFont aOldFont(*this);
2965 
2966     float fScale = 0.0;
2967     HFONT hOldFont = 0;
2968     ImplDoSetFont( &aIFSD, fScale, hOldFont );
2969 
2970     if( pFont->IsSubsettable() )
2971     {
2972         // get raw font file data
2973         const RawFontData xRawFontData( mhDC );
2974         if( !xRawFontData.get() )
2975             return;
2976 
2977         // open font file
2978         sal_uInt32 nFaceNum = 0;
2979         if( !*xRawFontData.get() )  // TTC candidate
2980             nFaceNum = ~0U;  // indicate "TTC font extracts only"
2981 
2982         ScopedTrueTypeFont aSftTTF;
2983         int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
2984         if( nRC != SF_OK )
2985             return;
2986 
2987         int nGlyphs = GetTTGlyphCount( aSftTTF.get() );
2988         if( nGlyphs > 0 )
2989         {
2990             rWidths.resize(nGlyphs);
2991             std::vector<sal_uInt16> aGlyphIds(nGlyphs);
2992             for( int i = 0; i < nGlyphs; i++ )
2993                 aGlyphIds[i] = sal_uInt16(i);
2994             TTSimpleGlyphMetrics* pMetrics = ::GetTTSimpleGlyphMetrics( aSftTTF.get(),
2995                                                                         &aGlyphIds[0],
2996                                                                         nGlyphs,
2997                                                                         bVertical ? 1 : 0 );
2998             if( pMetrics )
2999             {
3000                 for( int i = 0; i< nGlyphs; i++ )
3001                     rWidths[i] = pMetrics[i].adv;
3002                 free( pMetrics );
3003                 rUnicodeEnc.clear();
3004             }
3005             const ImplWinFontData* pWinFont = static_cast<const ImplWinFontData*>(pFont);
3006             const ImplFontCharMap* pMap = pWinFont->GetImplFontCharMap();
3007             DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" );
3008             pMap->AddReference();
3009 
3010             int nCharCount = pMap->GetCharCount();
3011             sal_uInt32 nChar = pMap->GetFirstChar();
3012             for( int i = 0; i < nCharCount; i++ )
3013             {
3014                 if( nChar < 0x00010000 )
3015                 {
3016                     sal_uInt16 nGlyph = ::MapChar( aSftTTF.get(),
3017                                                    static_cast<sal_Ucs>(nChar),
3018                                                    bVertical ? 1 : 0 );
3019                     if( nGlyph )
3020                         rUnicodeEnc[ static_cast<sal_Unicode>(nChar) ] = nGlyph;
3021                 }
3022                 nChar = pMap->GetNextChar( nChar );
3023             }
3024 
3025             pMap->DeReference(); // TODO: and and use a RAII object
3026         }
3027     }
3028     else if( pFont->IsEmbeddable() )
3029     {
3030         // get individual character widths
3031         rWidths.clear();
3032         rUnicodeEnc.clear();
3033         rWidths.reserve( 224 );
3034         for( sal_Unicode i = 32; i < 256; ++i )
3035         {
3036             int nCharWidth = 0;
3037             if( ::GetCharWidth32W( mhDC, i, i, &nCharWidth ) )
3038             {
3039                 rUnicodeEnc[ i ] = rWidths.size();
3040                 rWidths.push_back( nCharWidth );
3041             }
3042         }
3043     }
3044 }
3045 
3046 //--------------------------------------------------------------------------
3047 
3048 void WinSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
3049 {}
3050 
3051 //--------------------------------------------------------------------------
3052 
3053 SystemFontData WinSalGraphics::GetSysFontData( int nFallbacklevel ) const
3054 {
3055     SystemFontData aSysFontData;
3056 
3057     if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
3058     if (nFallbacklevel < 0 ) nFallbacklevel = 0;
3059 
3060     aSysFontData.nSize = sizeof( SystemFontData );
3061     aSysFontData.hFont = mhFonts[nFallbacklevel];
3062     aSysFontData.bFakeBold = false;
3063     aSysFontData.bFakeItalic = false;
3064     aSysFontData.bAntialias = true;
3065     aSysFontData.bVerticalCharacterType = false;
3066 
3067     OSL_TRACE("\r\n:WinSalGraphics::GetSysFontData(): FontID: %p, Fallback level: %d",
3068               aSysFontData.hFont,
3069               nFallbacklevel);
3070 
3071     return aSysFontData;
3072 }
3073 
3074 //--------------------------------------------------------------------------
3075 
3076