xref: /aoo42x/main/vcl/win/source/gdi/salgdi3.cxx (revision 9f62ea84)
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