xref: /trunk/main/vcl/win/source/gdi/salgdi3.cxx (revision 86e1cf34)
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 
FixedFromDouble(double d)93 inline FIXED FixedFromDouble( double d )
94 {
95     const long l = (long) ( d * 65536. );
96     return *(FIXED*) &l;
97 }
98 
99 // -----------------------------------------------------------------------
100 
IntTimes256FromFixed(FIXED f)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 
ImplFontAttrCache(const String & rFileNameURL,const String & rBaseURL)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 
~ImplFontAttrCache()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 
OptimizeURL(const String & rURL) const220 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 
GetFontAttr(const String & rFontFileName) const229 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 
AddFontAttr(const String & rFontFileName,const ImplDevFontAttributes & rDFA)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 );
~RawFontData()257     			~RawFontData() { delete[] mpRawBytes; }
get() const258     const unsigned char*	get() const { return mpRawBytes; }
steal()259     const unsigned char*	steal() { unsigned char* p = mpRawBytes; mpRawBytes = NULL; return p; }
size() const260     const int				size() const { return mnByteCount; }
261 
262 private:
263     unsigned char*	mpRawBytes;
264     int				mnByteCount;
265 };
266 
RawFontData(HDC hDC,DWORD nTableTag)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
MapCharToLanguage(sal_UCS4 uChar)407 LanguageType MapCharToLanguage( sal_UCS4 uChar )
408 {
409 	// entries marked with default-CJK get replaced with the preferred 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 preferred 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 
WinGlyphFallbackSubstititution(HDC hDC)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?
HasMissingChars(const ImplFontData * pFace,const rtl::OUString & rMissingChars) const499 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 preferred?
FindFontSubstitute(ImplFontSelectData & rFontSelData,rtl::OUString & rMissingChars) const551 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 	bool bFound = false;
609 	for( int i = 0; i < nTestFontCount; ++i )
610 	{
611 		const ImplFontData* pFace = pTestFontList->Get( i );
612 		bFound = HasMissingChars( pFace, rMissingChars );
613 		if( !bFound )
614 			continue;
615 		rFontSelData.maSearchName = pFace->maName;
616 		break;
617 	}
618 
619 	delete pTestFontList;
620 
621 	return bFound;
622 }
623 
624 // =======================================================================
625 
626 struct ImplEnumInfo
627 {
628     HDC                 mhDC;
629     ImplDevFontList*    mpList;
630     String*             mpName;
631     LOGFONTA*           mpLogFontA;
632     LOGFONTW*           mpLogFontW;
633     UINT                mnPreferedCharSet;
634     bool                mbCourier;
635     bool                mbImplSalCourierScalable;
636     bool                mbImplSalCourierNew;
637     bool                mbPrinter;
638     int                 mnFontCount;
639 };
640 
641 // =======================================================================
642 
ImplCharSetToSal(BYTE nCharSet)643 static CharSet ImplCharSetToSal( BYTE nCharSet )
644 {
645     rtl_TextEncoding eTextEncoding;
646 
647     if ( nCharSet == OEM_CHARSET )
648     {
649         UINT nCP = (sal_uInt16)GetOEMCP();
650         switch ( nCP )
651         {
652             // It is unclear why these two (undefined?) code page numbers are
653             // handled specially here:
654             case 1004:  eTextEncoding = RTL_TEXTENCODING_MS_1252; break;
655             case 65400: eTextEncoding = RTL_TEXTENCODING_SYMBOL; break;
656             default:
657                 eTextEncoding = rtl_getTextEncodingFromWindowsCodePage(nCP);
658                 break;
659         };
660     }
661     else
662     {
663         if( nCharSet )
664             eTextEncoding = rtl_getTextEncodingFromWindowsCharset( nCharSet );
665         else
666             eTextEncoding = RTL_TEXTENCODING_UNICODE;
667     }
668 
669     return eTextEncoding;
670 }
671 
672 // -----------------------------------------------------------------------
673 
ImplFamilyToSal(BYTE nFamily)674 static FontFamily ImplFamilyToSal( BYTE nFamily )
675 {
676     switch ( nFamily & 0xF0 )
677     {
678         case FF_DECORATIVE:
679             return FAMILY_DECORATIVE;
680 
681         case FF_MODERN:
682             return FAMILY_MODERN;
683 
684         case FF_ROMAN:
685             return FAMILY_ROMAN;
686 
687         case FF_SCRIPT:
688             return FAMILY_SCRIPT;
689 
690         case FF_SWISS:
691             return FAMILY_SWISS;
692 
693         default:
694             break;
695     }
696 
697     return FAMILY_DONTKNOW;
698 }
699 
700 // -----------------------------------------------------------------------
701 
ImplFamilyToWin(FontFamily eFamily)702 static BYTE ImplFamilyToWin( FontFamily eFamily )
703 {
704     switch ( eFamily )
705     {
706         case FAMILY_DECORATIVE:
707             return FF_DECORATIVE;
708 
709         case FAMILY_MODERN:
710             return FF_MODERN;
711 
712         case FAMILY_ROMAN:
713             return FF_ROMAN;
714 
715         case FAMILY_SCRIPT:
716             return FF_SCRIPT;
717 
718         case FAMILY_SWISS:
719             return FF_SWISS;
720 
721         case FAMILY_SYSTEM:
722             return FF_SWISS;
723 
724         default:
725             break;
726     }
727 
728     return FF_DONTCARE;
729 }
730 
731 // -----------------------------------------------------------------------
732 
ImplWeightToSal(int nWeight)733 static FontWeight ImplWeightToSal( int nWeight )
734 {
735     if ( nWeight <= FW_THIN )
736         return WEIGHT_THIN;
737     else if ( nWeight <= FW_ULTRALIGHT )
738         return WEIGHT_ULTRALIGHT;
739     else if ( nWeight <= FW_LIGHT )
740         return WEIGHT_LIGHT;
741     else if ( nWeight < FW_MEDIUM )
742         return WEIGHT_NORMAL;
743     else if ( nWeight == FW_MEDIUM )
744         return WEIGHT_MEDIUM;
745     else if ( nWeight <= FW_SEMIBOLD )
746         return WEIGHT_SEMIBOLD;
747     else if ( nWeight <= FW_BOLD )
748         return WEIGHT_BOLD;
749     else if ( nWeight <= FW_ULTRABOLD )
750         return WEIGHT_ULTRABOLD;
751     else
752         return WEIGHT_BLACK;
753 }
754 
755 // -----------------------------------------------------------------------
756 
ImplWeightToWin(FontWeight eWeight)757 static int ImplWeightToWin( FontWeight eWeight )
758 {
759     switch ( eWeight )
760     {
761         case WEIGHT_THIN:
762             return FW_THIN;
763 
764         case WEIGHT_ULTRALIGHT:
765             return FW_ULTRALIGHT;
766 
767         case WEIGHT_LIGHT:
768             return FW_LIGHT;
769 
770         case WEIGHT_SEMILIGHT:
771         case WEIGHT_NORMAL:
772             return FW_NORMAL;
773 
774         case WEIGHT_MEDIUM:
775             return FW_MEDIUM;
776 
777         case WEIGHT_SEMIBOLD:
778             return FW_SEMIBOLD;
779 
780         case WEIGHT_BOLD:
781             return FW_BOLD;
782 
783         case WEIGHT_ULTRABOLD:
784             return FW_ULTRABOLD;
785 
786         case WEIGHT_BLACK:
787             return FW_BLACK;
788 
789         default:
790             break;
791     }
792 
793     return 0;
794 }
795 
796 // -----------------------------------------------------------------------
797 
ImplLogPitchToSal(BYTE nPitch)798 inline FontPitch ImplLogPitchToSal( BYTE nPitch )
799 {
800     if ( nPitch & FIXED_PITCH )
801         return PITCH_FIXED;
802     else
803         return PITCH_VARIABLE;
804 }
805 
806 // -----------------------------------------------------------------------
807 
ImplMetricPitchToSal(BYTE nPitch)808 inline FontPitch ImplMetricPitchToSal( BYTE nPitch )
809 {
810     // Sausaecke bei MS !! siehe NT Hilfe
811     if ( !(nPitch & TMPF_FIXED_PITCH) )
812         return PITCH_FIXED;
813     else
814         return PITCH_VARIABLE;
815 }
816 
817 // -----------------------------------------------------------------------
818 
ImplPitchToWin(FontPitch ePitch)819 inline BYTE ImplPitchToWin( FontPitch ePitch )
820 {
821     if ( ePitch == PITCH_FIXED )
822         return FIXED_PITCH;
823     else if ( ePitch == PITCH_VARIABLE )
824         return VARIABLE_PITCH;
825     else
826         return DEFAULT_PITCH;
827 }
828 
829 // -----------------------------------------------------------------------
830 
WinFont2DevFontAttributes(const ENUMLOGFONTEXA & rEnumFont,const NEWTEXTMETRICA & rMetric,DWORD nFontType)831 static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXA& rEnumFont,
832     const NEWTEXTMETRICA& rMetric, DWORD nFontType )
833 {
834     ImplDevFontAttributes aDFA;
835 
836     const LOGFONTA rLogFont = rEnumFont.elfLogFont;
837 
838     // get font face attributes
839     aDFA.meFamily       = ImplFamilyToSal( rLogFont.lfPitchAndFamily );
840     aDFA.meWidthType    = WIDTH_DONTKNOW;
841     aDFA.meWeight       = ImplWeightToSal( rLogFont.lfWeight );
842     aDFA.meItalic       = (rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE;
843     aDFA.mePitch        = ImplLogPitchToSal( rLogFont.lfPitchAndFamily );
844     aDFA.mbSymbolFlag   = (rLogFont.lfCharSet == SYMBOL_CHARSET);
845 
846     // get the font face name
847     aDFA.maName = ImplSalGetUniString( rLogFont.lfFaceName );
848 
849     // use the face's style name only if it looks reasonable
850     const char* pStyleName = (const char*)rEnumFont.elfStyle;
851     const char* pEnd = pStyleName + sizeof( rEnumFont.elfStyle );
852     const char* p = pStyleName;
853     for(; *p && (p < pEnd); ++p )
854         if( (0x00 < *p) && (*p < 0x20) )
855             break;
856     if( p < pEnd )
857         aDFA.maStyleName = ImplSalGetUniString( pStyleName );
858 
859     // get device specific font attributes
860     aDFA.mbOrientation  = (nFontType & RASTER_FONTTYPE) == 0;
861     aDFA.mbDevice       = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
862 
863     aDFA.mbEmbeddable   = false;
864     aDFA.mbSubsettable  = false;
865     if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
866      || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
867         aDFA.mbSubsettable = true;
868     else if( 0 != (rMetric.ntmFlags & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
869         aDFA.mbEmbeddable = true;
870 
871     // heuristics for font quality
872     // -   standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
873     // -   subsetting > embedding > none
874     aDFA.mnQuality = 0;
875     if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
876         aDFA.mnQuality += 50;
877     if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
878         aDFA.mnQuality += 10;
879     if( aDFA.mbSubsettable )
880         aDFA.mnQuality += 200;
881     else if( aDFA.mbEmbeddable )
882         aDFA.mnQuality += 100;
883 
884     // #i38665# prefer Type1 versions of the standard postscript fonts
885     if( aDFA.mbEmbeddable )
886     {
887         if( aDFA.maName.EqualsAscii( "AvantGarde" )
888         ||  aDFA.maName.EqualsAscii( "Bookman" )
889         ||  aDFA.maName.EqualsAscii( "Courier" )
890         ||  aDFA.maName.EqualsAscii( "Helvetica" )
891         ||  aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
892         ||  aDFA.maName.EqualsAscii( "Palatino" )
893         ||  aDFA.maName.EqualsAscii( "Symbol" )
894         ||  aDFA.maName.EqualsAscii( "Times" )
895         ||  aDFA.maName.EqualsAscii( "ZapfChancery" )
896         ||  aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
897             aDFA.mnQuality += 500;
898     }
899 
900     // TODO: add alias names
901     return aDFA;
902 }
903 
904 // -----------------------------------------------------------------------
905 
WinFont2DevFontAttributes(const ENUMLOGFONTEXW & rEnumFont,const NEWTEXTMETRICW & rMetric,DWORD nFontType)906 static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXW& rEnumFont,
907     const NEWTEXTMETRICW& rMetric, DWORD nFontType )
908 {
909     ImplDevFontAttributes aDFA;
910 
911     const LOGFONTW rLogFont = rEnumFont.elfLogFont;
912 
913     // get font face attributes
914     aDFA.meFamily       = ImplFamilyToSal( rLogFont.lfPitchAndFamily );
915     aDFA.meWidthType    = WIDTH_DONTKNOW;
916     aDFA.meWeight       = ImplWeightToSal( rLogFont.lfWeight );
917     aDFA.meItalic       = (rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE;
918     aDFA.mePitch        = ImplLogPitchToSal( rLogFont.lfPitchAndFamily );
919     aDFA.mbSymbolFlag   = (rLogFont.lfCharSet == SYMBOL_CHARSET);
920 
921     // get the font face name
922     aDFA.maName = reinterpret_cast<const sal_Unicode*>(rLogFont.lfFaceName);
923 
924     // use the face's style name only if it looks reasonable
925     const wchar_t* pStyleName = rEnumFont.elfStyle;
926     const wchar_t* pEnd = pStyleName + sizeof(rEnumFont.elfStyle)/sizeof(*rEnumFont.elfStyle);
927     const wchar_t* p = pStyleName;
928     for(; *p && (p < pEnd); ++p )
929         if( *p < 0x0020 )
930             break;
931     if( p < pEnd )
932         aDFA.maStyleName = reinterpret_cast<const sal_Unicode*>(pStyleName);
933 
934     // get device specific font attributes
935     aDFA.mbOrientation  = (nFontType & RASTER_FONTTYPE) == 0;
936     aDFA.mbDevice       = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
937 
938     aDFA.mbEmbeddable   = false;
939     aDFA.mbSubsettable  = false;
940     if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
941      || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
942         aDFA.mbSubsettable = true;
943     else if( 0 != (rMetric.ntmFlags & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
944         aDFA.mbEmbeddable = true;
945 
946     // heuristics for font quality
947     // -   standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
948     // -   subsetting > embedding > none
949     aDFA.mnQuality = 0;
950     if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
951         aDFA.mnQuality += 50;
952     if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
953         aDFA.mnQuality += 10;
954     if( aDFA.mbSubsettable )
955         aDFA.mnQuality += 200;
956     else if( aDFA.mbEmbeddable )
957         aDFA.mnQuality += 100;
958 
959     // #i38665# prefer Type1 versions of the standard postscript fonts
960     if( aDFA.mbEmbeddable )
961     {
962         if( aDFA.maName.EqualsAscii( "AvantGarde" )
963         ||  aDFA.maName.EqualsAscii( "Bookman" )
964         ||  aDFA.maName.EqualsAscii( "Courier" )
965         ||  aDFA.maName.EqualsAscii( "Helvetica" )
966         ||  aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
967         ||  aDFA.maName.EqualsAscii( "Palatino" )
968         ||  aDFA.maName.EqualsAscii( "Symbol" )
969         ||  aDFA.maName.EqualsAscii( "Times" )
970         ||  aDFA.maName.EqualsAscii( "ZapfChancery" )
971         ||  aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
972             aDFA.mnQuality += 500;
973     }
974 
975     // TODO: add alias names
976     return aDFA;
977 }
978 
979 // -----------------------------------------------------------------------
980 
ImplLogMetricToDevFontDataA(const ENUMLOGFONTEXA * pLogFont,const NEWTEXTMETRICA * pMetric,DWORD nFontType)981 static ImplWinFontData* ImplLogMetricToDevFontDataA( const ENUMLOGFONTEXA* pLogFont,
982                                          const NEWTEXTMETRICA* pMetric,
983                                          DWORD nFontType )
984 {
985     int nHeight = 0;
986     if ( nFontType & RASTER_FONTTYPE )
987         nHeight = pMetric->tmHeight - pMetric->tmInternalLeading;
988 
989     ImplWinFontData* pData = new ImplWinFontData(
990         WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType),
991         nHeight,
992         pLogFont->elfLogFont.lfCharSet,
993         pMetric->tmPitchAndFamily );
994 
995     return pData;
996 }
997 
998 // -----------------------------------------------------------------------
999 
ImplLogMetricToDevFontDataW(const ENUMLOGFONTEXW * pLogFont,const NEWTEXTMETRICW * pMetric,DWORD nFontType)1000 static ImplWinFontData* ImplLogMetricToDevFontDataW( const ENUMLOGFONTEXW* pLogFont,
1001                                          const NEWTEXTMETRICW* pMetric,
1002                                          DWORD nFontType )
1003 {
1004     int nHeight = 0;
1005     if ( nFontType & RASTER_FONTTYPE )
1006         nHeight = pMetric->tmHeight - pMetric->tmInternalLeading;
1007 
1008     ImplWinFontData* pData = new ImplWinFontData(
1009         WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType),
1010         nHeight,
1011         pLogFont->elfLogFont.lfCharSet,
1012         pMetric->tmPitchAndFamily );
1013 
1014     return pData;
1015 }
1016 
1017 // -----------------------------------------------------------------------
1018 
ImplSalLogFontToFontA(HDC hDC,const LOGFONTA & rLogFont,Font & rFont)1019 void ImplSalLogFontToFontA( HDC hDC, const LOGFONTA& rLogFont, Font& rFont )
1020 {
1021     String aFontName( ImplSalGetUniString( rLogFont.lfFaceName ) );
1022     if ( aFontName.Len() )
1023     {
1024         rFont.SetName( aFontName );
1025         rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) );
1026         rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) );
1027         rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) );
1028         rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) );
1029 
1030         long nFontHeight = rLogFont.lfHeight;
1031         if ( nFontHeight < 0 )
1032             nFontHeight = -nFontHeight;
1033         long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
1034         if( !nDPIY )
1035             nDPIY = 600;
1036         nFontHeight *= 72;
1037         nFontHeight += nDPIY/2;
1038         nFontHeight /= nDPIY;
1039         rFont.SetSize( Size( 0, nFontHeight ) );
1040         rFont.SetOrientation( (short)rLogFont.lfEscapement );
1041         if ( rLogFont.lfItalic )
1042             rFont.SetItalic( ITALIC_NORMAL );
1043         else
1044             rFont.SetItalic( ITALIC_NONE );
1045         if ( rLogFont.lfUnderline )
1046             rFont.SetUnderline( UNDERLINE_SINGLE );
1047         else
1048             rFont.SetUnderline( UNDERLINE_NONE );
1049         if ( rLogFont.lfStrikeOut )
1050             rFont.SetStrikeout( STRIKEOUT_SINGLE );
1051         else
1052             rFont.SetStrikeout( STRIKEOUT_NONE );
1053     }
1054 }
1055 
1056 // -----------------------------------------------------------------------
1057 
ImplSalLogFontToFontW(HDC hDC,const LOGFONTW & rLogFont,Font & rFont)1058 void ImplSalLogFontToFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont )
1059 {
1060     XubString aFontName( reinterpret_cast<const xub_Unicode*>(rLogFont.lfFaceName) );
1061     if ( aFontName.Len() )
1062     {
1063         rFont.SetName( aFontName );
1064         rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) );
1065         rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) );
1066         rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) );
1067         rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) );
1068 
1069         long nFontHeight = rLogFont.lfHeight;
1070         if ( nFontHeight < 0 )
1071             nFontHeight = -nFontHeight;
1072         long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
1073         if( !nDPIY )
1074             nDPIY = 600;
1075         nFontHeight *= 72;
1076         nFontHeight += nDPIY/2;
1077         nFontHeight /= nDPIY;
1078         rFont.SetSize( Size( 0, nFontHeight ) );
1079         rFont.SetOrientation( (short)rLogFont.lfEscapement );
1080         if ( rLogFont.lfItalic )
1081             rFont.SetItalic( ITALIC_NORMAL );
1082         else
1083             rFont.SetItalic( ITALIC_NONE );
1084         if ( rLogFont.lfUnderline )
1085             rFont.SetUnderline( UNDERLINE_SINGLE );
1086         else
1087             rFont.SetUnderline( UNDERLINE_NONE );
1088         if ( rLogFont.lfStrikeOut )
1089             rFont.SetStrikeout( STRIKEOUT_SINGLE );
1090         else
1091             rFont.SetStrikeout( STRIKEOUT_NONE );
1092     }
1093 }
1094 
1095 // =======================================================================
1096 
ImplWinFontData(const ImplDevFontAttributes & rDFS,int nHeight,BYTE eWinCharSet,BYTE nPitchAndFamily)1097 ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes& rDFS,
1098     int nHeight, BYTE eWinCharSet, BYTE nPitchAndFamily )
1099 :   ImplFontData( rDFS, 0 ),
1100     meWinCharSet( eWinCharSet ),
1101     mnPitchAndFamily( nPitchAndFamily ),
1102     mpFontCharSets( NULL ),
1103     mpUnicodeMap( NULL ),
1104     mbGsubRead( false ),
1105     mbDisableGlyphApi( false ),
1106     mbHasKoreanRange( false ),
1107     mbHasCJKSupport( false ),
1108 #ifdef ENABLE_GRAPHITE
1109     mbHasGraphiteSupport( false ),
1110 #endif
1111     mbHasArabicSupport ( false ),
1112     mbAliasSymbolsLow( false ),
1113     mbAliasSymbolsHigh( false ),
1114     mnId( 0 ),
1115     mpEncodingVector( NULL )
1116 {
1117     SetBitmapSize( 0, nHeight );
1118 
1119     if( eWinCharSet == SYMBOL_CHARSET )
1120     {
1121         if( (nPitchAndFamily & TMPF_TRUETYPE) != 0 )
1122         {
1123             // truetype fonts need their symbols as U+F0xx
1124             mbAliasSymbolsHigh = true;
1125         }
1126         else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_DEVICE))
1127                                  == (TMPF_VECTOR|TMPF_DEVICE) )
1128         {
1129             // scalable device fonts (e.g. builtin printer fonts)
1130             // need their symbols as U+00xx
1131             mbAliasSymbolsLow  = true;
1132         }
1133         else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) == 0 )
1134         {
1135             // bitmap fonts need their symbols as U+F0xx
1136             mbAliasSymbolsHigh = true;
1137         }
1138     }
1139 }
1140 
1141 // -----------------------------------------------------------------------
1142 
~ImplWinFontData()1143 ImplWinFontData::~ImplWinFontData()
1144 {
1145     delete[] mpFontCharSets;
1146 
1147     if( mpUnicodeMap )
1148         mpUnicodeMap->DeReference();
1149     delete mpEncodingVector;
1150 }
1151 
1152 // -----------------------------------------------------------------------
1153 
GetFontId() const1154 sal_IntPtr ImplWinFontData::GetFontId() const
1155 {
1156     return mnId;
1157 }
1158 
1159 // -----------------------------------------------------------------------
1160 
UpdateFromHDC(HDC hDC) const1161 void ImplWinFontData::UpdateFromHDC( HDC hDC ) const
1162 {
1163     // short circuit if already initialized
1164     if( mpUnicodeMap != NULL )
1165         return;
1166 
1167     ReadCmapTable( hDC );
1168     ReadOs2Table( hDC );
1169 #ifdef ENABLE_GRAPHITE
1170 	static const char* pDisableGraphiteText = getenv( "SAL_DISABLE_GRAPHITE" );
1171     if( !pDisableGraphiteText || (pDisableGraphiteText[0] == '0') )
1172 	{
1173 		mbHasGraphiteSupport = gr::WinFont::FontHasGraphiteTables(hDC);
1174 	}
1175 #endif
1176 
1177     // even if the font works some fonts have problems with the glyph API
1178     // => the heuristic below tries to figure out which fonts have the problem
1179     TEXTMETRICA aTextMetric;
1180     if( ::GetTextMetricsA( hDC, &aTextMetric ) )
1181         if( !(aTextMetric.tmPitchAndFamily & TMPF_TRUETYPE)
1182         ||   (aTextMetric.tmPitchAndFamily & TMPF_DEVICE) )
1183             mbDisableGlyphApi = true;
1184 
1185 #if 0
1186     // #110548# more important than #107885# => TODO: better solution
1187     DWORD nFLI = GetFontLanguageInfo( hDC );
1188     if( 0 == (nFLI & GCP_GLYPHSHAPE) )
1189         mbDisableGlyphApi = true;
1190 #endif
1191 }
1192 
1193 // -----------------------------------------------------------------------
1194 
HasGSUBstitutions(HDC hDC) const1195 bool ImplWinFontData::HasGSUBstitutions( HDC hDC ) const
1196 {
1197     if( !mbGsubRead )
1198         ReadGsubTable( hDC );
1199     return !maGsubTable.empty();
1200 }
1201 
1202 // -----------------------------------------------------------------------
1203 
IsGSUBstituted(sal_UCS4 cChar) const1204 bool ImplWinFontData::IsGSUBstituted( sal_UCS4 cChar ) const
1205 {
1206     return( maGsubTable.find( cChar ) != maGsubTable.end() );
1207 }
1208 
1209 // -----------------------------------------------------------------------
1210 
GetImplFontCharMap() const1211 const ImplFontCharMap* ImplWinFontData::GetImplFontCharMap() const
1212 {
1213     if( !mpUnicodeMap )
1214         return NULL;
1215     return mpUnicodeMap;
1216 }
1217 
1218 // -----------------------------------------------------------------------
1219 
GetUInt(const unsigned char * p)1220 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
GetUShort(const unsigned char * p)1221 static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
1222 //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
CalcTag(const char p[4])1223 static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); }
1224 
ReadOs2Table(HDC hDC) const1225 void ImplWinFontData::ReadOs2Table( HDC hDC ) const
1226 {
1227     const DWORD Os2Tag = CalcTag( "OS/2" );
1228     DWORD nLength = ::GetFontData( hDC, Os2Tag, 0, NULL, 0 );
1229     if( (nLength == GDI_ERROR) || !nLength )
1230         return;
1231     std::vector<unsigned char> aOS2map( nLength );
1232     unsigned char* pOS2map = &aOS2map[0];
1233     ::GetFontData( hDC, Os2Tag, 0, pOS2map, nLength );
1234     sal_uInt32 nVersion = GetUShort( pOS2map );
1235     if ( nVersion >= 0x0001 && nLength >= 58 )
1236     {
1237         // We need at least version 0x0001 (TrueType rev 1.66)
1238         // to have access to the needed struct members.
1239         sal_uInt32 ulUnicodeRange1 = GetUInt( pOS2map + 42 );
1240         sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
1241 #if 0
1242         sal_uInt32 ulUnicodeRange3 = GetUInt( pOS2map + 50 );
1243         sal_uInt32 ulUnicodeRange4 = GetUInt( pOS2map + 54 );
1244 #endif
1245 
1246         // Check for CJK capabilities of the current font
1247         mbHasCJKSupport = (ulUnicodeRange2 & 0x2DF00000);
1248         mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000)
1249                         | (ulUnicodeRange2 & 0x01100000);
1250         mbHasArabicSupport = (ulUnicodeRange1 & 0x00002000);
1251    }
1252 }
1253 
1254 // -----------------------------------------------------------------------
1255 
ReadGsubTable(HDC hDC) const1256 void ImplWinFontData::ReadGsubTable( HDC hDC ) const
1257 {
1258     mbGsubRead = true;
1259 
1260     // check the existence of a GSUB table
1261     const DWORD GsubTag = CalcTag( "GSUB" );
1262     DWORD nRC = ::GetFontData( hDC, GsubTag, 0, NULL, 0 );
1263     if( (nRC == GDI_ERROR) || !nRC )
1264         return;
1265 
1266 	// parse the GSUB table through sft
1267     // TODO: parse it directly
1268 
1269     // sft needs the full font file data => get it
1270     const RawFontData aRawFontData( hDC );
1271     if( !aRawFontData.get() )
1272     	return;
1273 
1274     // open font file
1275     sal_uInt32 nFaceNum = 0;
1276     if( !*aRawFontData.get() )  // TTC candidate
1277         nFaceNum = ~0U;  // indicate "TTC font extracts only"
1278 
1279     TrueTypeFont* pTTFont = NULL;
1280     ::OpenTTFontBuffer( (void*)aRawFontData.get(), aRawFontData.size(), nFaceNum, &pTTFont );
1281     if( !pTTFont )
1282         return;
1283 
1284     // add vertically substituted characters to list
1285     static const sal_Unicode aGSUBCandidates[] = {
1286         0x0020, 0x0080, // ASCII
1287         0x2000, 0x2600, // misc
1288         0x3000, 0x3100, // CJK punctutation
1289         0x3300, 0x3400, // squared words
1290         0xFF00, 0xFFF0, // halfwidth|fullwidth forms
1291     0 };
1292 
1293     for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
1294         for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
1295             if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
1296                 maGsubTable.insert( cChar ); // insert GSUBbed unicodes
1297 
1298     CloseTTFont( pTTFont );
1299 }
1300 
1301 // -----------------------------------------------------------------------
1302 
ReadCmapTable(HDC hDC) const1303 void ImplWinFontData::ReadCmapTable( HDC hDC ) const
1304 {
1305     if( mpUnicodeMap != NULL )
1306         return;
1307 
1308     bool bIsSymbolFont = (meWinCharSet == SYMBOL_CHARSET);
1309     // get the CMAP table from the font which is selected into the DC
1310     const DWORD nCmapTag = CalcTag( "cmap" );
1311     const RawFontData aRawFontData( hDC, nCmapTag );
1312     // parse the CMAP table if available
1313     if( aRawFontData.get() ) {
1314         CmapResult aResult;
1315         ParseCMAP( aRawFontData.get(), aRawFontData.size(), aResult );
1316         mbDisableGlyphApi |= aResult.mbRecoded;
1317         aResult.mbSymbolic = bIsSymbolFont;
1318         if( aResult.mnRangeCount > 0 )
1319             mpUnicodeMap = new ImplFontCharMap( aResult );
1320     }
1321 
1322     if( !mpUnicodeMap )
1323         mpUnicodeMap = ImplFontCharMap::GetDefaultMap( bIsSymbolFont );
1324     mpUnicodeMap->AddReference();
1325 }
1326 
1327 // =======================================================================
1328 
SetTextColor(SalColor nSalColor)1329 void WinSalGraphics::SetTextColor( SalColor nSalColor )
1330 {
1331     COLORREF aCol = PALETTERGB( SALCOLOR_RED( nSalColor ),
1332                                 SALCOLOR_GREEN( nSalColor ),
1333                                 SALCOLOR_BLUE( nSalColor ) );
1334 
1335     if( !mbPrinter &&
1336         GetSalData()->mhDitherPal &&
1337         ImplIsSysColorEntry( nSalColor ) )
1338     {
1339         aCol = PALRGB_TO_RGB( aCol );
1340     }
1341 
1342     ::SetTextColor( getHDC(), aCol );
1343 }
1344 
1345 // -----------------------------------------------------------------------
1346 
SalEnumQueryFontProcExW(const ENUMLOGFONTEXW *,const NEWTEXTMETRICEXW *,DWORD,LPARAM lParam)1347 int CALLBACK SalEnumQueryFontProcExW( const ENUMLOGFONTEXW*,
1348                                       const NEWTEXTMETRICEXW*,
1349                                       DWORD, LPARAM lParam )
1350 {
1351     *((bool*)(void*)lParam) = true;
1352     return 0;
1353 }
1354 
1355 // -----------------------------------------------------------------------
1356 
SalEnumQueryFontProcExA(const ENUMLOGFONTEXA *,const NEWTEXTMETRICEXA *,DWORD,LPARAM lParam)1357 int CALLBACK SalEnumQueryFontProcExA( const ENUMLOGFONTEXA*,
1358                                       const NEWTEXTMETRICEXA*,
1359                                       DWORD, LPARAM lParam )
1360 {
1361     *((bool*)(void*)lParam) = true;
1362     return 0;
1363 }
1364 
1365 // -----------------------------------------------------------------------
1366 
ImplIsFontAvailable(HDC hDC,const UniString & rName)1367 bool ImplIsFontAvailable( HDC hDC, const UniString& rName )
1368 {
1369         // Test, if Font available
1370         LOGFONTW aLogFont;
1371         memset( &aLogFont, 0, sizeof( aLogFont ) );
1372         aLogFont.lfCharSet = DEFAULT_CHARSET;
1373 
1374         UINT nNameLen = rName.Len();
1375         if ( nNameLen > (sizeof( aLogFont.lfFaceName )/sizeof( wchar_t ))-1 )
1376             nNameLen = (sizeof( aLogFont.lfFaceName )/sizeof( wchar_t ))-1;
1377         memcpy( aLogFont.lfFaceName, rName.GetBuffer(), nNameLen*sizeof( wchar_t ) );
1378         aLogFont.lfFaceName[nNameLen] = 0;
1379 
1380     bool bAvailable = false;
1381     EnumFontFamiliesExW( hDC, &aLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW,
1382                              (LPARAM)(void*)&bAvailable, 0 );
1383 
1384     return bAvailable;
1385 }
1386 
1387 // -----------------------------------------------------------------------
1388 
ImplGetLogFontFromFontSelect(HDC hDC,const ImplFontSelectData * pFont,LOGFONTW & rLogFont,bool)1389 void ImplGetLogFontFromFontSelect( HDC hDC,
1390                                    const ImplFontSelectData* pFont,
1391                                    LOGFONTW& rLogFont,
1392                                    bool /*bTestVerticalAvail*/ )
1393 {
1394     UniString   aName;
1395     if ( pFont->mpFontData )
1396         aName = pFont->mpFontData->maName;
1397     else
1398         aName = pFont->maName.GetToken( 0 );
1399 
1400     UINT nNameLen = aName.Len();
1401     if ( nNameLen > (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1 )
1402         nNameLen = (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1;
1403     memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen*sizeof( wchar_t ) );
1404     rLogFont.lfFaceName[nNameLen] = 0;
1405 
1406     if( !pFont->mpFontData )
1407     {
1408         rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET;
1409         rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->mePitch )
1410                                   | ImplFamilyToWin( pFont->meFamily );
1411     }
1412     else
1413     {
1414         const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData );
1415         rLogFont.lfCharSet        = pWinFontData->GetCharSet();
1416         rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily();
1417     }
1418 
1419     rLogFont.lfWeight          = ImplWeightToWin( pFont->meWeight );
1420     rLogFont.lfHeight          = (LONG)-pFont->mnHeight;
1421     rLogFont.lfWidth           = (LONG)pFont->mnWidth;
1422     rLogFont.lfUnderline       = 0;
1423     rLogFont.lfStrikeOut       = 0;
1424     rLogFont.lfItalic          = (pFont->meItalic) != ITALIC_NONE;
1425     rLogFont.lfEscapement      = pFont->mnOrientation;
1426     rLogFont.lfOrientation     = rLogFont.lfEscapement;
1427     rLogFont.lfClipPrecision   = CLIP_DEFAULT_PRECIS;
1428     rLogFont.lfQuality         = DEFAULT_QUALITY;
1429     rLogFont.lfOutPrecision    = OUT_TT_PRECIS;
1430     if ( pFont->mnOrientation )
1431         rLogFont.lfClipPrecision |= CLIP_LH_ANGLES;
1432 
1433     // disable antialiasing if requested
1434     if ( pFont->mbNonAntialiased )
1435         rLogFont.lfQuality = NONANTIALIASED_QUALITY;
1436 
1437     // select vertical mode if requested and available
1438     if( pFont->mbVertical && nNameLen )
1439     {
1440         // vertical fonts start with an '@'
1441         memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0],
1442             sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) );
1443         rLogFont.lfFaceName[0] = '@';
1444 
1445         // check availability of vertical mode for this font
1446         bool bAvailable = false;
1447         EnumFontFamiliesExW( hDC, &rLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW,
1448                          (LPARAM)&bAvailable, 0 );
1449 
1450         if( !bAvailable )
1451         {
1452             // restore non-vertical name if not vertical mode isn't available
1453             memcpy( &rLogFont.lfFaceName[0], aName.GetBuffer(), nNameLen*sizeof(wchar_t) );
1454             if( nNameLen < LF_FACESIZE )
1455                 rLogFont.lfFaceName[nNameLen] = '\0';
1456         }
1457     }
1458 }
1459 
1460 // -----------------------------------------------------------------------
1461 
ImplGetLogFontFromFontSelect(HDC hDC,const ImplFontSelectData * pFont,LOGFONTA & rLogFont,bool)1462 static void ImplGetLogFontFromFontSelect( HDC hDC,
1463                                    const ImplFontSelectData* pFont,
1464                                    LOGFONTA& rLogFont,
1465                                    bool /*bTestVerticalAvail*/ )
1466 {
1467     ByteString aName;
1468     if( pFont->mpFontData )
1469         aName = ImplSalGetWinAnsiString( pFont->mpFontData->maName );
1470     else
1471         aName = ImplSalGetWinAnsiString( pFont->maName.GetToken( 0 ) );
1472 
1473     int nNameLen = aName.Len();
1474     if( nNameLen > LF_FACESIZE )
1475         nNameLen = LF_FACESIZE;
1476     memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen );
1477     if( nNameLen < LF_FACESIZE )
1478         rLogFont.lfFaceName[nNameLen] = '\0';
1479 
1480     if( !pFont->mpFontData )
1481     {
1482         rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET;
1483         rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->mePitch )
1484                                   | ImplFamilyToWin( pFont->meFamily );
1485     }
1486     else
1487     {
1488         const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData );
1489         rLogFont.lfCharSet        = pWinFontData->GetCharSet();
1490         rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily();
1491     }
1492 
1493     rLogFont.lfWeight           = ImplWeightToWin( pFont->meWeight );
1494     rLogFont.lfHeight           = (LONG)-pFont->mnHeight;
1495     rLogFont.lfWidth            = (LONG)pFont->mnWidth;
1496     rLogFont.lfUnderline        = 0;
1497     rLogFont.lfStrikeOut        = 0;
1498     rLogFont.lfItalic           = (pFont->meItalic) != ITALIC_NONE;
1499     rLogFont.lfEscapement       = pFont->mnOrientation;
1500     rLogFont.lfOrientation      = rLogFont.lfEscapement; // ignored by W98
1501     rLogFont.lfClipPrecision    = CLIP_DEFAULT_PRECIS;
1502     rLogFont.lfQuality          = DEFAULT_QUALITY;
1503     rLogFont.lfOutPrecision     = OUT_TT_PRECIS;
1504     if( pFont->mnOrientation )
1505         rLogFont.lfClipPrecision |= CLIP_LH_ANGLES;
1506 
1507     // disable antialiasing if requested
1508     if( pFont->mbNonAntialiased )
1509         rLogFont.lfQuality = NONANTIALIASED_QUALITY;
1510 
1511     // select vertical mode if requested and available
1512     if( pFont->mbVertical && nNameLen )
1513     {
1514         // vertical fonts start with an '@'
1515         memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0],
1516                     sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) );
1517         rLogFont.lfFaceName[0] = '@';
1518 
1519         // check availability of vertical mode for this font
1520         bool bAvailable = false;
1521         EnumFontFamiliesExA( hDC, &rLogFont, (FONTENUMPROCA)SalEnumQueryFontProcExA,
1522                          (LPARAM)&bAvailable, 0 );
1523 
1524         if( !bAvailable )
1525         {
1526             // restore non-vertical name if vertical mode is not supported
1527             memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen );
1528             if( nNameLen < LF_FACESIZE )
1529                 rLogFont.lfFaceName[nNameLen] = '\0';
1530         }
1531     }
1532 }
1533 
1534 // -----------------------------------------------------------------------
1535 
ImplDoSetFont(ImplFontSelectData * i_pFont,float & o_rFontScale,HFONT & o_rOldFont)1536 HFONT WinSalGraphics::ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, HFONT& o_rOldFont )
1537 {
1538     HFONT hNewFont = 0;
1539 
1540     HDC hdcScreen = 0;
1541     if( mbVirDev )
1542         // only required for virtual devices, see below for details
1543         hdcScreen = GetDC(0);
1544 
1545     if( true/*aSalShlData.mbWNT*/ )
1546     {
1547         LOGFONTW aLogFont;
1548         ImplGetLogFontFromFontSelect( getHDC(), i_pFont, aLogFont, true );
1549 
1550         // on the display we prefer Courier New when Courier is a
1551         // bitmap only font and we need to stretch or rotate it
1552         if( mbScreen
1553         &&  (i_pFont->mnWidth != 0
1554           || i_pFont->mnOrientation != 0
1555           || i_pFont->mpFontData == NULL
1556           || (i_pFont->mpFontData->GetHeight() != i_pFont->mnHeight))
1557         && !bImplSalCourierScalable
1558         && bImplSalCourierNew
1559         && (ImplSalWICompareAscii( aLogFont.lfFaceName, "Courier" ) == 0) )
1560             lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 );
1561 
1562         // #i47675# limit font requests to MAXFONTHEIGHT
1563         // TODO: share MAXFONTHEIGHT font instance
1564         if( (-aLogFont.lfHeight <= MAXFONTHEIGHT)
1565         &&  (+aLogFont.lfWidth <= MAXFONTHEIGHT) )
1566         {
1567             o_rFontScale = 1.0;
1568         }
1569         else if( -aLogFont.lfHeight >= +aLogFont.lfWidth )
1570         {
1571             o_rFontScale = -aLogFont.lfHeight / (float)MAXFONTHEIGHT;
1572             aLogFont.lfHeight = -MAXFONTHEIGHT;
1573             aLogFont.lfWidth = FRound( aLogFont.lfWidth / o_rFontScale );
1574         }
1575         else // #i95867# also limit font widths
1576         {
1577             o_rFontScale = +aLogFont.lfWidth / (float)MAXFONTHEIGHT;
1578             aLogFont.lfWidth = +MAXFONTHEIGHT;
1579             aLogFont.lfHeight = FRound( aLogFont.lfHeight / o_rFontScale );
1580         }
1581 
1582         hNewFont = ::CreateFontIndirectW( &aLogFont );
1583         if( hdcScreen )
1584         {
1585             // select font into screen hdc first to get an antialiased font
1586             // see knowledge base article 305290:
1587             // "PRB: Fonts Not Drawn Antialiased on Device Context for DirectDraw Surface"
1588             SelectFont( hdcScreen, SelectFont( hdcScreen , hNewFont ) );
1589         }
1590         o_rOldFont = ::SelectFont( getHDC(), hNewFont );
1591 
1592         TEXTMETRICW aTextMetricW;
1593         if( !::GetTextMetricsW( getHDC(), &aTextMetricW ) )
1594         {
1595             // the selected font doesn't work => try a replacement
1596             // TODO: use its font fallback instead
1597             lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 );
1598             aLogFont.lfPitchAndFamily = FIXED_PITCH;
1599             HFONT hNewFont2 = CreateFontIndirectW( &aLogFont );
1600             SelectFont( getHDC(), hNewFont2 );
1601             DeleteFont( hNewFont );
1602             hNewFont = hNewFont2;
1603         }
1604     }
1605 
1606     if( hdcScreen )
1607         ::ReleaseDC( NULL, hdcScreen );
1608 
1609     return hNewFont;
1610 }
1611 
SetFont(ImplFontSelectData * pFont,int nFallbackLevel)1612 sal_uInt16 WinSalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel )
1613 {
1614     // return early if there is no new font
1615     if( !pFont )
1616     {
1617         // deselect still active font
1618         if( mhDefFont )
1619             ::SelectFont( getHDC(), mhDefFont );
1620         // release no longer referenced font handles
1621         for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
1622         {
1623             if( mhFonts[i] )
1624                 ::DeleteFont( mhFonts[i] );
1625             mhFonts[ i ] = 0;
1626         }
1627         mhDefFont = 0;
1628         return 0;
1629     }
1630 
1631     DBG_ASSERT( pFont->mpFontData, "WinSalGraphics mpFontData==NULL");
1632     mpWinFontEntry[ nFallbackLevel ] = reinterpret_cast<ImplWinFontEntry*>( pFont->mpFontEntry );
1633     mpWinFontData[ nFallbackLevel ] = static_cast<const ImplWinFontData*>( pFont->mpFontData );
1634 
1635     HFONT hOldFont = 0;
1636     HFONT hNewFont = ImplDoSetFont( pFont, mfFontScale, hOldFont );
1637 
1638     if( !mhDefFont )
1639     {
1640         // keep default font
1641         mhDefFont = hOldFont;
1642     }
1643     else
1644     {
1645         // release no longer referenced font handles
1646         for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
1647         {
1648             if( mhFonts[i] )
1649             {
1650                 ::DeleteFont( mhFonts[i] );
1651                 mhFonts[i] = 0;
1652             }
1653         }
1654     }
1655 
1656     // store new font in correct layer
1657     mhFonts[ nFallbackLevel ] = hNewFont;
1658     // now the font is live => update font face
1659     if( mpWinFontData[ nFallbackLevel ] )
1660         mpWinFontData[ nFallbackLevel ]->UpdateFromHDC( getHDC() );
1661 
1662     if( !nFallbackLevel )
1663     {
1664         mbFontKernInit = TRUE;
1665         if ( mpFontKernPairs )
1666         {
1667             delete[] mpFontKernPairs;
1668             mpFontKernPairs = NULL;
1669         }
1670         mnFontKernPairCount = 0;
1671     }
1672 
1673     mnFontCharSetCount = 0;
1674 
1675     // some printers have higher internal resolution, so their
1676     // text output would be different from what we calculated
1677     // => suggest DrawTextArray to workaround this problem
1678     if ( mbPrinter )
1679         return SAL_SETFONT_USEDRAWTEXTARRAY;
1680     else
1681         return 0;
1682 }
1683 
1684 // -----------------------------------------------------------------------
1685 
GetFontMetric(ImplFontMetricData * pMetric,int nFallbackLevel)1686 void WinSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel )
1687 {
1688     // temporarily change the HDC to the font in the fallback level
1689     HFONT hOldFont = SelectFont( getHDC(), mhFonts[nFallbackLevel] );
1690 
1691         wchar_t aFaceName[LF_FACESIZE+60];
1692         if( ::GetTextFaceW( getHDC(), sizeof(aFaceName)/sizeof(wchar_t), aFaceName ) )
1693             pMetric->maName = reinterpret_cast<const sal_Unicode*>(aFaceName);
1694 
1695     // get the font metric
1696     TEXTMETRICA aWinMetric;
1697     const bool bOK = GetTextMetricsA( getHDC(), &aWinMetric );
1698     // restore the HDC to the font in the base level
1699     SelectFont( getHDC(), hOldFont );
1700     if( !bOK )
1701         return;
1702 
1703     // device independent font attributes
1704     pMetric->meFamily       = ImplFamilyToSal( aWinMetric.tmPitchAndFamily );;
1705     pMetric->mbSymbolFlag   = (aWinMetric.tmCharSet == SYMBOL_CHARSET);
1706     pMetric->meWeight       = ImplWeightToSal( aWinMetric.tmWeight );
1707     pMetric->mePitch        = ImplMetricPitchToSal( aWinMetric.tmPitchAndFamily );
1708     pMetric->meItalic       = aWinMetric.tmItalic ? ITALIC_NORMAL : ITALIC_NONE;
1709     pMetric->mnSlant        = 0;
1710 
1711     // device dependend font attributes
1712     pMetric->mbDevice       = (aWinMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
1713     pMetric->mbScalableFont = (aWinMetric.tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) != 0;
1714     if( pMetric->mbScalableFont )
1715     {
1716         // check if there are kern pairs
1717         // TODO: does this work with GPOS kerning?
1718         DWORD nKernPairs = ::GetKerningPairsA( getHDC(), 0, NULL );
1719         pMetric->mbKernableFont = (nKernPairs > 0);
1720     }
1721     else
1722     {
1723         // bitmap fonts cannot be rotated directly
1724         pMetric->mnOrientation  = 0;
1725         // bitmap fonts have no kerning
1726         pMetric->mbKernableFont = false;
1727     }
1728 
1729     // transformation dependend font metrics
1730     pMetric->mnWidth        = static_cast<int>( mfFontScale * aWinMetric.tmAveCharWidth );
1731     pMetric->mnIntLeading   = static_cast<int>( mfFontScale * aWinMetric.tmInternalLeading );
1732     pMetric->mnExtLeading   = static_cast<int>( mfFontScale * aWinMetric.tmExternalLeading );
1733     pMetric->mnAscent       = static_cast<int>( mfFontScale * aWinMetric.tmAscent );
1734     pMetric->mnDescent      = static_cast<int>( mfFontScale * aWinMetric.tmDescent );
1735 
1736     // #107888# improved metric compatibility for Asian fonts...
1737     // TODO: assess workaround below for CWS >= extleading
1738     // TODO: evaluate use of aWinMetric.sTypo* members for CJK
1739     if( mpWinFontData[nFallbackLevel] && mpWinFontData[nFallbackLevel]->SupportsCJK() )
1740     {
1741         pMetric->mnIntLeading += pMetric->mnExtLeading;
1742 
1743         // #109280# The line height for Asian fonts is too small.
1744         // Therefore we add half of the external leading to the
1745         // ascent, the other half is added to the descent.
1746         const long nHalfTmpExtLeading = pMetric->mnExtLeading / 2;
1747         const long nOtherHalfTmpExtLeading = pMetric->mnExtLeading - nHalfTmpExtLeading;
1748 
1749         // #110641# external leading for Asian fonts.
1750         // The factor 0.3 has been confirmed with experiments.
1751         long nCJKExtLeading = static_cast<long>(0.30 * (pMetric->mnAscent + pMetric->mnDescent));
1752         nCJKExtLeading -= pMetric->mnExtLeading;
1753         pMetric->mnExtLeading = (nCJKExtLeading > 0) ? nCJKExtLeading : 0;
1754 
1755         pMetric->mnAscent   += nHalfTmpExtLeading;
1756         pMetric->mnDescent  += nOtherHalfTmpExtLeading;
1757     }
1758 
1759     pMetric->mnMinKashida = GetMinKashidaWidth();
1760 }
1761 
1762 // -----------------------------------------------------------------------
1763 
SalEnumCharSetsProcExA(const ENUMLOGFONTEXA * pLogFont,const NEWTEXTMETRICEXA *,DWORD,LPARAM lParam)1764 int CALLBACK SalEnumCharSetsProcExA( const ENUMLOGFONTEXA* pLogFont,
1765                                      const NEWTEXTMETRICEXA* /*pMetric*/,
1766                                      DWORD /*nFontType*/, LPARAM lParam )
1767 {
1768     WinSalGraphics* pData = (WinSalGraphics*)lParam;
1769     // Charset already in the list?
1770     for ( BYTE i = 0; i < pData->mnFontCharSetCount; i++ )
1771     {
1772         if ( pData->mpFontCharSets[i] == pLogFont->elfLogFont.lfCharSet )
1773             return 1;
1774     }
1775     pData->mpFontCharSets[pData->mnFontCharSetCount] = pLogFont->elfLogFont.lfCharSet;
1776     pData->mnFontCharSetCount++;
1777     return 1;
1778 }
1779 
1780 // -----------------------------------------------------------------------
1781 
ImplGetAllFontCharSets(WinSalGraphics * pData)1782 static void ImplGetAllFontCharSets( WinSalGraphics* pData )
1783 {
1784     if ( !pData->mpFontCharSets )
1785         pData->mpFontCharSets = new BYTE[256];
1786 
1787     LOGFONTA aLogFont;
1788     memset( &aLogFont, 0, sizeof( aLogFont ) );
1789     aLogFont.lfCharSet = DEFAULT_CHARSET;
1790     GetTextFaceA( pData->getHDC(), sizeof( aLogFont.lfFaceName ), aLogFont.lfFaceName );
1791     EnumFontFamiliesExA( pData->getHDC(), &aLogFont, (FONTENUMPROCA)SalEnumCharSetsProcExA,
1792                          (LPARAM)(void*)pData, 0 );
1793 }
1794 
1795 // -----------------------------------------------------------------------
1796 
ImplAddKerningPairs(WinSalGraphics * pData)1797 static void ImplAddKerningPairs( WinSalGraphics* pData )
1798 {
1799     sal_uLong nPairs = ::GetKerningPairsA( pData->getHDC(), 0, NULL );
1800     if ( !nPairs )
1801         return;
1802 
1803     CHARSETINFO aInfo;
1804     if ( !TranslateCharsetInfo( (DWORD*)(sal_uLong)GetTextCharset( pData->getHDC() ), &aInfo, TCI_SRCCHARSET ) )
1805         return;
1806 
1807     if ( !pData->mpFontKernPairs )
1808         pData->mpFontKernPairs = new KERNINGPAIR[nPairs];
1809     else
1810     {
1811         KERNINGPAIR* pOldPairs = pData->mpFontKernPairs;
1812         pData->mpFontKernPairs = new KERNINGPAIR[nPairs+pData->mnFontKernPairCount];
1813         memcpy( pData->mpFontKernPairs, pOldPairs,
1814                 pData->mnFontKernPairCount*sizeof( KERNINGPAIR ) );
1815         delete[] pOldPairs;
1816     }
1817 
1818     UINT            nCP = aInfo.ciACP;
1819     sal_uLong           nOldPairs = pData->mnFontKernPairCount;
1820     KERNINGPAIR*    pTempPair = pData->mpFontKernPairs+pData->mnFontKernPairCount;
1821     nPairs = ::GetKerningPairsA( pData->getHDC(), nPairs, pTempPair );
1822     for ( sal_uLong i = 0; i < nPairs; i++ )
1823     {
1824         unsigned char   aBuf[2];
1825         wchar_t         nChar;
1826         int             nLen;
1827         sal_Bool            bAdd = TRUE;
1828 
1829         // None-ASCII?, then we must convert the char
1830         if ( (pTempPair->wFirst > 125) || (pTempPair->wFirst == 92) )
1831         {
1832             if ( pTempPair->wFirst < 256 )
1833             {
1834                 aBuf[0] = (unsigned char)pTempPair->wFirst;
1835                 nLen = 1;
1836             }
1837             else
1838             {
1839                 aBuf[0] = (unsigned char)(pTempPair->wFirst >> 8);
1840                 aBuf[1] = (unsigned char)(pTempPair->wFirst & 0xFF);
1841                 nLen = 2;
1842             }
1843             if ( MultiByteToWideChar( nCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
1844                                       (const char*)aBuf, nLen, &nChar, 1 ) )
1845                 pTempPair->wFirst = nChar;
1846             else
1847                 bAdd = FALSE;
1848         }
1849         if ( (pTempPair->wSecond > 125) || (pTempPair->wSecond == 92) )
1850         {
1851             if ( pTempPair->wSecond < 256 )
1852             {
1853                 aBuf[0] = (unsigned char)pTempPair->wSecond;
1854                 nLen = 1;
1855             }
1856             else
1857             {
1858                 aBuf[0] = (unsigned char)(pTempPair->wSecond >> 8);
1859                 aBuf[1] = (unsigned char)(pTempPair->wSecond & 0xFF);
1860                 nLen = 2;
1861             }
1862             if ( MultiByteToWideChar( nCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
1863                                       (const char*)aBuf, nLen, &nChar, 1 ) )
1864                 pTempPair->wSecond = nChar;
1865             else
1866                 bAdd = FALSE;
1867         }
1868 
1869         // TODO: get rid of linear search!
1870         KERNINGPAIR* pTempPair2 = pData->mpFontKernPairs;
1871         for ( sal_uLong j = 0; j < nOldPairs; j++ )
1872         {
1873             if ( (pTempPair2->wFirst == pTempPair->wFirst) &&
1874                  (pTempPair2->wSecond == pTempPair->wSecond) )
1875             {
1876                 bAdd = FALSE;
1877                 break;
1878             }
1879             pTempPair2++;
1880         }
1881 
1882         if ( bAdd )
1883         {
1884             KERNINGPAIR* pDestPair = pData->mpFontKernPairs+pData->mnFontKernPairCount;
1885             if ( pDestPair != pTempPair )
1886                 memcpy( pDestPair, pTempPair, sizeof( KERNINGPAIR ) );
1887             pData->mnFontKernPairCount++;
1888         }
1889 
1890         pTempPair++;
1891     }
1892 }
1893 
1894 // -----------------------------------------------------------------------
1895 
GetKernPairs(sal_uLong nPairs,ImplKernPairData * pKernPairs)1896 sal_uLong WinSalGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData* pKernPairs )
1897 {
1898     DBG_ASSERT( sizeof( KERNINGPAIR ) == sizeof( ImplKernPairData ),
1899                 "WinSalGraphics::GetKernPairs(): KERNINGPAIR != ImplKernPairData" );
1900 
1901     if ( mbFontKernInit )
1902     {
1903         if( mpFontKernPairs )
1904         {
1905             delete[] mpFontKernPairs;
1906             mpFontKernPairs = NULL;
1907         }
1908         mnFontKernPairCount = 0;
1909 
1910         KERNINGPAIR* pPairs = NULL;
1911         int nCount = ::GetKerningPairsW( getHDC(), 0, NULL );
1912         if( nCount )
1913         {
1914             #ifdef GCP_KERN_HACK
1915             pPairs = new KERNINGPAIR[ nCount+1 ];
1916             mpFontKernPairs = pPairs;
1917             mnFontKernPairCount = nCount;
1918             ::GetKerningPairsW( getHDC(), nCount, pPairs );
1919             #else // GCP_KERN_HACK
1920             pPairs = pKernPairs;
1921             nCount = (nCount < nPairs) : nCount : nPairs;
1922             ::GetKerningPairsW( getHDC(), nCount, pPairs );
1923             return nCount;
1924             #endif // GCP_KERN_HACK
1925         }
1926 
1927         mbFontKernInit = FALSE;
1928 
1929         std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData );
1930     }
1931 
1932     if( !pKernPairs )
1933         return mnFontKernPairCount;
1934     else if( mpFontKernPairs )
1935     {
1936         if ( nPairs < mnFontKernPairCount )
1937             nPairs = mnFontKernPairCount;
1938         memcpy( pKernPairs, mpFontKernPairs,
1939                 nPairs*sizeof( ImplKernPairData ) );
1940         return nPairs;
1941     }
1942 
1943     return 0;
1944 }
1945 
1946 // -----------------------------------------------------------------------
1947 
GetImplFontCharMap() const1948 const ImplFontCharMap* WinSalGraphics::GetImplFontCharMap() const
1949 {
1950     if( !mpWinFontData[0] )
1951         return ImplFontCharMap::GetDefaultMap();
1952     return mpWinFontData[0]->GetImplFontCharMap();
1953 }
1954 
1955 // -----------------------------------------------------------------------
1956 
SalEnumFontsProcExA(const ENUMLOGFONTEXA * pLogFont,const NEWTEXTMETRICEXA * pMetric,DWORD nFontType,LPARAM lParam)1957 int CALLBACK SalEnumFontsProcExA( const ENUMLOGFONTEXA* pLogFont,
1958                                   const NEWTEXTMETRICEXA* pMetric,
1959                                   DWORD nFontType, LPARAM lParam )
1960 {
1961     ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam;
1962     if ( !pInfo->mpName )
1963     {
1964         // Ignore vertical fonts
1965         if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
1966         {
1967             if ( !pInfo->mbImplSalCourierNew )
1968                 pInfo->mbImplSalCourierNew = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0;
1969             if ( !pInfo->mbImplSalCourierScalable )
1970                 pInfo->mbCourier = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0;
1971             else
1972                 pInfo->mbCourier = FALSE;
1973             String aName( ImplSalGetUniString( pLogFont->elfLogFont.lfFaceName ) );
1974             pInfo->mpName = &aName;
1975             strncpy( pInfo->mpLogFontA->lfFaceName, pLogFont->elfLogFont.lfFaceName, LF_FACESIZE );
1976             pInfo->mpLogFontA->lfCharSet = pLogFont->elfLogFont.lfCharSet;
1977             EnumFontFamiliesExA( pInfo->mhDC, pInfo->mpLogFontA, (FONTENUMPROCA)SalEnumFontsProcExA,
1978                                  (LPARAM)(void*)pInfo, 0 );
1979             pInfo->mpLogFontA->lfFaceName[0] = '\0';
1980             pInfo->mpLogFontA->lfCharSet = DEFAULT_CHARSET;
1981             pInfo->mpName = NULL;
1982             pInfo->mbCourier = FALSE;
1983         }
1984     }
1985     else
1986     {
1987         // ignore non-scalable non-device font on printer
1988         if( pInfo->mbPrinter )
1989             if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) )
1990                 return 1;
1991 
1992         ImplWinFontData* pData = ImplLogMetricToDevFontDataA( pLogFont, &(pMetric->ntmTm), nFontType );
1993         pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
1994 
1995         // prefer the system character set, so that we get as much as
1996         // possible important characters. In the other case we could only
1997         // display a limited set of characters (#87309#)
1998         if ( pInfo->mnPreferedCharSet == pLogFont->elfLogFont.lfCharSet )
1999             pData->mnQuality += 100;
2000 
2001         // knowing Courier to be scalable is nice
2002         if( pInfo->mbCourier )
2003             pInfo->mbImplSalCourierScalable |= pData->IsScalable();
2004 
2005         pInfo->mpList->Add( pData );
2006     }
2007 
2008     return 1;
2009 }
2010 
2011 // -----------------------------------------------------------------------
2012 
SalEnumFontsProcExW(const ENUMLOGFONTEXW * pLogFont,const NEWTEXTMETRICEXW * pMetric,DWORD nFontType,LPARAM lParam)2013 int CALLBACK SalEnumFontsProcExW( const ENUMLOGFONTEXW* pLogFont,
2014                                   const NEWTEXTMETRICEXW* pMetric,
2015                                   DWORD nFontType, LPARAM lParam )
2016 {
2017     ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam;
2018     if ( !pInfo->mpName )
2019     {
2020         // Ignore vertical fonts
2021         if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
2022         {
2023             if ( !pInfo->mbImplSalCourierNew )
2024                 pInfo->mbImplSalCourierNew = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0;
2025             if ( !pInfo->mbImplSalCourierScalable )
2026                 pInfo->mbCourier = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0;
2027             else
2028                 pInfo->mbCourier = FALSE;
2029             String aName( reinterpret_cast<const sal_Unicode*>(pLogFont->elfLogFont.lfFaceName) );
2030             pInfo->mpName = &aName;
2031             memcpy( pInfo->mpLogFontW->lfFaceName, pLogFont->elfLogFont.lfFaceName, (aName.Len()+1)*sizeof( wchar_t ) );
2032             pInfo->mpLogFontW->lfCharSet = pLogFont->elfLogFont.lfCharSet;
2033             EnumFontFamiliesExW( pInfo->mhDC, pInfo->mpLogFontW, (FONTENUMPROCW)SalEnumFontsProcExW,
2034                                  (LPARAM)(void*)pInfo, 0 );
2035             pInfo->mpLogFontW->lfFaceName[0] = '\0';
2036             pInfo->mpLogFontW->lfCharSet = DEFAULT_CHARSET;
2037             pInfo->mpName = NULL;
2038             pInfo->mbCourier = FALSE;
2039         }
2040     }
2041     else
2042     {
2043         // ignore non-scalable non-device font on printer
2044         if( pInfo->mbPrinter )
2045             if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) )
2046                 return 1;
2047 
2048         ImplWinFontData* pData = ImplLogMetricToDevFontDataW( pLogFont, &(pMetric->ntmTm), nFontType );
2049         pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
2050 
2051         // knowing Courier to be scalable is nice
2052         if( pInfo->mbCourier )
2053             pInfo->mbImplSalCourierScalable |= pData->IsScalable();
2054 
2055         pInfo->mpList->Add( pData );
2056     }
2057 
2058     return 1;
2059 }
2060 
2061 // -----------------------------------------------------------------------
2062 
2063 struct TempFontItem
2064 {
2065     ::rtl::OUString maFontFilePath;
2066     ::rtl::OString maResourcePath;
2067     TempFontItem* mpNextItem;
2068 };
2069 
2070 #ifdef FR_PRIVATE
__AddFontResourceExW(LPCWSTR lpszfileName,DWORD fl,PVOID pdv)2071 static int WINAPI __AddFontResourceExW( LPCWSTR lpszfileName, DWORD fl, PVOID pdv )
2072 {
2073 	typedef int (WINAPI *AddFontResourceExW_FUNC)(LPCWSTR, DWORD, PVOID );
2074 
2075 	static AddFontResourceExW_FUNC	pFunc = NULL;
2076 	static HMODULE					hmGDI = NULL;
2077 
2078 	if ( !pFunc && !hmGDI )
2079 	{
2080 		hmGDI = GetModuleHandleA( "GDI32" );
2081 		if ( hmGDI )
2082 			pFunc = reinterpret_cast<AddFontResourceExW_FUNC>( GetProcAddress( hmGDI, "AddFontResourceExW" ) );
2083 	}
2084 
2085 	if ( pFunc )
2086 		return pFunc( lpszfileName, fl, pdv );
2087 	else
2088 	{
2089 		SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
2090 		return 0;
2091 	}
2092 }
2093 #endif
2094 
ImplAddTempFont(SalData & rSalData,const String & rFontFileURL)2095 bool ImplAddTempFont( SalData& rSalData, const String& rFontFileURL )
2096 {
2097     int nRet = 0;
2098     ::rtl::OUString aUSytemPath;
2099     OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
2100 
2101 #ifdef FR_PRIVATE
2102     nRet = __AddFontResourceExW( reinterpret_cast<LPCWSTR>(aUSytemPath.getStr()), FR_PRIVATE, NULL );
2103 #endif
2104 
2105 	if ( !nRet )
2106     {
2107         static int nCounter = 0;
2108         char aFileName[] = "soAA.fot";
2109         aFileName[2] = sal::static_int_cast<char>('A' + (15 & (nCounter>>4)));
2110         aFileName[3] = sal::static_int_cast<char>('A' + (15 & nCounter));
2111         char aResourceName[512];
2112         int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16;
2113         int nLen = ::GetTempPathA( nMaxLen, aResourceName );
2114         ::strncpy( aResourceName + nLen, aFileName, sizeof( aResourceName )- nLen );
2115         // security: end buffer in any case
2116         aResourceName[ (sizeof(aResourceName)/sizeof(*aResourceName))-1 ] = 0;
2117         ::DeleteFileA( aResourceName );
2118 
2119         rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
2120         ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
2121         // TODO: font should be private => need to investigate why it doesn't work then
2122         if( !::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL ) )
2123             return false;
2124         ++nCounter;
2125 
2126         nRet = ::AddFontResourceA( aResourceName );
2127         if( nRet > 0 )
2128         {
2129             TempFontItem* pNewItem = new TempFontItem;
2130             pNewItem->maResourcePath = rtl::OString( aResourceName );
2131             pNewItem->maFontFilePath = aUSytemPath.getStr();
2132             pNewItem->mpNextItem = rSalData.mpTempFontItem;
2133             rSalData.mpTempFontItem = pNewItem;
2134         }
2135     }
2136 
2137 	return (nRet > 0);
2138 }
2139 
2140 // -----------------------------------------------------------------------
2141 
ImplReleaseTempFonts(SalData & rSalData)2142 void ImplReleaseTempFonts( SalData& rSalData )
2143 {
2144     int nCount = 0;
2145     while( TempFontItem* p = rSalData.mpTempFontItem )
2146     {
2147         ++nCount;
2148         if( p->maResourcePath.getLength() )
2149         {
2150             const char* pResourcePath = p->maResourcePath.getStr();
2151             ::RemoveFontResourceA( pResourcePath );
2152             ::DeleteFileA( pResourcePath );
2153         }
2154         else
2155         {
2156             ::RemoveFontResourceW( reinterpret_cast<LPCWSTR>(p->maFontFilePath.getStr()) );
2157         }
2158 
2159         rSalData.mpTempFontItem = p->mpNextItem;
2160         delete p;
2161     }
2162 
2163 #ifndef FR_PRIVATE
2164     // notify every other application
2165     // unless the temp fonts were installed as private fonts
2166     if( nCount > 0 )
2167         ::PostMessage( HWND_BROADCAST, WM_FONTCHANGE, 0, NULL );
2168 #endif // FR_PRIVATE
2169 }
2170 
2171 // -----------------------------------------------------------------------
2172 
ImplGetFontAttrFromFile(const String & rFontFileURL,ImplDevFontAttributes & rDFA)2173 static bool ImplGetFontAttrFromFile( const String& rFontFileURL,
2174     ImplDevFontAttributes& rDFA )
2175 {
2176     ::rtl::OUString aUSytemPath;
2177     OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
2178 
2179     // get FontAttributes from a *fot file
2180     // TODO: use GetTTGlobalFontInfo() to access the font directly
2181     rDFA.mnQuality    = 1000;
2182     rDFA.mbDevice     = true;
2183     rDFA.meFamily     = FAMILY_DONTKNOW;
2184     rDFA.meWidthType  = WIDTH_DONTKNOW;
2185     rDFA.meWeight     = WEIGHT_DONTKNOW;
2186     rDFA.meItalic     = ITALIC_DONTKNOW;
2187     rDFA.mePitch      = PITCH_DONTKNOW;;
2188     rDFA.mbSubsettable= true;
2189     rDFA.mbEmbeddable = false;
2190 
2191     // Create temporary file name
2192     char aFileName[] = "soAAT.fot";
2193     char aResourceName[512];
2194     int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16;
2195     int nLen = ::GetTempPathA( nMaxLen, aResourceName );
2196     ::strncpy( aResourceName + nLen, aFileName, Max( 0, nMaxLen - nLen ));
2197     ::DeleteFileA( aResourceName );
2198 
2199     // Create font resource file (typically with a .fot file name extension).
2200     rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
2201     ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
2202     ::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL );
2203 
2204     // Open and read the font resource file
2205     rtl::OUString aFotFileName = rtl::OStringToOUString( aResourceName, osl_getThreadTextEncoding() );
2206     osl::FileBase::getFileURLFromSystemPath( aFotFileName, aFotFileName );
2207     osl::File aFotFile( aFotFileName );
2208     osl::FileBase::RC aError = aFotFile.open( osl_File_OpenFlag_Read );
2209     if( aError != osl::FileBase::E_None )
2210         return false;
2211 
2212     sal_uInt64  nBytesRead = 0;
2213     char        aBuffer[4096];
2214     aFotFile.read( aBuffer, sizeof( aBuffer ), nBytesRead );
2215     // clean up temporary resource file
2216     aFotFile.close();
2217     ::DeleteFileA( aResourceName );
2218 
2219     // retrieve font family name from byte offset 0x4F6
2220     int i = 0x4F6;
2221     int nNameOfs = i;
2222     while( (i < nBytesRead) && (aBuffer[i++] != 0) );
2223     // skip full name
2224     while( (i < nBytesRead) && (aBuffer[i++] != 0) );
2225     // retrieve font style name
2226     int nStyleOfs = i;
2227     while( (i < nBytesRead) && (aBuffer[i++] != 0) );
2228     if( i >= nBytesRead )
2229         return false;
2230 
2231     // convert byte strings to unicode
2232     rDFA.maName      = String( aBuffer + nNameOfs, osl_getThreadTextEncoding() );
2233     rDFA.maStyleName = String( aBuffer + nStyleOfs, osl_getThreadTextEncoding() );
2234 
2235     // byte offset 0x4C7: OS2_fsSelection
2236     const char nFSS = aBuffer[ 0x4C7 ];
2237     if( nFSS & 0x01 )   // italic
2238         rDFA.meItalic = ITALIC_NORMAL;
2239     //if( nFSS & 0x20 )   // bold
2240     //   rDFA.meWeight = WEIGHT_BOLD;
2241     if( nFSS & 0x40 )   // regular
2242     {
2243         rDFA.meWeight = WEIGHT_NORMAL;
2244         rDFA.meItalic = ITALIC_NONE;
2245     }
2246 
2247     // byte offsets 0x4D7/0x4D8: wingdi's FW_WEIGHT
2248     int nWinWeight = (aBuffer[0x4D7] & 0xFF) + ((aBuffer[0x4D8] & 0xFF) << 8);
2249     rDFA.meWeight = ImplWeightToSal( nWinWeight );
2250 
2251     rDFA.mbSymbolFlag = false;          // TODO
2252     rDFA.mePitch      = PITCH_DONTKNOW; // TODO
2253 
2254     // byte offset 0x4DE: pitch&family
2255     rDFA.meFamily = ImplFamilyToSal( aBuffer[0x4DE] );
2256 
2257     // byte offsets 0x4C8/0x4C9: emunits
2258     // byte offsets 0x4CE/0x4CF: winascent
2259     // byte offsets 0x4D0/0x4D1: winascent+windescent-emunits
2260     // byte offsets 0x4DF/0x4E0: avgwidth
2261     //...
2262 
2263     return true;
2264 }
2265 
2266 // -----------------------------------------------------------------------
2267 
AddTempDevFont(ImplDevFontList * pFontList,const String & rFontFileURL,const String & rFontName)2268 bool WinSalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
2269     const String& rFontFileURL, const String& rFontName )
2270 {
2271 	RTL_LOGFILE_TRACE1( "WinSalGraphics::AddTempDevFont(): %s", rtl::OUStringToOString( rFontFileURL, RTL_TEXTENCODING_UTF8 ).getStr() );
2272 
2273     ImplDevFontAttributes aDFA;
2274     aDFA.maName = rFontName;
2275     aDFA.mnQuality    = 1000;
2276     aDFA.mbDevice     = true;
2277 
2278     // Search Font Name in Cache
2279     if( !rFontName.Len() && mpFontAttrCache )
2280         aDFA = mpFontAttrCache->GetFontAttr( rFontFileURL );
2281 
2282     // Retrieve font name from font resource
2283     if( !aDFA.maName.Len() )
2284     {
2285         ImplGetFontAttrFromFile( rFontFileURL, aDFA );
2286         if( mpFontAttrCache && aDFA.maName.Len() )
2287             mpFontAttrCache->AddFontAttr( rFontFileURL, aDFA );
2288     }
2289 
2290     if ( !aDFA.maName.Len() )
2291         return false;
2292 
2293     // remember temp font for cleanup later
2294     if( !ImplAddTempFont( *GetSalData(), rFontFileURL ) )
2295         return false;
2296 
2297     UINT nPreferedCharSet = DEFAULT_CHARSET;
2298 
2299     // create matching FontData struct
2300     aDFA.mbSymbolFlag = false; // TODO: how to know it without accessing the font?
2301     aDFA.meFamily     = FAMILY_DONTKNOW;
2302     aDFA.meWidthType  = WIDTH_DONTKNOW;
2303     aDFA.meWeight     = WEIGHT_DONTKNOW;
2304     aDFA.meItalic     = ITALIC_DONTKNOW;
2305     aDFA.mePitch      = PITCH_DONTKNOW;;
2306     aDFA.mbSubsettable= true;
2307     aDFA.mbEmbeddable = false;
2308 
2309     /*
2310     // TODO: improve ImplDevFontAttributes using the "font resource file"
2311     aDFS.maName = // using "FONTRES:" from file
2312     if( rFontName != aDFS.maName )
2313         aDFS.maMapName = aFontName;
2314     */
2315 
2316     ImplWinFontData* pFontData = new ImplWinFontData( aDFA, 0,
2317         sal::static_int_cast<BYTE>(nPreferedCharSet),
2318         sal::static_int_cast<BYTE>(TMPF_VECTOR|TMPF_TRUETYPE) );
2319     pFontData->SetFontId( reinterpret_cast<sal_IntPtr>(pFontData) );
2320     pFontList->Add( pFontData );
2321     return true;
2322 }
2323 
2324 // -----------------------------------------------------------------------
2325 
GetDevFontList(ImplDevFontList * pFontList)2326 void WinSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
2327 {
2328     // make sure all fonts are registered at least temporarily
2329     static bool bOnce = true;
2330     if( bOnce )
2331     {
2332         bOnce = false;
2333 
2334         // determine font path
2335         // since we are only interested in fonts that could not be
2336         // registered before because of missing administration rights
2337         // only the font path of the user installation is needed
2338         ::rtl::OUString aPath;
2339         osl_getExecutableFile( &aPath.pData );
2340 		::rtl::OUString aExecutableFile( aPath );
2341         aPath = aPath.copy( 0, aPath.lastIndexOf('/') );
2342         String aFontDirUrl = aPath.copy( 0, aPath.lastIndexOf('/') );
2343         aFontDirUrl += String( RTL_CONSTASCII_USTRINGPARAM("/share/fonts/truetype") );
2344 
2345         // collect fonts in font path that could not be registered
2346         osl::Directory aFontDir( aFontDirUrl );
2347         osl::FileBase::RC rcOSL = aFontDir.open();
2348         if( rcOSL == osl::FileBase::E_None )
2349         {
2350             osl::DirectoryItem aDirItem;
2351             String aEmptyString;
2352 
2353 			::rtl::OUString aBootStrap;
2354             rtl::Bootstrap::get( String( RTL_CONSTASCII_USTRINGPARAM( "OOO_BASE_DIR" ) ), aBootStrap );
2355 			aBootStrap += String( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
2356 			rtl::Bootstrap aBootstrap( aBootStrap );
2357 			::rtl::OUString aUserPath;
2358 			aBootstrap.getFrom( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserInstallation" ) ), aUserPath );
2359 			aUserPath += String( RTL_CONSTASCII_USTRINGPARAM("/user/config/fontnames.dat") );
2360 			String aBaseURL = aPath.copy( 0, aPath.lastIndexOf('/')+1 );
2361 			mpFontAttrCache = new ImplFontAttrCache( aUserPath, aBaseURL );
2362 
2363 			while( aFontDir.getNextItem( aDirItem, 10 ) == osl::FileBase::E_None )
2364             {
2365                 osl::FileStatus aFileStatus( FileStatusMask_FileURL );
2366                 rcOSL = aDirItem.getFileStatus( aFileStatus );
2367                 if ( rcOSL == osl::FileBase::E_None )
2368                     AddTempDevFont( pFontList, aFileStatus.getFileURL(), aEmptyString );
2369             }
2370 
2371             delete mpFontAttrCache; // destructor rewrites the cache file if needed
2372             mpFontAttrCache = NULL;
2373         }
2374     }
2375 
2376     ImplEnumInfo aInfo;
2377     aInfo.mhDC          = getHDC();
2378     aInfo.mpList        = pFontList;
2379     aInfo.mpName        = NULL;
2380     aInfo.mpLogFontA    = NULL;
2381     aInfo.mpLogFontW    = NULL;
2382     aInfo.mbCourier     = false;
2383     aInfo.mbPrinter     = mbPrinter;
2384     aInfo.mnFontCount   = 0;
2385     if ( !mbPrinter )
2386     {
2387         aInfo.mbImplSalCourierScalable  = false;
2388         aInfo.mbImplSalCourierNew       = false;
2389     }
2390     else
2391     {
2392         aInfo.mbImplSalCourierScalable  = true;
2393         aInfo.mbImplSalCourierNew       = true;
2394     }
2395 
2396     aInfo.mnPreferedCharSet = DEFAULT_CHARSET;
2397     DWORD nCP = GetACP();
2398     CHARSETINFO aCharSetInfo;
2399     if ( TranslateCharsetInfo( (DWORD*)nCP, &aCharSetInfo, TCI_SRCCODEPAGE ) )
2400         aInfo.mnPreferedCharSet = aCharSetInfo.ciCharset;
2401 
2402     LOGFONTW aLogFont;
2403     memset( &aLogFont, 0, sizeof( aLogFont ) );
2404     aLogFont.lfCharSet = DEFAULT_CHARSET;
2405     aInfo.mpLogFontW = &aLogFont;
2406     EnumFontFamiliesExW( getHDC(), &aLogFont,
2407             (FONTENUMPROCW)SalEnumFontsProcExW, (LPARAM)(void*)&aInfo, 0 );
2408 
2409     // Feststellen, was es fuer Courier-Schriften auf dem Bildschirm gibt,
2410     // um in SetFont() evt. Courier auf Courier New zu mappen
2411     if ( !mbPrinter )
2412     {
2413         bImplSalCourierScalable = aInfo.mbImplSalCourierScalable;
2414         bImplSalCourierNew      = aInfo.mbImplSalCourierNew;
2415     }
2416 
2417 	// set glyph fallback hook
2418 	static WinGlyphFallbackSubstititution aSubstFallback( getHDC() );
2419 	pFontList->SetFallbackHook( &aSubstFallback );
2420 }
2421 
2422 // ----------------------------------------------------------------------------
2423 
GetDevFontSubstList(OutputDevice *)2424 void WinSalGraphics::GetDevFontSubstList( OutputDevice* )
2425 {}
2426 
2427 // -----------------------------------------------------------------------
2428 
GetGlyphBoundRect(sal_GlyphId aGlyphId,Rectangle & rRect)2429 bool WinSalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect )
2430 {
2431     HDC hDC = getHDC();
2432 
2433     // use unity matrix
2434     MAT2 aMat;
2435     aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
2436     aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
2437 
2438     UINT nGGOFlags = GGO_METRICS;
2439     if( !(aGlyphId & GF_ISCHAR) )
2440         nGGOFlags |= GGO_GLYPH_INDEX;
2441     aGlyphId &= GF_IDXMASK;
2442 
2443     GLYPHMETRICS aGM;
2444     aGM.gmptGlyphOrigin.x = aGM.gmptGlyphOrigin.y = 0;
2445     aGM.gmBlackBoxX = aGM.gmBlackBoxY = 0;
2446     DWORD nSize = ::GetGlyphOutlineW( hDC, aGlyphId, nGGOFlags, &aGM, 0, NULL, &aMat );
2447     if( nSize == GDI_ERROR )
2448         return false;
2449 
2450     rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
2451         Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
2452     rRect.Left()    = static_cast<int>( mfFontScale * rRect.Left() );
2453     rRect.Right()   = static_cast<int>( mfFontScale * rRect.Right() );
2454     rRect.Top()     = static_cast<int>( mfFontScale * rRect.Top() );
2455     rRect.Bottom()  = static_cast<int>( mfFontScale * rRect.Bottom() );
2456     return true;
2457 }
2458 
2459 // -----------------------------------------------------------------------
2460 
GetGlyphOutline(sal_GlyphId aGlyphId,::basegfx::B2DPolyPolygon & rB2DPolyPoly)2461 bool WinSalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId,
2462     ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
2463 {
2464     rB2DPolyPoly.clear();
2465 
2466     HDC  hDC = getHDC();
2467 
2468     // use unity matrix
2469     MAT2 aMat;
2470     aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
2471     aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
2472 
2473     UINT nGGOFlags = GGO_NATIVE;
2474     if( !(aGlyphId & GF_ISCHAR) )
2475         nGGOFlags |= GGO_GLYPH_INDEX;
2476     aGlyphId &= GF_IDXMASK;
2477 
2478     GLYPHMETRICS aGlyphMetrics;
2479     const DWORD nSize1 = ::GetGlyphOutlineW( hDC, aGlyphId, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
2480     if( !nSize1 )       // blank glyphs are ok
2481         return true;
2482     else if( nSize1 == GDI_ERROR )
2483         return false;
2484 
2485     BYTE* pData = new BYTE[ nSize1 ];
2486     const DWORD nSize2 = ::GetGlyphOutlineW( hDC, aGlyphId, nGGOFlags,
2487               &aGlyphMetrics, nSize1, pData, &aMat );
2488 
2489     if( nSize1 != nSize2 )
2490         return false;
2491 
2492     // TODO: avoid tools polygon by creating B2DPolygon directly
2493     int     nPtSize = 512;
2494     Point*  pPoints = new Point[ nPtSize ];
2495     BYTE*   pFlags = new BYTE[ nPtSize ];
2496 
2497     TTPOLYGONHEADER* pHeader = (TTPOLYGONHEADER*)pData;
2498     while( (BYTE*)pHeader < pData+nSize2 )
2499     {
2500         // only outline data is interesting
2501         if( pHeader->dwType != TT_POLYGON_TYPE )
2502             break;
2503 
2504         // get start point; next start points are end points
2505         // of previous segment
2506         USHORT nPnt = 0;
2507 
2508         long nX = IntTimes256FromFixed( pHeader->pfxStart.x );
2509         long nY = IntTimes256FromFixed( pHeader->pfxStart.y );
2510         pPoints[ nPnt ] = Point( nX, nY );
2511         pFlags[ nPnt++ ] = POLY_NORMAL;
2512 
2513         bool bHasOfflinePoints = false;
2514         TTPOLYCURVE* pCurve = (TTPOLYCURVE*)( pHeader + 1 );
2515         pHeader = (TTPOLYGONHEADER*)( (BYTE*)pHeader + pHeader->cb );
2516         while( (BYTE*)pCurve < (BYTE*)pHeader )
2517         {
2518             int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx;
2519             if( nPtSize < nNeededSize )
2520             {
2521                 Point* pOldPoints = pPoints;
2522                 BYTE* pOldFlags = pFlags;
2523                 nPtSize = 2 * nNeededSize;
2524                 pPoints = new Point[ nPtSize ];
2525                 pFlags = new BYTE[ nPtSize ];
2526                 for( USHORT i = 0; i < nPnt; ++i )
2527                 {
2528                     pPoints[ i ] = pOldPoints[ i ];
2529                     pFlags[ i ] = pOldFlags[ i ];
2530                 }
2531                 delete[] pOldPoints;
2532                 delete[] pOldFlags;
2533             }
2534 
2535             int i = 0;
2536             if( TT_PRIM_LINE == pCurve->wType )
2537             {
2538                 while( i < pCurve->cpfx )
2539                 {
2540                     nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2541                     nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2542                     ++i;
2543                     pPoints[ nPnt ] = Point( nX, nY );
2544                     pFlags[ nPnt ] = POLY_NORMAL;
2545                     ++nPnt;
2546                 }
2547             }
2548             else if( TT_PRIM_QSPLINE == pCurve->wType )
2549             {
2550                 bHasOfflinePoints = true;
2551                 while( i < pCurve->cpfx )
2552                 {
2553                     // get control point of quadratic bezier spline
2554                     nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2555                     nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2556                     ++i;
2557                     Point aControlP( nX, nY );
2558 
2559                     // calculate first cubic control point
2560                     // P0 = 1/3 * (PBeg + 2 * PQControl)
2561                     nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X();
2562                     nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y();
2563                     pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
2564                     pFlags[ nPnt+0 ] = POLY_CONTROL;
2565 
2566                     // calculate endpoint of segment
2567                     nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2568                     nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2569 
2570                     if ( i+1 >= pCurve->cpfx )
2571                     {
2572                         // endpoint is either last point in segment => advance
2573                         ++i;
2574                     }
2575                     else
2576                     {
2577                         // or endpoint is the middle of two control points
2578                         nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x );
2579                         nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y );
2580                         nX = (nX + 1) / 2;
2581                         nY = (nY + 1) / 2;
2582                         // no need to advance, because the current point
2583                         // is the control point in next bezier spline
2584                     }
2585 
2586                     pPoints[ nPnt+2 ] = Point( nX, nY );
2587                     pFlags[ nPnt+2 ] = POLY_NORMAL;
2588 
2589                     // calculate second cubic control point
2590                     // P1 = 1/3 * (PEnd + 2 * PQControl)
2591                     nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X();
2592                     nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y();
2593                     pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
2594                     pFlags[ nPnt+1 ] = POLY_CONTROL;
2595 
2596                     nPnt += 3;
2597                 }
2598             }
2599 
2600             // next curve segment
2601             pCurve = (TTPOLYCURVE*)&pCurve->apfx[ i ];
2602         }
2603 
2604         // end point is start point for closed contour
2605         // disabled, because Polygon class closes the contour itself
2606         // pPoints[nPnt++] = pPoints[0];
2607         // #i35928#
2608         // Added again, but add only when not yet closed
2609         if(pPoints[nPnt - 1] != pPoints[0])
2610         {
2611             if( bHasOfflinePoints )
2612                 pFlags[nPnt] = pFlags[0];
2613 
2614             pPoints[nPnt++] = pPoints[0];
2615         }
2616 
2617         // convert y-coordinates W32 -> VCL
2618         for( int i = 0; i < nPnt; ++i )
2619             pPoints[i].Y() = -pPoints[i].Y();
2620 
2621         // insert into polypolygon
2622         Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : NULL) );
2623         // convert to B2DPolyPolygon
2624         // TODO: get rid of the intermediate PolyPolygon
2625         rB2DPolyPoly.append( aPoly.getB2DPolygon() );
2626     }
2627 
2628     delete[] pPoints;
2629     delete[] pFlags;
2630 
2631     delete[] pData;
2632 
2633     // rescaling needed for the PolyPolygon conversion
2634     if( rB2DPolyPoly.count() )
2635     {
2636 		const double fFactor(mfFontScale/256);
2637 		rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fFactor, fFactor));
2638     }
2639 
2640     return true;
2641 }
2642 
2643 // -----------------------------------------------------------------------
2644 
2645 class ScopedFont
2646 {
2647 public:
2648     explicit ScopedFont(WinSalGraphics & rData);
2649 
2650     ~ScopedFont();
2651 
2652 private:
2653     WinSalGraphics & m_rData;
2654     HFONT m_hOrigFont;
2655 };
2656 
ScopedFont(WinSalGraphics & rData)2657 ScopedFont::ScopedFont(WinSalGraphics & rData): m_rData(rData)
2658 {
2659     m_hOrigFont = m_rData.mhFonts[0];
2660     m_rData.mhFonts[0] = 0; // avoid deletion of current font
2661 }
2662 
~ScopedFont()2663 ScopedFont::~ScopedFont()
2664 {
2665     if( m_hOrigFont )
2666     {
2667         // restore original font, destroy temporary font
2668         HFONT hTempFont = m_rData.mhFonts[0];
2669         m_rData.mhFonts[0] = m_hOrigFont;
2670         SelectObject( m_rData.getHDC(), m_hOrigFont );
2671         DeleteObject( hTempFont );
2672     }
2673 }
2674 
2675 class ScopedTrueTypeFont
2676 {
2677 public:
ScopedTrueTypeFont()2678     inline ScopedTrueTypeFont(): m_pFont(0) {}
2679 
2680     ~ScopedTrueTypeFont();
2681 
2682     int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum);
2683 
get() const2684     inline TrueTypeFont * get() const { return m_pFont; }
2685 
2686 private:
2687     TrueTypeFont * m_pFont;
2688 };
2689 
~ScopedTrueTypeFont()2690 ScopedTrueTypeFont::~ScopedTrueTypeFont()
2691 {
2692     if (m_pFont != 0)
2693         CloseTTFont(m_pFont);
2694 }
2695 
open(void * pBuffer,sal_uInt32 nLen,sal_uInt32 nFaceNum)2696 int ScopedTrueTypeFont::open(void * pBuffer, sal_uInt32 nLen,
2697                              sal_uInt32 nFaceNum)
2698 {
2699     OSL_ENSURE(m_pFont == 0, "already open");
2700     return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont);
2701 }
2702 
CreateFontSubset(const rtl::OUString & rToFile,const ImplFontData * pFont,sal_GlyphId * pGlyphIds,sal_uInt8 * pEncoding,sal_Int32 * pGlyphWidths,int nGlyphCount,FontSubsetInfo & rInfo)2703 sal_Bool WinSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
2704     const ImplFontData* pFont, sal_GlyphId* pGlyphIds, sal_uInt8* pEncoding,
2705     sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
2706 {
2707     // TODO: use more of the central font-subsetting code, move stuff there if needed
2708 
2709     // create matching ImplFontSelectData
2710     // we need just enough to get to the font file data
2711     // use height=1000 for easier debugging (to match psprint's font units)
2712     ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2713 
2714     // TODO: much better solution: move SetFont and restoration of old font to caller
2715     ScopedFont aOldFont(*this);
2716     float fScale = 1.0;
2717     HFONT hOldFont = 0;
2718     ImplDoSetFont( &aIFSD, fScale, hOldFont );
2719 
2720     ImplWinFontData* pWinFontData = (ImplWinFontData*)aIFSD.mpFontData;
2721 
2722 #if OSL_DEBUG_LEVEL > 1
2723     // get font metrics
2724     TEXTMETRICA aWinMetric;
2725     if( !::GetTextMetricsA( getHDC(), &aWinMetric ) )
2726         return FALSE;
2727 
2728     DBG_ASSERT( !(aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "cannot subset device font" );
2729     DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" );
2730 #endif
2731 
2732     rtl::OUString aSysPath;
2733     if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
2734         return FALSE;
2735     const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
2736     const ByteString aToFile( aSysPath.getStr(), (xub_StrLen)aSysPath.getLength(), aThreadEncoding );
2737 
2738 	// check if the font has a CFF-table
2739 	const DWORD nCffTag = CalcTag( "CFF " );
2740 	const RawFontData aRawCffData( getHDC(), nCffTag );
2741 	if( aRawCffData.get() )
2742 	{
2743 		pWinFontData->UpdateFromHDC( getHDC() );
2744 		const ImplFontCharMap* pCharMap = pWinFontData->GetImplFontCharMap();
2745 		pCharMap->AddReference();
2746 
2747 		sal_GlyphId aRealGlyphIds[ 256 ];
2748 		for( int i = 0; i < nGlyphCount; ++i )
2749 		{
2750 			// TODO: remap notdef glyph if needed
2751 			// TODO: use GDI's GetGlyphIndices instead? Does it handle GSUB properly?
2752 			sal_GlyphId aGlyphId = pGlyphIds[i] & GF_IDXMASK;
2753 			if( pGlyphIds[i] & GF_ISCHAR ) // remaining pseudo-glyphs need to be translated
2754 				aGlyphId = pCharMap->GetGlyphIndex( aGlyphId );
2755 			if( (pGlyphIds[i] & (GF_ROTMASK|GF_GSUB)) != 0)	// TODO: vertical substitution
2756 				{/*####*/}
2757 
2758 			aRealGlyphIds[i] = aGlyphId;
2759 		}
2760 
2761 		pCharMap->DeReference(); // TODO: and and use a RAII object
2762 
2763 		// provide a font subset from the CFF-table
2764 		FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
2765 		rInfo.LoadFont( FontSubsetInfo::CFF_FONT, aRawCffData.get(), aRawCffData.size() );
2766 		bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL,
2767 				aRealGlyphIds, pEncoding, nGlyphCount, pGlyphWidths );
2768 		fclose( pOutFile );
2769 		return bRC;
2770 	}
2771 
2772     // get raw font file data
2773     const RawFontData xRawFontData( getHDC(), NULL );
2774     if( !xRawFontData.get() )
2775 		return FALSE;
2776 
2777     // open font file
2778     sal_uInt32 nFaceNum = 0;
2779     if( !*xRawFontData.get() )  // TTC candidate
2780         nFaceNum = ~0U;  // indicate "TTC font extracts only"
2781 
2782     ScopedTrueTypeFont aSftTTF;
2783     int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
2784     if( nRC != SF_OK )
2785         return FALSE;
2786 
2787     TTGlobalFontInfo aTTInfo;
2788     ::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
2789     rInfo.m_nFontType   = FontSubsetInfo::SFNT_TTF;
2790     rInfo.m_aPSName     = ImplSalGetUniString( aTTInfo.psname );
2791     rInfo.m_nAscent	    = aTTInfo.winAscent;
2792     rInfo.m_nDescent    = aTTInfo.winDescent;
2793     rInfo.m_aFontBBox	= Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
2794                                     Point( aTTInfo.xMax, aTTInfo.yMax ) );
2795     rInfo.m_nCapHeight	= aTTInfo.yMax; // Well ...
2796 
2797     // subset TTF-glyphs and get their properties
2798     // take care that subset fonts require the NotDef glyph in pos 0
2799     int nOrigCount = nGlyphCount;
2800     sal_uInt16    aShortIDs[ 256 ];
2801     sal_uInt8 aTempEncs[ 256 ];
2802 
2803     int nNotDef=-1, i;
2804     for( i = 0; i < nGlyphCount; ++i )
2805     {
2806         aTempEncs[i] = pEncoding[i];
2807         sal_GlyphId aGlyphId = pGlyphIds[i] & GF_IDXMASK;
2808         if( pGlyphIds[i] & GF_ISCHAR )
2809         {
2810         	sal_Unicode cChar = static_cast<sal_Unicode>(aGlyphId); // TODO: sal_UCS4
2811         	const bool bVertical = ((pGlyphIds[i] & (GF_ROTMASK|GF_GSUB)) != 0);
2812             aGlyphId = ::MapChar( aSftTTF.get(), cChar, bVertical );
2813             if( (aGlyphId == 0) && pFont->IsSymbolFont() )
2814             {
2815                 // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
2816                 cChar = (cChar & 0xF000) ? (cChar & 0x00FF) : (cChar | 0xF000);
2817                 aGlyphId = ::MapChar( aSftTTF.get(), cChar, bVertical );
2818             }
2819         }
2820         aShortIDs[i] = static_cast<sal_uInt16>( aGlyphId );
2821         if( !aGlyphId )
2822             if( nNotDef < 0 )
2823                 nNotDef = i; // first NotDef glyph found
2824     }
2825 
2826     if( nNotDef != 0 )
2827     {
2828         // add fake NotDef glyph if needed
2829         if( nNotDef < 0 )
2830             nNotDef = nGlyphCount++;
2831 
2832         // NotDef glyph must be in pos 0 => swap glyphids
2833         aShortIDs[ nNotDef ] = aShortIDs[0];
2834         aTempEncs[ nNotDef ] = aTempEncs[0];
2835         aShortIDs[0] = 0;
2836         aTempEncs[0] = 0;
2837     }
2838     DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
2839 
2840     // fill pWidth array
2841     TTSimpleGlyphMetrics* pMetrics =
2842         ::GetTTSimpleGlyphMetrics( aSftTTF.get(), aShortIDs, nGlyphCount, aIFSD.mbVertical );
2843     if( !pMetrics )
2844         return FALSE;
2845     sal_uInt16 nNotDefAdv   = pMetrics[0].adv;
2846     pMetrics[0].adv         = pMetrics[nNotDef].adv;
2847     pMetrics[nNotDef].adv   = nNotDefAdv;
2848     for( i = 0; i < nOrigCount; ++i )
2849         pGlyphWidths[i] = pMetrics[i].adv;
2850     free( pMetrics );
2851 
2852     // write subset into destination file
2853     nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.GetBuffer(), aShortIDs,
2854             aTempEncs, nGlyphCount, 0, NULL, 0 );
2855     return (nRC == SF_OK);
2856 }
2857 
2858 //--------------------------------------------------------------------------
2859 
GetEmbedFontData(const ImplFontData * pFont,const sal_Unicode * pUnicodes,sal_Int32 * pCharWidths,FontSubsetInfo & rInfo,long * pDataLen)2860 const void* WinSalGraphics::GetEmbedFontData( const ImplFontData* pFont,
2861     const sal_Unicode* pUnicodes, sal_Int32* pCharWidths,
2862     FontSubsetInfo& rInfo, long* pDataLen )
2863 {
2864     // create matching ImplFontSelectData
2865     // we need just enough to get to the font file data
2866     ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2867 
2868     // TODO: much better solution: move SetFont and restoration of old font to caller
2869     ScopedFont aOldFont(*this);
2870     SetFont( &aIFSD, 0 );
2871 
2872     // get the raw font file data
2873     RawFontData aRawFontData( getHDC() );
2874     *pDataLen = aRawFontData.size();
2875     if( !aRawFontData.get() )
2876         return NULL;
2877 
2878     // get important font properties
2879     TEXTMETRICA aTm;
2880     if( !::GetTextMetricsA( getHDC(), &aTm ) )
2881         *pDataLen = 0;
2882     const bool bPFA = (*aRawFontData.get() < 0x80);
2883     rInfo.m_nFontType = bPFA ? FontSubsetInfo::TYPE1_PFA : FontSubsetInfo::TYPE1_PFB;
2884     WCHAR aFaceName[64];
2885     int nFNLen = ::GetTextFaceW( getHDC(), 64, aFaceName );
2886     // #i59854# strip eventual null byte
2887     while( nFNLen > 0 && aFaceName[nFNLen-1] == 0 )
2888         nFNLen--;
2889     if( nFNLen == 0 )
2890         *pDataLen = 0;
2891     rInfo.m_aPSName     = String( reinterpret_cast<const sal_Unicode*>(aFaceName), sal::static_int_cast<sal_uInt16>(nFNLen) );
2892     rInfo.m_nAscent     = +aTm.tmAscent;
2893     rInfo.m_nDescent    = -aTm.tmDescent;
2894     rInfo.m_aFontBBox   = Rectangle( Point( -aTm.tmOverhang, -aTm.tmDescent ),
2895               Point( aTm.tmMaxCharWidth, aTm.tmAscent+aTm.tmExternalLeading ) );
2896     rInfo.m_nCapHeight  = aTm.tmAscent; // Well ...
2897 
2898     // get individual character widths
2899     for( int i = 0; i < 256; ++i )
2900     {
2901         int nCharWidth = 0;
2902         const sal_Unicode cChar = pUnicodes[i];
2903         if( !::GetCharWidth32W( getHDC(), cChar, cChar, &nCharWidth ) )
2904             *pDataLen = 0;
2905         pCharWidths[i] = nCharWidth;
2906     }
2907 
2908     if( !*pDataLen )
2909         return NULL;
2910 
2911 	const unsigned char* pData = aRawFontData.steal();
2912     return (void*)pData;
2913 }
2914 
2915 //--------------------------------------------------------------------------
2916 
FreeEmbedFontData(const void * pData,long)2917 void WinSalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ )
2918 {
2919     delete[] reinterpret_cast<char*>(const_cast<void*>(pData));
2920 }
2921 
2922 //--------------------------------------------------------------------------
2923 
GetFontEncodingVector(const ImplFontData * pFont,const Ucs2OStrMap ** pNonEncoded)2924 const Ucs2SIntMap* WinSalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
2925 {
2926     // TODO: even for builtin fonts we get here... why?
2927     if( !pFont->IsEmbeddable() )
2928         return NULL;
2929 
2930     // fill the encoding vector
2931     // currently no nonencoded vector
2932     if( pNonEncoded )
2933         *pNonEncoded = NULL;
2934 
2935     const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>(pFont);
2936     const Ucs2SIntMap* pEncoding = pWinFontData->GetEncodingVector();
2937     if( pEncoding == NULL )
2938     {
2939         Ucs2SIntMap* pNewEncoding = new Ucs2SIntMap;
2940         #if 0
2941         // TODO: get correct encoding vector
2942         GLYPHSET aGlyphSet;
2943         aGlyphSet.cbThis = sizeof(aGlyphSet);
2944         DWORD aW = ::GetFontUnicodeRanges( getHDC(), &aGlyphSet);
2945         #else
2946         for( sal_Unicode i = 32; i < 256; ++i )
2947             (*pNewEncoding)[i] = i;
2948         #endif
2949         pWinFontData->SetEncodingVector( pNewEncoding );
2950 	pEncoding = pNewEncoding;
2951     }
2952 
2953     return pEncoding;
2954 }
2955 
2956 //--------------------------------------------------------------------------
2957 
GetGlyphWidths(const ImplFontData * pFont,bool bVertical,Int32Vector & rWidths,Ucs2UIntMap & rUnicodeEnc)2958 void WinSalGraphics::GetGlyphWidths( const ImplFontData* pFont,
2959                                      bool bVertical,
2960                                      Int32Vector& rWidths,
2961                                      Ucs2UIntMap& rUnicodeEnc )
2962 {
2963     // create matching ImplFontSelectData
2964     // we need just enough to get to the font file data
2965     ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2966 
2967     // TODO: much better solution: move SetFont and restoration of old font to caller
2968     ScopedFont aOldFont(*this);
2969 
2970     float fScale = 0.0;
2971     HFONT hOldFont = 0;
2972     ImplDoSetFont( &aIFSD, fScale, hOldFont );
2973 
2974     if( pFont->IsSubsettable() )
2975     {
2976         // get raw font file data
2977         const RawFontData xRawFontData( getHDC() );
2978 	    if( !xRawFontData.get() )
2979 			return;
2980 
2981         // open font file
2982         sal_uInt32 nFaceNum = 0;
2983         if( !*xRawFontData.get() )  // TTC candidate
2984             nFaceNum = ~0U;  // indicate "TTC font extracts only"
2985 
2986         ScopedTrueTypeFont aSftTTF;
2987         int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
2988         if( nRC != SF_OK )
2989             return;
2990 
2991         int nGlyphs = GetTTGlyphCount( aSftTTF.get() );
2992         if( nGlyphs > 0 )
2993         {
2994             rWidths.resize(nGlyphs);
2995             std::vector<sal_uInt16> aGlyphIds(nGlyphs);
2996             for( int i = 0; i < nGlyphs; i++ )
2997                 aGlyphIds[i] = sal_uInt16(i);
2998             TTSimpleGlyphMetrics* pMetrics = ::GetTTSimpleGlyphMetrics( aSftTTF.get(),
2999                                                                         &aGlyphIds[0],
3000                                                                         nGlyphs,
3001                                                                         bVertical ? 1 : 0 );
3002             if( pMetrics )
3003             {
3004                 for( int i = 0; i< nGlyphs; i++ )
3005                     rWidths[i] = pMetrics[i].adv;
3006                 free( pMetrics );
3007                 rUnicodeEnc.clear();
3008             }
3009             const ImplWinFontData* pWinFont = static_cast<const ImplWinFontData*>(pFont);
3010             const ImplFontCharMap* pMap = pWinFont->GetImplFontCharMap();
3011 			DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" );
3012 			pMap->AddReference();
3013 
3014 			int nCharCount = pMap->GetCharCount();
3015             sal_uInt32 nChar = pMap->GetFirstChar();
3016 			for( int i = 0; i < nCharCount; i++ )
3017             {
3018                 if( nChar < 0x00010000 )
3019                 {
3020                     sal_uInt16 nGlyph = ::MapChar( aSftTTF.get(),
3021                                                    static_cast<sal_Ucs>(nChar),
3022                                                    bVertical ? 1 : 0 );
3023                     if( nGlyph )
3024                         rUnicodeEnc[ static_cast<sal_Unicode>(nChar) ] = nGlyph;
3025                 }
3026 				nChar = pMap->GetNextChar( nChar );
3027             }
3028 
3029 			pMap->DeReference(); // TODO: and and use a RAII object
3030         }
3031     }
3032     else if( pFont->IsEmbeddable() )
3033     {
3034         // get individual character widths
3035         rWidths.clear();
3036         rUnicodeEnc.clear();
3037         rWidths.reserve( 224 );
3038         for( sal_Unicode i = 32; i < 256; ++i )
3039         {
3040             int nCharWidth = 0;
3041             if( ::GetCharWidth32W( getHDC(), i, i, &nCharWidth ) )
3042             {
3043                 rUnicodeEnc[ i ] = rWidths.size();
3044                 rWidths.push_back( nCharWidth );
3045             }
3046         }
3047     }
3048 }
3049 
3050 //--------------------------------------------------------------------------
3051 
DrawServerFontLayout(const ServerFontLayout &)3052 void WinSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
3053 {}
3054 
3055 //--------------------------------------------------------------------------
3056 
GetSysFontData(int nFallbacklevel) const3057 SystemFontData WinSalGraphics::GetSysFontData( int nFallbacklevel ) const
3058 {
3059     SystemFontData aSysFontData;
3060 
3061     if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
3062     if (nFallbacklevel < 0 ) nFallbacklevel = 0;
3063 
3064     aSysFontData.nSize = sizeof( SystemFontData );
3065     aSysFontData.hFont = mhFonts[nFallbacklevel];
3066     aSysFontData.bFakeBold = false;
3067     aSysFontData.bFakeItalic = false;
3068     aSysFontData.bAntialias = true;
3069     aSysFontData.bVerticalCharacterType = false;
3070 
3071     OSL_TRACE("\r\n:WinSalGraphics::GetSysFontData(): FontID: %p, Fallback level: %d",
3072               aSysFontData.hFont,
3073               nFallbacklevel);
3074 
3075     return aSysFontData;
3076 }
3077 
3078 //--------------------------------------------------------------------------
3079 
3080