Branch libreoffice-5-0-4
[LibreOffice.git] / vcl / win / source / gdi / salgdi3.cxx
blob419fa26a9dc3dac9b5cdb89f36f682a4130c9881
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/types.h>
21 #include <config_folders.h>
23 #include <algorithm>
24 #include <malloc.h>
25 #include <map>
26 #include <set>
27 #include <string.h>
28 #include <svsys.h>
29 #include <vector>
31 #include <basegfx/matrix/b2dhommatrixtools.hxx>
32 #include <basegfx/polygon/b2dpolygon.hxx>
33 #include <i18nlangtag/mslangid.hxx>
34 #include <osl/file.hxx>
35 #include <osl/process.h>
36 #include <rtl/bootstrap.hxx>
37 #include <tools/helpers.hxx>
38 #include <tools/stream.hxx>
39 #include <unotools/fontcfg.hxx>
40 #include <vcl/settings.hxx>
41 #include <vcl/sysdata.hxx>
42 #include <vcl/metric.hxx>
44 #include "fontsubset.hxx"
45 #include "outdev.h"
46 #include "PhysicalFontCollection.hxx"
47 #include "PhysicalFontFace.hxx"
48 #include "sft.hxx"
49 #include "win/saldata.hxx"
50 #include "win/salgdi.h"
52 using namespace vcl;
54 static const int MAXFONTHEIGHT = 2048;
56 // - Inlines -
58 inline FIXED FixedFromDouble( double d )
60 const long l = (long) ( d * 65536. );
61 return *(FIXED*) &l;
64 inline int IntTimes256FromFixed(FIXED f)
66 int nFixedTimes256 = (f.value << 8) + ((f.fract+0x80) >> 8);
67 return nFixedTimes256;
70 // these variables can be static because they store system wide settings
71 static bool bImplSalCourierScalable = false;
72 static bool bImplSalCourierNew = false;
74 // TODO: also support temporary TTC font files
75 typedef std::map< OUString, ImplDevFontAttributes > FontAttrMap;
77 class ImplFontAttrCache
79 private:
80 FontAttrMap aFontAttributes;
81 OUString aCacheFileName;
82 OUString aBaseURL;
83 bool bModified;
85 protected:
86 OUString OptimizeURL( const OUString& rURL ) const;
88 enum{ MAGIC = 0x12349876 }; // change if fontattrcache format changes
90 public:
91 ImplFontAttrCache(const OUString& rCacheFileName,
92 const OUString& rBaseURL);
93 ~ImplFontAttrCache();
95 ImplDevFontAttributes GetFontAttr( const OUString& rFontFileName ) const;
96 void AddFontAttr( const OUString& rFontFileName, const ImplDevFontAttributes& );
99 ImplFontAttrCache::ImplFontAttrCache( const OUString& rFileNameURL, const OUString& rBaseURL ) : aBaseURL( rBaseURL )
101 bModified = FALSE;
102 aBaseURL = aBaseURL.toAsciiLowerCase(); // Windows only, no problem...
104 // open the cache file
105 osl::FileBase::getSystemPathFromFileURL( rFileNameURL, aCacheFileName );
106 SvFileStream aCacheFile( aCacheFileName, StreamMode::READ );
107 if( !aCacheFile.IsOpen() )
108 return;
110 // check the cache version
111 sal_uInt32 nCacheMagic;
112 aCacheFile.ReadUInt32(nCacheMagic);
113 if( nCacheMagic != ImplFontAttrCache::MAGIC )
114 return; // ignore cache and rewrite if no match
116 // read the cache entries from the file
117 OUString aFontFileURL;
118 ImplDevFontAttributes aDFA;
119 for(;;)
121 aFontFileURL = read_uInt16_lenPrefixed_uInt8s_ToOUString(aCacheFile, RTL_TEXTENCODING_UTF8);
122 if( aFontFileURL.isEmpty() )
123 break;
124 aDFA.SetFamilyName(read_uInt16_lenPrefixed_uInt8s_ToOUString(aCacheFile, RTL_TEXTENCODING_UTF8));
126 short n;
127 aCacheFile.ReadInt16(n);
128 aDFA.SetWeight(static_cast<FontWeight>(n));
129 aCacheFile.ReadInt16(n);
130 aDFA.SetItalic(static_cast<FontItalic>(n));
131 aCacheFile.ReadInt16(n);
132 aDFA.SetPitch(static_cast<FontPitch>(n));
133 aCacheFile.ReadInt16(n);
134 aDFA.SetWidthType(static_cast<FontWidth>(n));
135 aCacheFile.ReadInt16(n);
136 aDFA.SetFamilyType(static_cast<FontFamily>(n));
137 aCacheFile.ReadInt16(n);
138 aDFA.SetSymbolFlag(n != 0);
140 OUString styleName;
141 aCacheFile.ReadByteStringLine( styleName, RTL_TEXTENCODING_UTF8 );
142 aDFA.SetStyleName( styleName );
144 aFontAttributes[ aFontFileURL ] = aDFA;
148 ImplFontAttrCache::~ImplFontAttrCache()
150 if ( bModified )
152 SvFileStream aCacheFile( aCacheFileName, StreamMode::WRITE|StreamMode::TRUNC );
153 if ( aCacheFile.IsWritable() )
155 sal_uInt32 nCacheMagic = ImplFontAttrCache::MAGIC;
156 aCacheFile.WriteUInt32( nCacheMagic );
158 // write the cache entries to the file
159 FontAttrMap::const_iterator aIter = aFontAttributes.begin();
160 while ( aIter != aFontAttributes.end() )
162 const OUString rFontFileURL( (*aIter).first );
163 const ImplDevFontAttributes& rDFA( (*aIter).second );
164 write_uInt16_lenPrefixed_uInt8s_FromOUString(aCacheFile, rFontFileURL, RTL_TEXTENCODING_UTF8);
165 write_uInt16_lenPrefixed_uInt8s_FromOUString(aCacheFile, rDFA.GetFamilyName(), RTL_TEXTENCODING_UTF8);
167 aCacheFile.WriteInt16(rDFA.GetWeight());
168 aCacheFile.WriteInt16(rDFA.GetSlant());
169 aCacheFile.WriteInt16(rDFA.GetPitch());
170 aCacheFile.WriteInt16(rDFA.GetWidthType());
171 aCacheFile.WriteInt16(rDFA.GetFamilyType());
172 aCacheFile.WriteInt16(rDFA.IsSymbolFont());
174 write_uInt16_lenPrefixed_uInt8s_FromOUString(aCacheFile, rDFA.GetStyleName(), RTL_TEXTENCODING_UTF8);
176 ++aIter;
178 // EOF Marker
179 write_uInt16_lenPrefixed_uInt8s_FromOString(aCacheFile, OString());
184 OUString ImplFontAttrCache::OptimizeURL( const OUString& rURL ) const
186 OUString aOptimizedFontFileURL( rURL.toAsciiLowerCase() );
187 if ( aOptimizedFontFileURL.startsWith( aBaseURL ) )
188 aOptimizedFontFileURL = aOptimizedFontFileURL.copy( aBaseURL.getLength() );
189 return aOptimizedFontFileURL;
192 ImplDevFontAttributes ImplFontAttrCache::GetFontAttr( const OUString& rFontFileName ) const
194 ImplDevFontAttributes aDFA;
195 FontAttrMap::const_iterator it = aFontAttributes.find( OptimizeURL( rFontFileName ) );
196 if( it != aFontAttributes.end() )
198 aDFA = it->second;
200 return aDFA;
203 void ImplFontAttrCache::AddFontAttr( const OUString& rFontFileName, const ImplDevFontAttributes& rDFA )
205 SAL_WARN_IF(rFontFileName.isEmpty() || rDFA.GetFamilyName().isEmpty(),
206 "vcl.gdi", "ImplFontNameCache::AddFontName - invalid data!");
207 if ( !rFontFileName.isEmpty() && !rDFA.GetFamilyName().isEmpty() )
209 aFontAttributes.insert( FontAttrMap::value_type( OptimizeURL( rFontFileName ), rDFA ) );
210 bModified = TRUE;
214 // raw font data with a scoped lifetime
215 class RawFontData
217 public:
218 explicit RawFontData( HDC, DWORD nTableTag=0 );
219 ~RawFontData() { delete[] mpRawBytes; }
220 const unsigned char* get() const { return mpRawBytes; }
221 const unsigned char* steal() { unsigned char* p = mpRawBytes; mpRawBytes = NULL; return p; }
222 int size() const { return mnByteCount; }
224 private:
225 unsigned char* mpRawBytes;
226 unsigned mnByteCount;
229 RawFontData::RawFontData( HDC hDC, DWORD nTableTag )
230 : mpRawBytes( NULL )
231 , mnByteCount( 0 )
233 // get required size in bytes
234 mnByteCount = ::GetFontData( hDC, nTableTag, 0, NULL, 0 );
235 if( mnByteCount == GDI_ERROR )
236 return;
237 else if( !mnByteCount )
238 return;
240 // allocate the array
241 mpRawBytes = new unsigned char[ mnByteCount ];
243 // get raw data in chunks small enough for GetFontData()
244 unsigned nRawDataOfs = 0;
245 DWORD nMaxChunkSize = 0x100000;
246 for(;;)
248 // calculate remaining raw data to get
249 DWORD nFDGet = mnByteCount - nRawDataOfs;
250 if( nFDGet <= 0 )
251 break;
252 // #i56745# limit GetFontData requests
253 if( nFDGet > nMaxChunkSize )
254 nFDGet = nMaxChunkSize;
255 const DWORD nFDGot = ::GetFontData( hDC, nTableTag, nRawDataOfs,
256 (void*)(mpRawBytes + nRawDataOfs), nFDGet );
257 if( !nFDGot )
258 break;
259 else if( nFDGot != GDI_ERROR )
260 nRawDataOfs += nFDGot;
261 else
263 // was the chunk too big? reduce it
264 nMaxChunkSize /= 2;
265 if( nMaxChunkSize < 0x10000 )
266 break;
270 // cleanup if the raw data is incomplete
271 if( nRawDataOfs != mnByteCount )
273 delete[] mpRawBytes;
274 mpRawBytes = NULL;
278 // platform specific font substitution hooks for glyph fallback enhancement
279 // TODO: move into i18n module (maybe merge with svx/ucsubset.*
280 // or merge with i18nutil/source/utility/unicode_data.h)
281 struct Unicode2LangType
283 sal_UCS4 mnMinCode;
284 sal_UCS4 mnMaxCode;
285 LanguageType mnLangID;
288 // entries marked with default-CJK get replaced with the default-CJK language
289 #define LANGUAGE_DEFAULT_CJK 0xFFF0
291 // map unicode ranges to languages supported by OOo
292 // NOTE: due to the binary search used this list must be sorted by mnMinCode
293 static Unicode2LangType aLangFromCodeChart[]= {
294 {0x0000, 0x007F, LANGUAGE_ENGLISH}, // Basic Latin
295 {0x0080, 0x024F, LANGUAGE_ENGLISH}, // Latin Extended-A and Latin Extended-B
296 {0x0250, 0x02AF, LANGUAGE_SYSTEM}, // IPA Extensions
297 {0x0370, 0x03FF, LANGUAGE_GREEK}, // Greek
298 {0x0590, 0x05FF, LANGUAGE_HEBREW}, // Hebrew
299 {0x0600, 0x06FF, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic
300 {0x0900, 0x097F, LANGUAGE_HINDI}, // Devanagari
301 {0x0980, 0x09FF, LANGUAGE_BENGALI}, // Bengali
302 {0x0A80, 0x0AFF, LANGUAGE_GUJARATI}, // Gujarati
303 {0x0B00, 0x0B7F, LANGUAGE_ODIA}, // Odia
304 {0x0B80, 0x0BFF, LANGUAGE_TAMIL}, // Tamil
305 {0x0C00, 0x0C7F, LANGUAGE_TELUGU}, // Telugu
306 {0x0C80, 0x0CFF, LANGUAGE_KANNADA}, // Kannada
307 {0x0D00, 0x0D7F, LANGUAGE_MALAYALAM}, // Malayalam
308 {0x0D80, 0x0D7F, LANGUAGE_SINHALESE_SRI_LANKA}, // Sinhala
309 {0x0E00, 0x0E7F, LANGUAGE_THAI}, // Thai
310 {0x0E80, 0x0EFF, LANGUAGE_LAO}, // Lao
311 {0x0F00, 0x0FFF, LANGUAGE_TIBETAN}, // Tibetan
312 {0x1000, 0x109F, LANGUAGE_BURMESE}, // Burmese
313 {0x10A0, 0x10FF, LANGUAGE_GEORGIAN}, // Georgian
314 {0x1100, 0x11FF, LANGUAGE_KOREAN}, // Hangul Jamo, Korean-specific
315 // {0x1200, 0x139F, LANGUAGE_AMHARIC_ETHIOPIA}, // Ethiopic
316 // {0x1200, 0x139F, LANGUAGE_TIGRIGNA_ETHIOPIA}, // Ethiopic
317 {0x13A0, 0x13FF, LANGUAGE_CHEROKEE_UNITED_STATES}, // Cherokee
318 // {0x1400, 0x167F, LANGUAGE_CANADIAN_ABORIGINAL}, // Canadian Aboriginial Syllabics
319 // {0x1680, 0x169F, LANGUAGE_OGHAM}, // Ogham
320 // {0x16A0, 0x16F0, LANGUAGE_RUNIC}, // Runic
321 // {0x1700, 0x171F, LANGUAGE_TAGALOG}, // Tagalog
322 // {0x1720, 0x173F, LANGUAGE_HANUNOO}, // Hanunoo
323 // {0x1740, 0x175F, LANGUAGE_BUHID}, // Buhid
324 // {0x1760, 0x177F, LANGUAGE_TAGBANWA}, // Tagbanwa
325 {0x1780, 0x17FF, LANGUAGE_KHMER}, // Khmer
326 {0x18A0, 0x18AF, LANGUAGE_MONGOLIAN_MONGOLIAN_MONGOLIA}, // Mongolian
327 // {0x1900, 0x194F, LANGUAGE_LIMBU}, // Limbu
328 // {0x1950, 0x197F, LANGUAGE_TAILE}, // Tai Le
329 // {0x1980, 0x19DF, LANGUAGE_TAILUE}, // Tai Lue
330 {0x19E0, 0x19FF, LANGUAGE_KHMER}, // Khmer Symbols
331 // {0x1A00, 0x1A1F, LANGUAGE_BUGINESE}, // Buginese/Lontara
332 // {0x1B00, 0x1B7F, LANGUAGE_BALINESE}, // Balinese
333 // {0x1D00, 0x1DFF, LANGUAGE_NONE}, // Phonetic Symbols
334 {0x1E00, 0x1EFF, LANGUAGE_ENGLISH}, // Latin Extended Additional
335 {0x1F00, 0x1FFF, LANGUAGE_GREEK}, // Greek Extended
336 {0x2C60, 0x2C7F, LANGUAGE_ENGLISH}, // Latin Extended-C
337 {0x2E80, 0x2FFf, LANGUAGE_CHINESE_SIMPLIFIED}, // CJK Radicals Supplement + Kangxi Radical + Ideographic Description Characters
338 {0x3000, 0x303F, LANGUAGE_DEFAULT_CJK}, // CJK Symbols and punctuation
339 {0x3040, 0x30FF, LANGUAGE_JAPANESE}, // Japanese Hiragana + Katakana
340 {0x3100, 0x312F, LANGUAGE_CHINESE_TRADITIONAL}, // Bopomofo
341 {0x3130, 0x318F, LANGUAGE_KOREAN}, // Hangul Compatibility Jamo, Kocrean-specific
342 {0x3190, 0x319F, LANGUAGE_JAPANESE}, // Kanbun
343 {0x31A0, 0x31BF, LANGUAGE_CHINESE_TRADITIONAL}, // Bopomofo Extended
344 {0x31C0, 0x31EF, LANGUAGE_DEFAULT_CJK}, // CJK Ideographs
345 {0x31F0, 0x31FF, LANGUAGE_JAPANESE}, // Japanese Katakana Phonetic Extensions
346 {0x3200, 0x321F, LANGUAGE_KOREAN}, // Parenthesized Hangul
347 {0x3220, 0x325F, LANGUAGE_DEFAULT_CJK}, // Parenthesized Ideographs
348 {0x3260, 0x327F, LANGUAGE_KOREAN}, // Circled Hangul
349 {0x3280, 0x32CF, LANGUAGE_DEFAULT_CJK}, // Circled Ideographs
350 {0x32d0, 0x32FF, LANGUAGE_JAPANESE}, // Japanese Circled Katakana
351 {0x3400, 0x4DBF, LANGUAGE_DEFAULT_CJK}, // CJK Unified Ideographs Extension A
352 {0x4E00, 0x9FCF, LANGUAGE_DEFAULT_CJK}, // Unified CJK Ideographs
353 {0xA720, 0xA7FF, LANGUAGE_ENGLISH}, // Latin Extended-D
354 {0xAC00, 0xD7AF, LANGUAGE_KOREAN}, // Hangul Syllables, Korean-specific
355 {0xF900, 0xFAFF, LANGUAGE_DEFAULT_CJK}, // CJK Compatibility Ideographs
356 {0xFB00, 0xFB4F, LANGUAGE_HEBREW}, // Hebrew Presentation Forms
357 {0xFB50, 0xFDFF, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic Presentation Forms-A
358 {0xFE70, 0xFEFE, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic Presentation Forms-B
359 {0xFF65, 0xFF9F, LANGUAGE_JAPANESE}, // Japanese Halfwidth Katakana variant
360 {0xFFA0, 0xFFDC, LANGUAGE_KOREAN}, // Kocrean halfwidth hangual variant
361 {0x10140, 0x1018F, LANGUAGE_GREEK}, // Ancient Greak numbers
362 {0x1D200, 0x1D24F, LANGUAGE_GREEK}, // Ancient Greek Musical
363 {0x20000, 0x2A6DF, LANGUAGE_DEFAULT_CJK}, // CJK Unified Ideographs Extension B
364 {0x2F800, 0x2FA1F, LANGUAGE_DEFAULT_CJK} // CJK Compatibility Ideographs Supplement
367 // get language matching to the missing char
368 LanguageType MapCharToLanguage( sal_UCS4 uChar )
370 // entries marked with default-CJK get replaced with the preferred CJK language
371 static bool bFirst = true;
372 if( bFirst )
374 bFirst = false;
376 // use method suggested in #i97086# to determnine the systems default language
377 // TODO: move into i18npool or sal/osl/w32/nlsupport.c
378 LanguageType nDefaultLang = 0;
379 HKEY hKey = NULL;
380 LONG lResult = ::RegOpenKeyExA( HKEY_LOCAL_MACHINE,
381 "SYSTEM\\CurrentControlSet\\Control\\Nls\\Language",
382 0, KEY_QUERY_VALUE, &hKey );
383 char aKeyValBuf[16];
384 DWORD nKeyValSize = sizeof(aKeyValBuf);
385 if( ERROR_SUCCESS == lResult )
386 lResult = RegQueryValueExA( hKey, "Default", NULL, NULL, (LPBYTE)aKeyValBuf, &nKeyValSize );
387 aKeyValBuf[ sizeof(aKeyValBuf)-1 ] = '\0';
388 if( ERROR_SUCCESS == lResult )
389 nDefaultLang = (LanguageType)rtl_str_toInt32( aKeyValBuf, 16 );
391 // TODO: use the default-CJK language selected in
392 // Tools->Options->LangSettings->Languages when it becomes available here
393 if( !nDefaultLang )
394 nDefaultLang = Application::GetSettings().GetUILanguageTag().getLanguageType();
396 LanguageType nDefaultCJK = MsLangId::isCJK(nDefaultLang) ? nDefaultLang : LANGUAGE_CHINESE;
398 // change the marked entries to preferred language
399 static const int nCount = SAL_N_ELEMENTS(aLangFromCodeChart);
400 for( int i = 0; i < nCount; ++i )
402 if( aLangFromCodeChart[ i].mnLangID == LANGUAGE_DEFAULT_CJK )
403 aLangFromCodeChart[ i].mnLangID = nDefaultCJK;
407 // binary search
408 int nLow = 0;
409 int nHigh = SAL_N_ELEMENTS(aLangFromCodeChart) - 1;
410 while( nLow <= nHigh )
412 int nMiddle = (nHigh + nLow) / 2;
413 if( uChar < aLangFromCodeChart[ nMiddle].mnMinCode )
414 nHigh = nMiddle - 1;
415 else if( uChar > aLangFromCodeChart[ nMiddle].mnMaxCode )
416 nLow = nMiddle + 1;
417 else
418 return aLangFromCodeChart[ nMiddle].mnLangID;
421 return LANGUAGE_DONTKNOW;
424 class WinGlyphFallbackSubstititution
425 : public ImplGlyphFallbackFontSubstitution
427 public:
428 explicit WinGlyphFallbackSubstititution( HDC );
430 bool FindFontSubstitute( FontSelectPattern&, OUString& rMissingChars ) const;
431 private:
432 HDC mhDC;
433 bool HasMissingChars( PhysicalFontFace*, const OUString& rMissingChars ) const;
436 inline WinGlyphFallbackSubstititution::WinGlyphFallbackSubstititution( HDC hDC )
437 : mhDC( hDC )
440 void ImplGetLogFontFromFontSelect( HDC, const FontSelectPattern*,
441 LOGFONTW&, bool /*bTestVerticalAvail*/ );
443 // does a font face hold the given missing characters?
444 bool WinGlyphFallbackSubstititution::HasMissingChars( PhysicalFontFace* pFace, const OUString& rMissingChars ) const
446 ImplWinFontData* pWinFont = static_cast< ImplWinFontData* >(pFace);
447 FontCharMapPtr pCharMap = pWinFont->GetFontCharMap();
448 if( !pCharMap )
450 // construct a Size structure as the parameter of constructor of class FontSelectPattern
451 const Size aSize( pFace->GetWidth(), pFace->GetHeight() );
452 // create a FontSelectPattern object for getting s LOGFONT
453 const FontSelectPattern aFSD( *pFace, aSize, (float)aSize.Height(), 0, false );
454 // construct log font
455 LOGFONTW aLogFont;
456 ImplGetLogFontFromFontSelect( mhDC, &aFSD, aLogFont, true );
458 // create HFONT from log font
459 HFONT hNewFont = ::CreateFontIndirectW( &aLogFont );
460 // select the new font into device
461 HFONT hOldFont = ::SelectFont( mhDC, hNewFont );
463 // read CMAP table to update their pCharMap
464 pWinFont->UpdateFromHDC( mhDC );
466 // cleanup temporary font
467 ::SelectFont( mhDC, hOldFont );
468 ::DeleteFont( hNewFont );
470 // get the new charmap
471 pCharMap = pWinFont->GetFontCharMap();
474 // avoid fonts with unknown CMAP subtables for glyph fallback
475 if( !pCharMap || pCharMap->IsDefaultMap() )
476 return false;
478 int nMatchCount = 0;
479 // static const int nMaxMatchCount = 1; // TODO: tolerate more missing characters?
480 const sal_Int32 nStrLen = rMissingChars.getLength();
481 for( sal_Int32 nStrIdx = 0; nStrIdx < nStrLen; /* ++nStrIdx unreachable code, see the 'break' below */ )
483 const sal_UCS4 uChar = rMissingChars.iterateCodePoints( &nStrIdx );
484 nMatchCount += pCharMap->HasChar( uChar );
485 break; // for now
488 pCharMap = 0;
490 const bool bHasMatches = (nMatchCount > 0);
491 return bHasMatches;
494 namespace
496 //used by 2-level font fallback
497 PhysicalFontFamily* findDevFontListByLocale(const PhysicalFontCollection &rFontCollection,
498 const LanguageTag& rLanguageTag )
500 // get the default font for a specified locale
501 const utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get();
502 const OUString aDefault = rDefaults.getUserInterfaceFont(rLanguageTag);
503 return rFontCollection.ImplFindByTokenNames(aDefault);
507 // find a fallback font for missing characters
508 // TODO: should stylistic matches be searched and preferred?
509 bool WinGlyphFallbackSubstititution::FindFontSubstitute( FontSelectPattern& rFontSelData, OUString& rMissingChars ) const
511 // guess a locale matching to the missing chars
512 LanguageType eLang = LANGUAGE_DONTKNOW;
513 LanguageTag aLanguageTag( eLang);
515 sal_Int32 nStrIdx = 0;
516 const sal_Int32 nStrLen = rMissingChars.getLength();
517 while( nStrIdx < nStrLen )
519 const sal_UCS4 uChar = rMissingChars.iterateCodePoints( &nStrIdx );
520 eLang = MapCharToLanguage( uChar );
521 if( eLang == LANGUAGE_DONTKNOW )
522 continue;
523 aLanguageTag.reset( eLang);
524 break;
527 // fall back to default UI locale if the missing characters are inconclusive
528 if( eLang == LANGUAGE_DONTKNOW )
529 aLanguageTag = Application::GetSettings().GetUILanguageTag();
531 // first level fallback:
532 // try use the locale specific default fonts defined in VCL.xcu
533 const PhysicalFontCollection* pFontCollection = ImplGetSVData()->maGDIData.mpScreenFontList;
534 PhysicalFontFamily* pFontFamily = findDevFontListByLocale(*pFontCollection, aLanguageTag);
535 if( pFontFamily )
537 PhysicalFontFace* pFace = pFontFamily->FindBestFontFace( rFontSelData );
538 if( HasMissingChars( pFace, rMissingChars ) )
540 rFontSelData.maSearchName = pFontFamily->GetSearchName();
541 return true;
545 // are the missing characters symbols?
546 pFontFamily = pFontCollection->ImplFindByAttributes( ImplFontAttrs::Symbol,
547 rFontSelData.GetWeight(),
548 rFontSelData.GetWidthType(),
549 rFontSelData.GetSlant(),
550 rFontSelData.maSearchName );
551 if( pFontFamily )
553 PhysicalFontFace* pFace = pFontFamily->FindBestFontFace( rFontSelData );
554 if( HasMissingChars( pFace, rMissingChars ) )
556 rFontSelData.maSearchName = pFontFamily->GetSearchName();
557 return true;
561 // last level fallback, check each font type face one by one
562 ImplGetDevFontList* pTestFontList = pFontCollection->GetDevFontList();
563 // limit the count of fonts to be checked to prevent hangs
564 static const int MAX_GFBFONT_COUNT = 600;
565 int nTestFontCount = pTestFontList->Count();
566 if( nTestFontCount > MAX_GFBFONT_COUNT )
567 nTestFontCount = MAX_GFBFONT_COUNT;
569 bool bFound = false;
570 for( int i = 0; i < nTestFontCount; ++i )
572 PhysicalFontFace* pFace = pTestFontList->Get( i );
573 bFound = HasMissingChars( pFace, rMissingChars );
574 if( !bFound )
575 continue;
576 rFontSelData.maSearchName = pFace->GetFamilyName();
577 break;
580 delete pTestFontList;
582 return bFound;
585 struct ImplEnumInfo
587 HDC mhDC;
588 PhysicalFontCollection* mpList;
589 OUString* mpName;
590 LOGFONTA* mpLogFontA;
591 LOGFONTW* mpLogFontW;
592 UINT mnPreferredCharSet;
593 bool mbCourier;
594 bool mbImplSalCourierScalable;
595 bool mbImplSalCourierNew;
596 bool mbPrinter;
597 int mnFontCount;
600 static rtl_TextEncoding ImplCharSetToSal( BYTE nCharSet )
602 rtl_TextEncoding eTextEncoding;
604 if ( nCharSet == OEM_CHARSET )
606 UINT nCP = (sal_uInt16)GetOEMCP();
607 switch ( nCP )
609 // It is unclear why these two (undefined?) code page numbers are
610 // handled specially here:
611 case 1004: eTextEncoding = RTL_TEXTENCODING_MS_1252; break;
612 case 65400: eTextEncoding = RTL_TEXTENCODING_SYMBOL; break;
613 default:
614 eTextEncoding = rtl_getTextEncodingFromWindowsCodePage(nCP);
615 break;
618 else
620 if( nCharSet )
621 eTextEncoding = rtl_getTextEncodingFromWindowsCharset( nCharSet );
622 else
623 eTextEncoding = RTL_TEXTENCODING_UNICODE;
626 return eTextEncoding;
629 static FontFamily ImplFamilyToSal( BYTE nFamily )
631 switch ( nFamily & 0xF0 )
633 case FF_DECORATIVE:
634 return FAMILY_DECORATIVE;
636 case FF_MODERN:
637 return FAMILY_MODERN;
639 case FF_ROMAN:
640 return FAMILY_ROMAN;
642 case FF_SCRIPT:
643 return FAMILY_SCRIPT;
645 case FF_SWISS:
646 return FAMILY_SWISS;
648 default:
649 break;
652 return FAMILY_DONTKNOW;
655 static BYTE ImplFamilyToWin( FontFamily eFamily )
657 switch ( eFamily )
659 case FAMILY_DECORATIVE:
660 return FF_DECORATIVE;
662 case FAMILY_MODERN:
663 return FF_MODERN;
665 case FAMILY_ROMAN:
666 return FF_ROMAN;
668 case FAMILY_SCRIPT:
669 return FF_SCRIPT;
671 case FAMILY_SWISS:
672 return FF_SWISS;
674 case FAMILY_SYSTEM:
675 return FF_SWISS;
677 default:
678 break;
681 return FF_DONTCARE;
684 static FontWeight ImplWeightToSal( int nWeight )
686 if ( nWeight <= FW_THIN )
687 return WEIGHT_THIN;
688 else if ( nWeight <= FW_ULTRALIGHT )
689 return WEIGHT_ULTRALIGHT;
690 else if ( nWeight <= FW_LIGHT )
691 return WEIGHT_LIGHT;
692 else if ( nWeight < FW_MEDIUM )
693 return WEIGHT_NORMAL;
694 else if ( nWeight == FW_MEDIUM )
695 return WEIGHT_MEDIUM;
696 else if ( nWeight <= FW_SEMIBOLD )
697 return WEIGHT_SEMIBOLD;
698 else if ( nWeight <= FW_BOLD )
699 return WEIGHT_BOLD;
700 else if ( nWeight <= FW_ULTRABOLD )
701 return WEIGHT_ULTRABOLD;
702 else
703 return WEIGHT_BLACK;
706 static int ImplWeightToWin( FontWeight eWeight )
708 switch ( eWeight )
710 case WEIGHT_THIN:
711 return FW_THIN;
713 case WEIGHT_ULTRALIGHT:
714 return FW_ULTRALIGHT;
716 case WEIGHT_LIGHT:
717 return FW_LIGHT;
719 case WEIGHT_SEMILIGHT:
720 case WEIGHT_NORMAL:
721 return FW_NORMAL;
723 case WEIGHT_MEDIUM:
724 return FW_MEDIUM;
726 case WEIGHT_SEMIBOLD:
727 return FW_SEMIBOLD;
729 case WEIGHT_BOLD:
730 return FW_BOLD;
732 case WEIGHT_ULTRABOLD:
733 return FW_ULTRABOLD;
735 case WEIGHT_BLACK:
736 return FW_BLACK;
738 default:
739 break;
742 return 0;
745 inline FontPitch ImplLogPitchToSal( BYTE nPitch )
747 if ( nPitch & FIXED_PITCH )
748 return PITCH_FIXED;
749 else
750 return PITCH_VARIABLE;
753 inline FontPitch ImplMetricPitchToSal( BYTE nPitch )
755 // Grrrr! See NT help
756 if ( !(nPitch & TMPF_FIXED_PITCH) )
757 return PITCH_FIXED;
758 else
759 return PITCH_VARIABLE;
762 inline BYTE ImplPitchToWin( FontPitch ePitch )
764 if ( ePitch == PITCH_FIXED )
765 return FIXED_PITCH;
766 else if ( ePitch == PITCH_VARIABLE )
767 return VARIABLE_PITCH;
768 else
769 return DEFAULT_PITCH;
772 static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXA& rEnumFont,
773 const NEWTEXTMETRICA& rMetric, DWORD nFontType )
775 ImplDevFontAttributes aDFA;
777 const LOGFONTA rLogFont = rEnumFont.elfLogFont;
779 // get font face attributes
780 aDFA.SetFamilyType(ImplFamilyToSal( rLogFont.lfPitchAndFamily ));
781 aDFA.SetWidthType(WIDTH_DONTKNOW);
782 aDFA.SetWeight(ImplWeightToSal( rLogFont.lfWeight ));
783 aDFA.SetItalic((rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE);
784 aDFA.SetPitch(ImplLogPitchToSal( rLogFont.lfPitchAndFamily ));
785 aDFA.SetSymbolFlag(rLogFont.lfCharSet == SYMBOL_CHARSET);
787 // get the font face name
788 aDFA.SetFamilyName(ImplSalGetUniString( rLogFont.lfFaceName ));
790 // use the face's style name only if it looks reasonable
791 const char* pStyleName = (const char*)rEnumFont.elfStyle;
792 const char* pEnd = pStyleName + sizeof( rEnumFont.elfStyle );
793 const char* p = pStyleName;
794 for(; *p && (p < pEnd); ++p )
795 if( (0x00 < *p) && (*p < 0x20) )
796 break;
797 if( p < pEnd )
798 aDFA.SetStyleName(ImplSalGetUniString( pStyleName ));
800 // get device specific font attributes
801 aDFA.mbOrientation = (nFontType & RASTER_FONTTYPE) == 0;
802 aDFA.mbDevice = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
804 aDFA.mbEmbeddable = false;
805 aDFA.mbSubsettable = false;
806 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
807 || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
808 aDFA.mbSubsettable = true;
809 else if( 0 != (rMetric.ntmFlags & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
810 aDFA.mbEmbeddable = true;
812 // heuristics for font quality
813 // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
814 // - subsetting > embedding > none
815 aDFA.mnQuality = 0;
816 if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
817 aDFA.mnQuality += 50;
818 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
819 aDFA.mnQuality += 10;
820 if( aDFA.mbSubsettable )
821 aDFA.mnQuality += 200;
822 else if( aDFA.mbEmbeddable )
823 aDFA.mnQuality += 100;
825 // #i38665# prefer Type1 versions of the standard postscript fonts
826 if( aDFA.mbEmbeddable )
828 if( aDFA.GetFamilyName() == "AvantGarde"
829 || aDFA.GetFamilyName() == "Bookman"
830 || aDFA.GetFamilyName() == "Courier"
831 || aDFA.GetFamilyName() == "Helvetica"
832 || aDFA.GetFamilyName() == "NewCenturySchlbk"
833 || aDFA.GetFamilyName() == "Palatino"
834 || aDFA.GetFamilyName() == "Symbol"
835 || aDFA.GetFamilyName() == "Times"
836 || aDFA.GetFamilyName() == "ZapfChancery"
837 || aDFA.GetFamilyName() == "ZapfDingbats" )
838 aDFA.mnQuality += 500;
841 // TODO: add alias names
842 return aDFA;
845 static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXW& rEnumFont,
846 const NEWTEXTMETRICW& rMetric, DWORD nFontType )
848 ImplDevFontAttributes aDFA;
850 const LOGFONTW rLogFont = rEnumFont.elfLogFont;
852 // get font face attributes
853 aDFA.SetFamilyType(ImplFamilyToSal( rLogFont.lfPitchAndFamily ));
854 aDFA.SetWidthType(WIDTH_DONTKNOW);
855 aDFA.SetWeight(ImplWeightToSal( rLogFont.lfWeight ));
856 aDFA.SetItalic((rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE);
857 aDFA.SetPitch(ImplLogPitchToSal( rLogFont.lfPitchAndFamily ));
858 aDFA.SetSymbolFlag(rLogFont.lfCharSet == SYMBOL_CHARSET);
860 // get the font face name
861 aDFA.SetFamilyName(OUString(reinterpret_cast<const sal_Unicode*>(rLogFont.lfFaceName)));
863 // use the face's style name only if it looks reasonable
864 const wchar_t* pStyleName = rEnumFont.elfStyle;
865 const wchar_t* pEnd = pStyleName + sizeof(rEnumFont.elfStyle)/sizeof(*rEnumFont.elfStyle);
866 const wchar_t* p = pStyleName;
867 for(; *p && (p < pEnd); ++p )
868 if( *p < 0x0020 )
869 break;
870 if( p < pEnd )
871 aDFA.SetStyleName(OUString(reinterpret_cast<const sal_Unicode*>(pStyleName)));
873 // get device specific font attributes
874 aDFA.mbOrientation = (nFontType & RASTER_FONTTYPE) == 0;
875 aDFA.mbDevice = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
877 aDFA.mbEmbeddable = false;
878 aDFA.mbSubsettable = false;
879 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
880 || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
881 aDFA.mbSubsettable = true;
882 else if( 0 != (rMetric.ntmFlags & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
883 aDFA.mbEmbeddable = true;
885 // heuristics for font quality
886 // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
887 // - subsetting > embedding > none
888 aDFA.mnQuality = 0;
889 if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
890 aDFA.mnQuality += 50;
891 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
892 aDFA.mnQuality += 10;
893 if( aDFA.mbSubsettable )
894 aDFA.mnQuality += 200;
895 else if( aDFA.mbEmbeddable )
896 aDFA.mnQuality += 100;
898 // #i38665# prefer Type1 versions of the standard postscript fonts
899 if( aDFA.mbEmbeddable )
901 if( aDFA.GetFamilyName() == "AvantGarde"
902 || aDFA.GetFamilyName() == "Bookman"
903 || aDFA.GetFamilyName() == "Courier"
904 || aDFA.GetFamilyName() == "Helvetica"
905 || aDFA.GetFamilyName() == "NewCenturySchlbk"
906 || aDFA.GetFamilyName() == "Palatino"
907 || aDFA.GetFamilyName() == "Symbol"
908 || aDFA.GetFamilyName() == "Times"
909 || aDFA.GetFamilyName() == "ZapfChancery"
910 || aDFA.GetFamilyName() == "ZapfDingbats" )
911 aDFA.mnQuality += 500;
914 // TODO: add alias names
915 return aDFA;
918 static ImplWinFontData* ImplLogMetricToDevFontDataA( const ENUMLOGFONTEXA* pLogFont,
919 const NEWTEXTMETRICA* pMetric,
920 DWORD nFontType )
922 int nHeight = 0;
923 if ( nFontType & RASTER_FONTTYPE )
924 nHeight = pMetric->tmHeight - pMetric->tmInternalLeading;
926 ImplWinFontData* pData = new ImplWinFontData(
927 WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType),
928 nHeight,
929 pLogFont->elfLogFont.lfCharSet,
930 pMetric->tmPitchAndFamily );
932 return pData;
935 static ImplWinFontData* ImplLogMetricToDevFontDataW( const ENUMLOGFONTEXW* pLogFont,
936 const NEWTEXTMETRICW* pMetric,
937 DWORD nFontType )
939 int nHeight = 0;
940 if ( nFontType & RASTER_FONTTYPE )
941 nHeight = pMetric->tmHeight - pMetric->tmInternalLeading;
943 ImplWinFontData* pData = new ImplWinFontData(
944 WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType),
945 nHeight,
946 pLogFont->elfLogFont.lfCharSet,
947 pMetric->tmPitchAndFamily );
949 return pData;
952 void ImplSalLogFontToFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont )
954 OUString aFontName( reinterpret_cast<const sal_Unicode*>(rLogFont.lfFaceName) );
955 if (!aFontName.isEmpty())
957 rFont.SetName( aFontName );
958 rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) );
959 rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) );
960 rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) );
961 rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) );
963 long nFontHeight = rLogFont.lfHeight;
964 if ( nFontHeight < 0 )
965 nFontHeight = -nFontHeight;
966 long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
967 if( !nDPIY )
968 nDPIY = 600;
969 nFontHeight *= 72;
970 nFontHeight += nDPIY/2;
971 nFontHeight /= nDPIY;
972 rFont.SetSize( Size( 0, nFontHeight ) );
973 rFont.SetOrientation( (short)rLogFont.lfEscapement );
974 if ( rLogFont.lfItalic )
975 rFont.SetItalic( ITALIC_NORMAL );
976 else
977 rFont.SetItalic( ITALIC_NONE );
978 if ( rLogFont.lfUnderline )
979 rFont.SetUnderline( UNDERLINE_SINGLE );
980 else
981 rFont.SetUnderline( UNDERLINE_NONE );
982 if ( rLogFont.lfStrikeOut )
983 rFont.SetStrikeout( STRIKEOUT_SINGLE );
984 else
985 rFont.SetStrikeout( STRIKEOUT_NONE );
989 #if ENABLE_GRAPHITE
991 #ifdef DEBUG
992 static FILE * grLogFile = NULL;
993 static FILE * grLog()
995 std::string logFileName(getenv("TEMP"));
996 logFileName.append("\\grface.log");
997 if (grLogFile == NULL) grLogFile = fopen(logFileName.c_str(),"w");
998 else fflush(grLogFile);
999 return grLogFile;
1001 #undef NDEBUG
1002 #endif
1004 const void * getGrTable(const void* appFaceHandle, unsigned int name, size_t *len)
1006 const GrFontData * fontTables = reinterpret_cast<const GrFontData*>(appFaceHandle);
1007 return fontTables->getTable(name, len);
1010 GrFontData::GrFontData(HDC hDC) :
1011 mhDC(hDC), mpFace(NULL), mnRefCount(1)
1013 // The face options ensure that the tables are all read at construction
1014 // time so there is no need to keep the hDC uptodate
1015 static const char* pGraphiteCacheStr = getenv( "SAL_GRAPHITE_CACHE_SIZE" );
1016 unsigned long graphiteSegCacheSize = pGraphiteCacheStr ? (atoi(pGraphiteCacheStr)) : 0;
1017 if (graphiteSegCacheSize > 500)
1018 mpFace = gr_make_face_with_seg_cache(this, getGrTable,
1019 graphiteSegCacheSize, gr_face_preloadGlyphs | gr_face_cacheCmap);
1020 else
1021 mpFace = gr_make_face(this, getGrTable,
1022 gr_face_preloadGlyphs | gr_face_cacheCmap);
1023 #ifdef DEBUG
1024 fprintf(grLog(), "gr_make_face %lx for WinFontData %lx\n", (unsigned long)mpFace,
1025 (unsigned long)this);
1026 #endif
1027 mhDC = NULL;
1030 GrFontData::~GrFontData()
1032 if (mpFace)
1034 #ifdef DEBUG
1035 fprintf(grLog(), "gr_face_destroy %lx for WinFontData %lx\n", (unsigned long)mpFace,
1036 (unsigned long)this);
1037 #endif
1038 gr_face_destroy(mpFace);
1039 mpFace = NULL;
1041 std::vector<RawFontData*>::iterator i = mvData.begin();
1042 while (i != mvData.end())
1044 delete *i;
1045 ++i;
1047 mvData.clear();
1050 const void * GrFontData::getTable(unsigned int name, size_t *len) const
1052 #ifdef DEBUG
1053 #undef NDEBUG
1054 #endif
1055 assert(mhDC);
1056 // swap the bytes
1057 union TtfTag {
1058 unsigned int i;
1059 unsigned char c[4];
1061 TtfTag littleEndianTag;
1062 littleEndianTag.i = name;
1063 TtfTag bigEndianTag;
1064 bigEndianTag.c[0] = littleEndianTag.c[3];
1065 bigEndianTag.c[1] = littleEndianTag.c[2];
1066 bigEndianTag.c[2] = littleEndianTag.c[1];
1067 bigEndianTag.c[3] = littleEndianTag.c[0];
1068 mvData.push_back(new RawFontData(mhDC, bigEndianTag.i));
1069 const RawFontData * data = mvData[mvData.size()-1];
1070 if (data && (data->size() > 0))
1072 if (len)
1073 *len = data->size();
1074 return reinterpret_cast<const void *>(data->get());
1076 else
1078 if (len)
1079 *len = 0;
1080 return NULL;
1083 #endif
1085 ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes& rDFS,
1086 int nHeight, BYTE eWinCharSet, BYTE nPitchAndFamily )
1087 : PhysicalFontFace( rDFS, 0 ),
1088 mnId( 0 ),
1089 mbHasKoreanRange( false ),
1090 mbHasCJKSupport( false ),
1091 #if ENABLE_GRAPHITE
1092 mpGraphiteData(NULL),
1093 mbHasGraphiteSupport( false ),
1094 #endif
1095 mbHasArabicSupport ( false ),
1096 mbFontCapabilitiesRead( false ),
1097 mpUnicodeMap( NULL ),
1098 mpEncodingVector( NULL ),
1099 meWinCharSet( eWinCharSet ),
1100 mnPitchAndFamily( nPitchAndFamily ),
1101 mbAliasSymbolsHigh( false ),
1102 mbAliasSymbolsLow( false ),
1103 mbGsubRead( false )
1105 SetBitmapSize( 0, nHeight );
1107 if( eWinCharSet == SYMBOL_CHARSET )
1109 if( (nPitchAndFamily & TMPF_TRUETYPE) != 0 )
1111 // truetype fonts need their symbols as U+F0xx
1112 mbAliasSymbolsHigh = true;
1114 else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_DEVICE))
1115 == (TMPF_VECTOR|TMPF_DEVICE) )
1117 // scalable device fonts (e.g. builtin printer fonts)
1118 // need their symbols as U+00xx
1119 mbAliasSymbolsLow = true;
1121 else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) == 0 )
1123 // bitmap fonts need their symbols as U+F0xx
1124 mbAliasSymbolsHigh = true;
1127 #ifdef DEBUG
1128 fprintf(grLog(), "ImplWinFontData::ImplWinFontData() %lx\n", (unsigned long)this);
1129 #endif
1132 ImplWinFontData::~ImplWinFontData()
1134 if( mpUnicodeMap )
1135 mpUnicodeMap = 0;
1136 #if ENABLE_GRAPHITE
1137 if (mpGraphiteData)
1138 mpGraphiteData->DeReference();
1139 #ifdef DEBUG
1140 fprintf(grLog(), "ImplWinFontData::~ImplWinFontData %lx\n", (unsigned long)this);
1141 #endif
1142 #endif // ENABLE_GRAPHITE
1143 delete mpEncodingVector;
1146 sal_IntPtr ImplWinFontData::GetFontId() const
1148 return mnId;
1151 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
1152 static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); }
1154 void ImplWinFontData::UpdateFromHDC( HDC hDC ) const
1156 // short circuit if already initialized
1157 if( mpUnicodeMap != NULL )
1158 return;
1160 ReadCmapTable( hDC );
1161 GetFontCapabilities( hDC );
1162 #if ENABLE_GRAPHITE
1163 static const char* pDisableGraphiteText = getenv( "SAL_DISABLE_GRAPHITE" );
1164 if( !pDisableGraphiteText || (pDisableGraphiteText[0] == '0') )
1166 const DWORD nSilfTag = CalcTag("Silf");
1167 const RawFontData aRawFontData( hDC, nSilfTag );
1168 mbHasGraphiteSupport = (aRawFontData.size() > 0);
1169 if (mbHasGraphiteSupport)
1171 #ifdef DEBUG
1172 fprintf(grLog(), "ImplWinFontData::UpdateFromHDC %lx\n",
1173 (unsigned long)this);
1174 #endif
1175 if (mpGraphiteData == NULL)
1177 mpGraphiteData = new GrFontData(hDC);
1178 if (!mpGraphiteData->getFace())
1180 mbHasGraphiteSupport = false;
1181 delete mpGraphiteData;
1182 mpGraphiteData = NULL;
1187 #endif
1190 #if ENABLE_GRAPHITE
1191 const gr_face* ImplWinFontData::GraphiteFace() const
1193 #ifdef DEBUG
1194 fprintf(grLog(), "ImplWinFontData::GraphiteFace %lx has face %lx\n",
1195 (unsigned long)this, mpGraphiteData? mpGraphiteData->getFace(): 0);
1196 #endif
1197 return (mpGraphiteData)? mpGraphiteData->getFace() : NULL;
1199 #endif
1201 bool ImplWinFontData::HasGSUBstitutions( HDC hDC ) const
1203 if( !mbGsubRead )
1204 ReadGsubTable( hDC );
1205 return !maGsubTable.empty();
1208 bool ImplWinFontData::IsGSUBstituted( sal_UCS4 cChar ) const
1210 return( maGsubTable.find( cChar ) != maGsubTable.end() );
1213 FontCharMapPtr ImplWinFontData::GetFontCharMap() const
1215 if( !mpUnicodeMap )
1216 return NULL;
1217 return mpUnicodeMap;
1220 bool ImplWinFontData::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
1222 rFontCapabilities = maFontCapabilities;
1223 return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty();
1226 void ImplWinFontData::ReadGsubTable( HDC hDC ) const
1228 mbGsubRead = true;
1230 // check the existence of a GSUB table
1231 const DWORD GsubTag = CalcTag( "GSUB" );
1232 DWORD nRC = ::GetFontData( hDC, GsubTag, 0, NULL, 0 );
1233 if( (nRC == GDI_ERROR) || !nRC )
1234 return;
1236 // parse the GSUB table through sft
1237 // TODO: parse it directly
1239 // sft needs the full font file data => get it
1240 const RawFontData aRawFontData( hDC );
1241 if( !aRawFontData.get() )
1242 return;
1244 // open font file
1245 sal_uInt32 nFaceNum = 0;
1246 if( !*aRawFontData.get() ) // TTC candidate
1247 nFaceNum = ~0U; // indicate "TTC font extracts only"
1249 TrueTypeFont* pTTFont = NULL;
1250 ::OpenTTFontBuffer( (void*)aRawFontData.get(), aRawFontData.size(), nFaceNum, &pTTFont );
1251 if( !pTTFont )
1252 return;
1254 // add vertically substituted characters to list
1255 static const sal_Unicode aGSUBCandidates[] = {
1256 0x0020, 0x0080, // ASCII
1257 0x2000, 0x2600, // misc
1258 0x3000, 0x3100, // CJK punctutation
1259 0x3300, 0x3400, // squared words
1260 0xFF00, 0xFFF0, // halfwidth|fullwidth forms
1261 0 };
1263 for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
1264 for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
1265 if( ::MapChar( pTTFont, cChar, false ) != ::MapChar( pTTFont, cChar, true ) )
1266 maGsubTable.insert( cChar ); // insert GSUBbed unicodes
1268 CloseTTFont( pTTFont );
1271 void ImplWinFontData::ReadCmapTable( HDC hDC ) const
1273 if( mpUnicodeMap != NULL )
1274 return;
1276 bool bIsSymbolFont = (meWinCharSet == SYMBOL_CHARSET);
1277 // get the CMAP table from the font which is selected into the DC
1278 const DWORD nCmapTag = CalcTag( "cmap" );
1279 const RawFontData aRawFontData( hDC, nCmapTag );
1280 // parse the CMAP table if available
1281 if( aRawFontData.get() ) {
1282 CmapResult aResult;
1283 ParseCMAP( aRawFontData.get(), aRawFontData.size(), aResult );
1284 aResult.mbSymbolic = bIsSymbolFont;
1285 if( aResult.mnRangeCount > 0 )
1287 FontCharMapPtr pUnicodeMap(new FontCharMap(aResult));
1288 mpUnicodeMap = pUnicodeMap;
1292 if( !mpUnicodeMap )
1294 mpUnicodeMap = FontCharMap::GetDefaultMap( bIsSymbolFont );
1298 void ImplWinFontData::GetFontCapabilities( HDC hDC ) const
1300 // read this only once per font
1301 if( mbFontCapabilitiesRead )
1302 return;
1304 mbFontCapabilitiesRead = true;
1306 // GSUB table
1307 DWORD nLength;
1308 const DWORD GsubTag = CalcTag( "GSUB" );
1309 nLength = ::GetFontData( hDC, GsubTag, 0, NULL, 0 );
1310 if( (nLength != GDI_ERROR) && nLength )
1312 std::vector<unsigned char> aTable( nLength );
1313 unsigned char* pTable = &aTable[0];
1314 ::GetFontData( hDC, GsubTag, 0, pTable, nLength );
1315 vcl::getTTScripts(maFontCapabilities.maGSUBScriptTags, pTable, nLength);
1318 // OS/2 table
1319 const DWORD OS2Tag = CalcTag( "OS/2" );
1320 nLength = ::GetFontData( hDC, OS2Tag, 0, NULL, 0 );
1321 if( (nLength != GDI_ERROR) && nLength )
1323 std::vector<unsigned char> aTable( nLength );
1324 unsigned char* pTable = &aTable[0];
1325 ::GetFontData( hDC, OS2Tag, 0, pTable, nLength );
1326 if (vcl::getTTCoverage(maFontCapabilities.maUnicodeRange, maFontCapabilities.maCodePageRange, pTable, nLength))
1328 // Check for CJK capabilities of the current font
1329 // TODO, we have this info already from getTT, decode bits to
1330 // a readable dynamic_bitset
1331 sal_uInt32 ulUnicodeRange1 = GetUInt( pTable + 42 );
1332 sal_uInt32 ulUnicodeRange2 = GetUInt( pTable + 46 );
1334 mbHasCJKSupport = (ulUnicodeRange2 & 0x2DF00000);
1335 mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000)
1336 | (ulUnicodeRange2 & 0x01100000);
1337 mbHasArabicSupport = (ulUnicodeRange1 & 0x00002000);
1342 void WinSalGraphics::SetTextColor( SalColor nSalColor )
1344 COLORREF aCol = PALETTERGB( SALCOLOR_RED( nSalColor ),
1345 SALCOLOR_GREEN( nSalColor ),
1346 SALCOLOR_BLUE( nSalColor ) );
1348 if( !mbPrinter &&
1349 GetSalData()->mhDitherPal &&
1350 ImplIsSysColorEntry( nSalColor ) )
1352 aCol = PALRGB_TO_RGB( aCol );
1355 ::SetTextColor( getHDC(), aCol );
1358 int CALLBACK SalEnumQueryFontProcExW( const ENUMLOGFONTEXW*,
1359 const NEWTEXTMETRICEXW*,
1360 DWORD, LPARAM lParam )
1362 *((bool*)(void*)lParam) = true;
1363 return 0;
1366 void ImplGetLogFontFromFontSelect( HDC hDC,
1367 const FontSelectPattern* pFont,
1368 LOGFONTW& rLogFont,
1369 bool /*bTestVerticalAvail*/ )
1371 OUString aName;
1372 if ( pFont->mpFontData )
1373 aName = pFont->mpFontData->GetFamilyName();
1374 else
1375 aName = pFont->GetFamilyName().getToken( 0, ';' );
1377 UINT nNameLen = aName.getLength();
1378 if ( nNameLen > (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1 )
1379 nNameLen = (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1;
1380 memcpy( rLogFont.lfFaceName, aName.getStr(), nNameLen*sizeof( wchar_t ) );
1381 rLogFont.lfFaceName[nNameLen] = 0;
1383 if( !pFont->mpFontData )
1385 rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET;
1386 rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->GetPitch() )
1387 | ImplFamilyToWin( pFont->GetFamilyType() );
1389 else
1391 const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData );
1392 rLogFont.lfCharSet = pWinFontData->GetCharSet();
1393 rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily();
1396 rLogFont.lfWeight = ImplWeightToWin( pFont->GetWeight() );
1397 rLogFont.lfHeight = (LONG)-pFont->mnHeight;
1398 rLogFont.lfWidth = (LONG)pFont->mnWidth;
1399 rLogFont.lfUnderline = 0;
1400 rLogFont.lfStrikeOut = 0;
1401 rLogFont.lfItalic = (pFont->GetSlant()) != ITALIC_NONE;
1402 rLogFont.lfEscapement = pFont->mnOrientation;
1403 rLogFont.lfOrientation = rLogFont.lfEscapement;
1404 rLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1405 rLogFont.lfQuality = DEFAULT_QUALITY;
1406 rLogFont.lfOutPrecision = OUT_TT_PRECIS;
1407 if ( pFont->mnOrientation )
1408 rLogFont.lfClipPrecision |= CLIP_LH_ANGLES;
1410 // disable antialiasing if requested
1411 if ( pFont->mbNonAntialiased )
1412 rLogFont.lfQuality = NONANTIALIASED_QUALITY;
1414 // select vertical mode if requested and available
1415 if( pFont->mbVertical && nNameLen )
1417 // vertical fonts start with an '@'
1418 memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0],
1419 sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) );
1420 rLogFont.lfFaceName[0] = '@';
1422 // check availability of vertical mode for this font
1423 bool bAvailable = false;
1424 EnumFontFamiliesExW( hDC, &rLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW,
1425 (LPARAM)&bAvailable, 0 );
1427 if( !bAvailable )
1429 // restore non-vertical name if not vertical mode isn't available
1430 memcpy( &rLogFont.lfFaceName[0], aName.getStr(), nNameLen*sizeof(wchar_t) );
1431 if( nNameLen < LF_FACESIZE )
1432 rLogFont.lfFaceName[nNameLen] = '\0';
1437 HFONT WinSalGraphics::ImplDoSetFont( FontSelectPattern* i_pFont, float& o_rFontScale, HFONT& o_rOldFont )
1439 HFONT hNewFont = 0;
1441 HDC hdcScreen = 0;
1442 if( mbVirDev )
1443 // only required for virtual devices, see below for details
1444 hdcScreen = GetDC(0);
1446 LOGFONTW aLogFont;
1447 ImplGetLogFontFromFontSelect( getHDC(), i_pFont, aLogFont, true );
1449 // on the display we prefer Courier New when Courier is a
1450 // bitmap only font and we need to stretch or rotate it
1451 if( mbScreen
1452 && (i_pFont->mnWidth != 0
1453 || i_pFont->mnOrientation != 0
1454 || i_pFont->mpFontData == NULL
1455 || (i_pFont->mpFontData->GetHeight() != i_pFont->mnHeight))
1456 && !bImplSalCourierScalable
1457 && bImplSalCourierNew
1458 && (ImplSalWICompareAscii( aLogFont.lfFaceName, "Courier" ) == 0) )
1459 lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 );
1461 // #i47675# limit font requests to MAXFONTHEIGHT
1462 // TODO: share MAXFONTHEIGHT font instance
1463 if( (-aLogFont.lfHeight <= MAXFONTHEIGHT)
1464 && (+aLogFont.lfWidth <= MAXFONTHEIGHT) )
1466 o_rFontScale = 1.0;
1468 else if( -aLogFont.lfHeight >= +aLogFont.lfWidth )
1470 o_rFontScale = -aLogFont.lfHeight / (float)MAXFONTHEIGHT;
1471 aLogFont.lfHeight = -MAXFONTHEIGHT;
1472 aLogFont.lfWidth = FRound( aLogFont.lfWidth / o_rFontScale );
1474 else // #i95867# also limit font widths
1476 o_rFontScale = +aLogFont.lfWidth / (float)MAXFONTHEIGHT;
1477 aLogFont.lfWidth = +MAXFONTHEIGHT;
1478 aLogFont.lfHeight = FRound( aLogFont.lfHeight / o_rFontScale );
1481 hNewFont = ::CreateFontIndirectW( &aLogFont );
1482 if( hdcScreen )
1484 // select font into screen hdc first to get an antialiased font
1485 // see knowledge base article 305290:
1486 // "PRB: Fonts Not Drawn Antialiased on Device Context for DirectDraw Surface"
1487 SelectFont( hdcScreen, SelectFont( hdcScreen , hNewFont ) );
1489 o_rOldFont = ::SelectFont( getHDC(), hNewFont );
1491 TEXTMETRICW aTextMetricW;
1492 if( !::GetTextMetricsW( getHDC(), &aTextMetricW ) )
1494 // the selected font doesn't work => try a replacement
1495 // TODO: use its font fallback instead
1496 lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 );
1497 aLogFont.lfPitchAndFamily = FIXED_PITCH;
1498 HFONT hNewFont2 = CreateFontIndirectW( &aLogFont );
1499 SelectFont( getHDC(), hNewFont2 );
1500 DeleteFont( hNewFont );
1501 hNewFont = hNewFont2;
1504 if( hdcScreen )
1505 ::ReleaseDC( NULL, hdcScreen );
1507 return hNewFont;
1510 sal_uInt16 WinSalGraphics::SetFont( FontSelectPattern* pFont, int nFallbackLevel )
1512 // return early if there is no new font
1513 if( !pFont )
1515 // deselect still active font
1516 if( mhDefFont )
1517 ::SelectFont( getHDC(), mhDefFont );
1518 mfCurrentFontScale = mfFontScale[nFallbackLevel];
1519 // release no longer referenced font handles
1520 for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
1522 if( mhFonts[i] )
1523 ::DeleteFont( mhFonts[i] );
1524 mhFonts[ i ] = 0;
1526 mhDefFont = 0;
1527 return 0;
1530 DBG_ASSERT( pFont->mpFontData, "WinSalGraphics mpFontData==NULL");
1531 mpWinFontEntry[ nFallbackLevel ] = reinterpret_cast<ImplWinFontEntry*>( pFont->mpFontEntry );
1532 mpWinFontData[ nFallbackLevel ] = static_cast<const ImplWinFontData*>( pFont->mpFontData );
1534 HFONT hOldFont = 0;
1535 HFONT hNewFont = ImplDoSetFont( pFont, mfFontScale[ nFallbackLevel ], hOldFont );
1536 mfCurrentFontScale = mfFontScale[nFallbackLevel];
1538 if( !mhDefFont )
1540 // keep default font
1541 mhDefFont = hOldFont;
1543 else
1545 // release no longer referenced font handles
1546 for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
1548 if( mhFonts[i] )
1550 ::DeleteFont( mhFonts[i] );
1551 mhFonts[i] = 0;
1556 // store new font in correct layer
1557 mhFonts[ nFallbackLevel ] = hNewFont;
1558 // now the font is live => update font face
1559 if( mpWinFontData[ nFallbackLevel ] )
1560 mpWinFontData[ nFallbackLevel ]->UpdateFromHDC( getHDC() );
1562 // some printers have higher internal resolution, so their
1563 // text output would be different from what we calculated
1564 // => suggest DrawTextArray to workaround this problem
1565 if ( mbPrinter )
1566 return SAL_SETFONT_USEDRAWTEXTARRAY;
1567 else
1568 return 0;
1571 void WinSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel )
1573 // temporarily change the HDC to the font in the fallback level
1574 HFONT hOldFont = SelectFont( getHDC(), mhFonts[nFallbackLevel] );
1576 wchar_t aFaceName[LF_FACESIZE+60];
1577 if( ::GetTextFaceW( getHDC(), sizeof(aFaceName)/sizeof(wchar_t), aFaceName ) )
1578 pMetric->SetFamilyName(OUString(reinterpret_cast<const sal_Unicode*>(aFaceName)));
1580 // get the font metric
1581 TEXTMETRICA aWinMetric;
1582 const bool bOK = GetTextMetricsA( getHDC(), &aWinMetric );
1583 // restore the HDC to the font in the base level
1584 SelectFont( getHDC(), hOldFont );
1585 if( !bOK )
1586 return;
1588 // device independent font attributes
1589 pMetric->SetFamilyType(ImplFamilyToSal( aWinMetric.tmPitchAndFamily ));
1590 pMetric->SetSymbolFlag(aWinMetric.tmCharSet == SYMBOL_CHARSET);
1591 pMetric->SetWeight(ImplWeightToSal( aWinMetric.tmWeight ));
1592 pMetric->SetPitch(ImplMetricPitchToSal( aWinMetric.tmPitchAndFamily ));
1593 pMetric->SetItalic(aWinMetric.tmItalic ? ITALIC_NORMAL : ITALIC_NONE);
1594 pMetric->mnSlant = 0;
1596 // device dependent font attributes
1597 pMetric->mbDevice = (aWinMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
1598 pMetric->mbScalableFont = (aWinMetric.tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) != 0;
1599 if( pMetric->mbScalableFont )
1601 // check if there are kern pairs
1602 // TODO: does this work with GPOS kerning?
1603 DWORD nKernPairs = ::GetKerningPairsA( getHDC(), 0, NULL );
1604 pMetric->mbKernableFont = (nKernPairs > 0);
1606 else
1608 // bitmap fonts cannot be rotated directly
1609 pMetric->mnOrientation = 0;
1610 // bitmap fonts have no kerning
1611 pMetric->mbKernableFont = false;
1614 // transformation dependent font metrics
1615 pMetric->mnWidth = static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmAveCharWidth );
1616 pMetric->mnIntLeading = static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmInternalLeading );
1617 pMetric->mnExtLeading = static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmExternalLeading );
1618 pMetric->mnAscent = static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmAscent );
1619 pMetric->mnDescent = static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmDescent );
1621 // #107888# improved metric compatibility for Asian fonts...
1622 // TODO: assess workaround below for CWS >= extleading
1623 // TODO: evaluate use of aWinMetric.sTypo* members for CJK
1624 if( mpWinFontData[nFallbackLevel] && mpWinFontData[nFallbackLevel]->SupportsCJK() )
1626 pMetric->mnIntLeading += pMetric->mnExtLeading;
1628 // #109280# The line height for Asian fonts is too small.
1629 // Therefore we add half of the external leading to the
1630 // ascent, the other half is added to the descent.
1631 const long nHalfTmpExtLeading = pMetric->mnExtLeading / 2;
1632 const long nOtherHalfTmpExtLeading = pMetric->mnExtLeading - nHalfTmpExtLeading;
1634 // #110641# external leading for Asian fonts.
1635 // The factor 0.3 has been confirmed with experiments.
1636 long nCJKExtLeading = static_cast<long>(0.30 * (pMetric->mnAscent + pMetric->mnDescent));
1637 nCJKExtLeading -= pMetric->mnExtLeading;
1638 pMetric->mnExtLeading = (nCJKExtLeading > 0) ? nCJKExtLeading : 0;
1640 pMetric->mnAscent += nHalfTmpExtLeading;
1641 pMetric->mnDescent += nOtherHalfTmpExtLeading;
1644 pMetric->mnMinKashida = GetMinKashidaWidth();
1647 const FontCharMapPtr WinSalGraphics::GetFontCharMap() const
1649 if( !mpWinFontData[0] )
1651 FontCharMapPtr pDefFontCharMap( new FontCharMap() );
1652 return pDefFontCharMap;
1654 return mpWinFontData[0]->GetFontCharMap();
1657 bool WinSalGraphics::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
1659 if( !mpWinFontData[0] )
1660 return false;
1661 return mpWinFontData[0]->GetFontCapabilities(rFontCapabilities);
1664 int CALLBACK SalEnumFontsProcExA( const ENUMLOGFONTEXA* pLogFont,
1665 const NEWTEXTMETRICEXA* pMetric,
1666 DWORD nFontType, LPARAM lParam )
1668 ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam;
1669 if ( !pInfo->mpName )
1671 // Ignore vertical fonts
1672 if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
1674 if ( !pInfo->mbImplSalCourierNew )
1675 pInfo->mbImplSalCourierNew = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0;
1676 if ( !pInfo->mbImplSalCourierScalable )
1677 pInfo->mbCourier = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0;
1678 else
1679 pInfo->mbCourier = FALSE;
1680 OUString aName( ImplSalGetUniString( pLogFont->elfLogFont.lfFaceName ) );
1681 pInfo->mpName = &aName;
1682 strncpy( pInfo->mpLogFontA->lfFaceName, pLogFont->elfLogFont.lfFaceName, LF_FACESIZE );
1683 pInfo->mpLogFontA->lfCharSet = pLogFont->elfLogFont.lfCharSet;
1684 EnumFontFamiliesExA( pInfo->mhDC, pInfo->mpLogFontA, (FONTENUMPROCA)SalEnumFontsProcExA,
1685 (LPARAM)(void*)pInfo, 0 );
1686 pInfo->mpLogFontA->lfFaceName[0] = '\0';
1687 pInfo->mpLogFontA->lfCharSet = DEFAULT_CHARSET;
1688 pInfo->mpName = NULL;
1689 pInfo->mbCourier = FALSE;
1692 else
1694 // ignore non-scalable non-device font on printer
1695 if( pInfo->mbPrinter )
1696 if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) )
1697 return 1;
1699 ImplWinFontData* pData = ImplLogMetricToDevFontDataA( pLogFont, &(pMetric->ntmTm), nFontType );
1700 pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
1702 // prefer the system character set, so that we get as much as
1703 // possible important characters. In the other case we could only
1704 // display a limited set of characters (#87309#)
1705 if ( pInfo->mnPreferredCharSet == pLogFont->elfLogFont.lfCharSet )
1706 pData->mnQuality += 100;
1708 // knowing Courier to be scalable is nice
1709 if( pInfo->mbCourier )
1710 pInfo->mbImplSalCourierScalable |= pData->IsScalable();
1712 pInfo->mpList->Add( pData );
1715 return 1;
1718 int CALLBACK SalEnumFontsProcExW( const ENUMLOGFONTEXW* pLogFont,
1719 const NEWTEXTMETRICEXW* pMetric,
1720 DWORD nFontType, LPARAM lParam )
1722 ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam;
1723 if ( !pInfo->mpName )
1725 // Ignore vertical fonts
1726 if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
1728 if ( !pInfo->mbImplSalCourierNew )
1729 pInfo->mbImplSalCourierNew = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0;
1730 if ( !pInfo->mbImplSalCourierScalable )
1731 pInfo->mbCourier = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0;
1732 else
1733 pInfo->mbCourier = FALSE;
1734 OUString aName = OUString(reinterpret_cast<const sal_Unicode*>(pLogFont->elfLogFont.lfFaceName));
1735 pInfo->mpName = &aName;
1736 memcpy( pInfo->mpLogFontW->lfFaceName, pLogFont->elfLogFont.lfFaceName, (aName.getLength()+1)*sizeof( wchar_t ) );
1737 pInfo->mpLogFontW->lfCharSet = pLogFont->elfLogFont.lfCharSet;
1738 EnumFontFamiliesExW( pInfo->mhDC, pInfo->mpLogFontW, (FONTENUMPROCW)SalEnumFontsProcExW,
1739 (LPARAM)(void*)pInfo, 0 );
1740 pInfo->mpLogFontW->lfFaceName[0] = '\0';
1741 pInfo->mpLogFontW->lfCharSet = DEFAULT_CHARSET;
1742 pInfo->mpName = NULL;
1743 pInfo->mbCourier = FALSE;
1746 else
1748 // ignore non-scalable non-device font on printer
1749 if( pInfo->mbPrinter )
1750 if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) )
1751 return 1;
1753 ImplWinFontData* pData = ImplLogMetricToDevFontDataW( pLogFont, &(pMetric->ntmTm), nFontType );
1754 pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
1756 // knowing Courier to be scalable is nice
1757 if( pInfo->mbCourier )
1758 pInfo->mbImplSalCourierScalable |= pData->IsScalable();
1760 pInfo->mpList->Add( pData );
1763 return 1;
1766 struct TempFontItem
1768 OUString maFontFilePath;
1769 OString maResourcePath;
1770 TempFontItem* mpNextItem;
1773 #ifdef FR_PRIVATE
1774 static int WINAPI __AddFontResourceExW( LPCWSTR lpszfileName, DWORD fl, PVOID pdv )
1776 typedef int (WINAPI *AddFontResourceExW_FUNC)(LPCWSTR, DWORD, PVOID );
1778 static AddFontResourceExW_FUNC pFunc = NULL;
1779 static HMODULE hmGDI = NULL;
1781 if ( !pFunc && !hmGDI )
1783 hmGDI = GetModuleHandleA( "GDI32" );
1784 if ( hmGDI )
1785 pFunc = reinterpret_cast<AddFontResourceExW_FUNC>( GetProcAddress( hmGDI, "AddFontResourceExW" ) );
1788 if ( pFunc )
1789 return pFunc( lpszfileName, fl, pdv );
1790 else
1792 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1793 return 0;
1796 #endif
1798 bool ImplAddTempFont( SalData& rSalData, const OUString& rFontFileURL )
1800 int nRet = 0;
1801 OUString aUSytemPath;
1802 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
1804 #ifdef FR_PRIVATE
1805 nRet = __AddFontResourceExW( reinterpret_cast<LPCWSTR>(aUSytemPath.getStr()), FR_PRIVATE, NULL );
1806 #endif
1808 if ( !nRet )
1810 static int nCounter = 0;
1811 char aFileName[] = "soAA.fot";
1812 aFileName[2] = sal::static_int_cast<char>('A' + (15 & (nCounter>>4)));
1813 aFileName[3] = sal::static_int_cast<char>('A' + (15 & nCounter));
1814 char aResourceName[512];
1815 int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16;
1816 int nLen = ::GetTempPathA( nMaxLen, aResourceName );
1817 ::strncpy( aResourceName + nLen, aFileName, sizeof( aResourceName )- nLen );
1818 // security: end buffer in any case
1819 aResourceName[ (sizeof(aResourceName)/sizeof(*aResourceName))-1 ] = 0;
1820 ::DeleteFileA( aResourceName );
1822 rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
1823 OString aCFileName = OUStringToOString( aUSytemPath, theEncoding );
1824 // TODO: font should be private => need to investigate why it doesn't work then
1825 if( !::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL ) )
1826 return false;
1827 ++nCounter;
1829 nRet = ::AddFontResourceA( aResourceName );
1830 if( nRet > 0 )
1832 TempFontItem* pNewItem = new TempFontItem;
1833 pNewItem->maResourcePath = OString( aResourceName );
1834 pNewItem->maFontFilePath = aUSytemPath.getStr();
1835 pNewItem->mpNextItem = rSalData.mpTempFontItem;
1836 rSalData.mpTempFontItem = pNewItem;
1840 return (nRet > 0);
1843 void ImplReleaseTempFonts( SalData& rSalData )
1845 int nCount = 0;
1846 while( TempFontItem* p = rSalData.mpTempFontItem )
1848 ++nCount;
1849 if( p->maResourcePath.getLength() )
1851 const char* pResourcePath = p->maResourcePath.getStr();
1852 ::RemoveFontResourceA( pResourcePath );
1853 ::DeleteFileA( pResourcePath );
1855 else
1857 ::RemoveFontResourceW( reinterpret_cast<LPCWSTR>(p->maFontFilePath.getStr()) );
1860 rSalData.mpTempFontItem = p->mpNextItem;
1861 delete p;
1864 #ifndef FR_PRIVATE
1865 // notify every other application
1866 // unless the temp fonts were installed as private fonts
1867 if( nCount > 0 )
1868 PostMessageW( HWND_BROADCAST, WM_FONTCHANGE, 0, NULL );
1869 #endif // FR_PRIVATE
1872 static bool ImplGetFontAttrFromFile( const OUString& rFontFileURL,
1873 ImplDevFontAttributes& rDFA )
1875 OUString aUSytemPath;
1876 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
1878 // get FontAttributes from a *fot file
1879 // TODO: use GetTTGlobalFontInfo() to access the font directly
1880 rDFA.mnQuality = 1000;
1881 rDFA.mbDevice = true;
1882 rDFA.SetFamilyType(FAMILY_DONTKNOW);
1883 rDFA.SetWidthType(WIDTH_DONTKNOW);
1884 rDFA.SetWeight(WEIGHT_DONTKNOW);
1885 rDFA.SetItalic(ITALIC_DONTKNOW);
1886 rDFA.SetPitch(PITCH_DONTKNOW);
1887 rDFA.mbSubsettable= true;
1888 rDFA.mbEmbeddable = false;
1890 // Create temporary file name
1891 char aFileName[] = "soAAT.fot";
1892 char aResourceName[512];
1893 int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16;
1894 int nLen = ::GetTempPathA( nMaxLen, aResourceName );
1895 ::strncpy( aResourceName + nLen, aFileName, std::max( 0, nMaxLen - nLen ));
1896 ::DeleteFileA( aResourceName );
1898 // Create font resource file (typically with a .fot file name extension).
1899 rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
1900 OString aCFileName = OUStringToOString( aUSytemPath, theEncoding );
1901 ::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL );
1903 // Open and read the font resource file
1904 OUString aFotFileName = OStringToOUString( aResourceName, osl_getThreadTextEncoding() );
1905 osl::FileBase::getFileURLFromSystemPath( aFotFileName, aFotFileName );
1906 osl::File aFotFile( aFotFileName );
1907 osl::FileBase::RC aError = aFotFile.open( osl_File_OpenFlag_Read );
1908 if( aError != osl::FileBase::E_None )
1909 return false;
1911 sal_uInt64 nBytesRead = 0;
1912 char aBuffer[4096];
1913 aFotFile.read( aBuffer, sizeof( aBuffer ), nBytesRead );
1914 // clean up temporary resource file
1915 aFotFile.close();
1916 ::DeleteFileA( aResourceName );
1918 // retrieve font family name from byte offset 0x4F6
1919 sal_uInt64 i = 0x4F6;
1920 sal_uInt64 nNameOfs = i;
1921 while( (i < nBytesRead) && (aBuffer[i++] != 0) );
1922 // skip full name
1923 while( (i < nBytesRead) && (aBuffer[i++] != 0) );
1924 // retrieve font style name
1925 int nStyleOfs = i;
1926 while( (i < nBytesRead) && (aBuffer[i++] != 0) );
1927 if( i >= nBytesRead )
1928 return false;
1930 // convert byte strings to unicode
1931 char *pName = aBuffer + nNameOfs;
1932 rDFA.SetFamilyName(OUString(pName, strlen(pName), osl_getThreadTextEncoding()));
1933 char *pStyle = aBuffer + nStyleOfs;
1934 rDFA.SetStyleName(OUString(pStyle, strlen(pStyle), osl_getThreadTextEncoding() ));
1936 // byte offset 0x4C7: OS2_fsSelection
1937 const char nFSS = aBuffer[ 0x4C7 ];
1938 if( nFSS & 0x01 ) // italic
1939 rDFA.SetItalic(ITALIC_NORMAL);
1940 //if( nFSS & 0x20 ) // bold
1941 // rDFA.meWeight = WEIGHT_BOLD;
1942 if( nFSS & 0x40 ) // regular
1944 rDFA.SetWeight(WEIGHT_NORMAL);
1945 rDFA.SetItalic(ITALIC_NONE);
1948 // byte offsets 0x4D7/0x4D8: wingdi's FW_WEIGHT
1949 int nWinWeight = (aBuffer[0x4D7] & 0xFF) + ((aBuffer[0x4D8] & 0xFF) << 8);
1950 rDFA.SetWeight(ImplWeightToSal( nWinWeight ));
1952 rDFA.SetSymbolFlag(false); // TODO
1953 rDFA.SetPitch(PITCH_DONTKNOW); // TODO
1955 // byte offset 0x4DE: pitch&family
1956 rDFA.SetFamilyType(ImplFamilyToSal( aBuffer[0x4DE] ));
1958 // byte offsets 0x4C8/0x4C9: emunits
1959 // byte offsets 0x4CE/0x4CF: winascent
1960 // byte offsets 0x4D0/0x4D1: winascent+windescent-emunits
1961 // byte offsets 0x4DF/0x4E0: avgwidth
1963 return true;
1966 bool WinSalGraphics::AddTempDevFont( PhysicalFontCollection* pFontCollection,
1967 const OUString& rFontFileURL, const OUString& rFontName )
1969 SAL_INFO( "vcl.gdi", "WinSalGraphics::AddTempDevFont(): " << OUStringToOString( rFontFileURL, RTL_TEXTENCODING_UTF8 ).getStr() );
1971 ImplDevFontAttributes aDFA;
1972 aDFA.SetFamilyName(rFontName);
1973 aDFA.mnQuality = 1000;
1974 aDFA.mbDevice = true;
1976 // Search Font Name in Cache
1977 if( rFontName.isEmpty() && mpFontAttrCache )
1978 aDFA = mpFontAttrCache->GetFontAttr( rFontFileURL );
1980 // Retrieve font name from font resource
1981 if( aDFA.GetFamilyName().isEmpty() )
1983 ImplGetFontAttrFromFile( rFontFileURL, aDFA );
1984 if( mpFontAttrCache && !aDFA.GetFamilyName().isEmpty() )
1985 mpFontAttrCache->AddFontAttr( rFontFileURL, aDFA );
1988 if ( aDFA.GetFamilyName().isEmpty() )
1989 return false;
1991 // remember temp font for cleanup later
1992 if( !ImplAddTempFont( *GetSalData(), rFontFileURL ) )
1993 return false;
1995 UINT nPreferredCharSet = DEFAULT_CHARSET;
1997 // create matching FontData struct
1998 aDFA.SetSymbolFlag(false); // TODO: how to know it without accessing the font?
1999 aDFA.SetFamilyType(FAMILY_DONTKNOW);
2000 aDFA.SetWidthType(WIDTH_DONTKNOW);
2001 aDFA.SetWeight(WEIGHT_DONTKNOW);
2002 aDFA.SetItalic(ITALIC_DONTKNOW);
2003 aDFA.SetPitch(PITCH_DONTKNOW);
2004 aDFA.mbSubsettable= true;
2005 aDFA.mbEmbeddable = false;
2008 // TODO: improve ImplDevFontAttributes using the "font resource file"
2009 aDFS.maName = // using "FONTRES:" from file
2010 if( rFontName != aDFS.maName )
2011 aDFS.maMapName = aFontName;
2014 ImplWinFontData* pFontData = new ImplWinFontData( aDFA, 0,
2015 sal::static_int_cast<BYTE>(nPreferredCharSet),
2016 sal::static_int_cast<BYTE>(TMPF_VECTOR|TMPF_TRUETYPE) );
2017 pFontData->SetFontId( reinterpret_cast<sal_IntPtr>(pFontData) );
2018 pFontCollection->Add( pFontData );
2019 return true;
2022 void WinSalGraphics::GetDevFontList( PhysicalFontCollection* pFontCollection )
2024 // make sure all fonts are registered at least temporarily
2025 static bool bOnce = true;
2026 if( bOnce )
2028 bOnce = false;
2030 // determine font path
2031 // since we are only interested in fonts that could not be
2032 // registered before because of missing administration rights
2033 // only the font path of the user installation is needed
2034 OUString aPath;
2035 osl_getExecutableFile( &aPath.pData );
2036 aPath = aPath.copy( 0, aPath.lastIndexOf('/') );
2037 OUString aFontDirUrl = aPath.copy( 0, aPath.lastIndexOf('/') );
2038 aFontDirUrl += "/" LIBO_SHARE_FOLDER "/fonts/truetype";
2040 // collect fonts in font path that could not be registered
2041 osl::Directory aFontDir( aFontDirUrl );
2042 osl::FileBase::RC rcOSL = aFontDir.open();
2043 if( rcOSL == osl::FileBase::E_None )
2045 osl::DirectoryItem aDirItem;
2046 OUString aEmptyString;
2048 OUString aBootStrap;
2049 rtl::Bootstrap::get( OUString("BRAND_BASE_DIR"), aBootStrap );
2050 aBootStrap += "/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE( "bootstrap" );
2051 rtl::Bootstrap aBootstrap( aBootStrap );
2052 OUString aUserPath;
2053 aBootstrap.getFrom( OUString( "UserInstallation" ), aUserPath );
2054 aUserPath += "/user/config/fontnames.dat";
2055 OUString aBaseURL = aPath.copy( 0, aPath.lastIndexOf('/')+1 );
2056 mpFontAttrCache = new ImplFontAttrCache( aUserPath, aBaseURL );
2058 while( aFontDir.getNextItem( aDirItem, 10 ) == osl::FileBase::E_None )
2060 osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileURL );
2061 rcOSL = aDirItem.getFileStatus( aFileStatus );
2062 if ( rcOSL == osl::FileBase::E_None )
2063 AddTempDevFont( pFontCollection, aFileStatus.getFileURL(), aEmptyString );
2066 delete mpFontAttrCache; // destructor rewrites the cache file if needed
2067 mpFontAttrCache = NULL;
2071 ImplEnumInfo aInfo;
2072 aInfo.mhDC = getHDC();
2073 aInfo.mpList = pFontCollection;
2074 aInfo.mpName = NULL;
2075 aInfo.mpLogFontA = NULL;
2076 aInfo.mpLogFontW = NULL;
2077 aInfo.mbCourier = false;
2078 aInfo.mbPrinter = mbPrinter;
2079 aInfo.mnFontCount = 0;
2080 if ( !mbPrinter )
2082 aInfo.mbImplSalCourierScalable = false;
2083 aInfo.mbImplSalCourierNew = false;
2085 else
2087 aInfo.mbImplSalCourierScalable = true;
2088 aInfo.mbImplSalCourierNew = true;
2091 aInfo.mnPreferredCharSet = DEFAULT_CHARSET;
2092 DWORD nCP = GetACP();
2093 CHARSETINFO aCharSetInfo;
2094 if ( TranslateCharsetInfo( (DWORD*)(sal_IntPtr)nCP, &aCharSetInfo, TCI_SRCCODEPAGE ) )
2095 aInfo.mnPreferredCharSet = aCharSetInfo.ciCharset;
2097 LOGFONTW aLogFont;
2098 memset( &aLogFont, 0, sizeof( aLogFont ) );
2099 aLogFont.lfCharSet = DEFAULT_CHARSET;
2100 aInfo.mpLogFontW = &aLogFont;
2101 EnumFontFamiliesExW( getHDC(), &aLogFont,
2102 (FONTENUMPROCW)SalEnumFontsProcExW, (LPARAM)(void*)&aInfo, 0 );
2104 // check what Courier fonts are used on the screen, so to perhaps
2105 // map Courier to CourierNew in SetFont()
2106 if ( !mbPrinter )
2108 bImplSalCourierScalable = aInfo.mbImplSalCourierScalable;
2109 bImplSalCourierNew = aInfo.mbImplSalCourierNew;
2112 // set glyph fallback hook
2113 static WinGlyphFallbackSubstititution aSubstFallback( getHDC() );
2114 pFontCollection->SetFallbackHook( &aSubstFallback );
2117 void WinSalGraphics::ClearDevFontCache()
2119 //anything to do here ?
2122 bool WinSalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect )
2124 HDC hDC = getHDC();
2126 // use unity matrix
2127 MAT2 aMat;
2128 aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
2129 aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
2131 UINT nGGOFlags = GGO_METRICS;
2132 if( !(aGlyphId & GF_ISCHAR) )
2133 nGGOFlags |= GGO_GLYPH_INDEX;
2134 aGlyphId &= GF_IDXMASK;
2136 GLYPHMETRICS aGM;
2137 aGM.gmptGlyphOrigin.x = aGM.gmptGlyphOrigin.y = 0;
2138 aGM.gmBlackBoxX = aGM.gmBlackBoxY = 0;
2139 DWORD nSize = ::GetGlyphOutlineW( hDC, aGlyphId, nGGOFlags, &aGM, 0, NULL, &aMat );
2140 if( nSize == GDI_ERROR )
2141 return false;
2143 rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
2144 Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
2145 rRect.Left() = static_cast<int>( mfCurrentFontScale * rRect.Left() );
2146 rRect.Right() = static_cast<int>( mfCurrentFontScale * rRect.Right() );
2147 rRect.Top() = static_cast<int>( mfCurrentFontScale * rRect.Top() );
2148 rRect.Bottom() = static_cast<int>( mfCurrentFontScale * rRect.Bottom() );
2149 return true;
2152 bool WinSalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId,
2153 ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
2155 rB2DPolyPoly.clear();
2157 HDC hDC = getHDC();
2159 // use unity matrix
2160 MAT2 aMat;
2161 aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
2162 aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
2164 UINT nGGOFlags = GGO_NATIVE;
2165 if( !(aGlyphId & GF_ISCHAR) )
2166 nGGOFlags |= GGO_GLYPH_INDEX;
2167 aGlyphId &= GF_IDXMASK;
2169 GLYPHMETRICS aGlyphMetrics;
2170 const DWORD nSize1 = ::GetGlyphOutlineW( hDC, aGlyphId, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
2171 if( !nSize1 ) // blank glyphs are ok
2172 return true;
2173 else if( nSize1 == GDI_ERROR )
2174 return false;
2176 BYTE* pData = new BYTE[ nSize1 ];
2177 const DWORD nSize2 = ::GetGlyphOutlineW( hDC, aGlyphId, nGGOFlags,
2178 &aGlyphMetrics, nSize1, pData, &aMat );
2180 if( nSize1 != nSize2 )
2181 return false;
2183 // TODO: avoid tools polygon by creating B2DPolygon directly
2184 int nPtSize = 512;
2185 Point* pPoints = new Point[ nPtSize ];
2186 BYTE* pFlags = new BYTE[ nPtSize ];
2188 TTPOLYGONHEADER* pHeader = (TTPOLYGONHEADER*)pData;
2189 while( (BYTE*)pHeader < pData+nSize2 )
2191 // only outline data is interesting
2192 if( pHeader->dwType != TT_POLYGON_TYPE )
2193 break;
2195 // get start point; next start points are end points
2196 // of previous segment
2197 sal_uInt16 nPnt = 0;
2199 long nX = IntTimes256FromFixed( pHeader->pfxStart.x );
2200 long nY = IntTimes256FromFixed( pHeader->pfxStart.y );
2201 pPoints[ nPnt ] = Point( nX, nY );
2202 pFlags[ nPnt++ ] = POLY_NORMAL;
2204 bool bHasOfflinePoints = false;
2205 TTPOLYCURVE* pCurve = (TTPOLYCURVE*)( pHeader + 1 );
2206 pHeader = (TTPOLYGONHEADER*)( (BYTE*)pHeader + pHeader->cb );
2207 while( (BYTE*)pCurve < (BYTE*)pHeader )
2209 int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx;
2210 if( nPtSize < nNeededSize )
2212 Point* pOldPoints = pPoints;
2213 BYTE* pOldFlags = pFlags;
2214 nPtSize = 2 * nNeededSize;
2215 pPoints = new Point[ nPtSize ];
2216 pFlags = new BYTE[ nPtSize ];
2217 for( sal_uInt16 i = 0; i < nPnt; ++i )
2219 pPoints[ i ] = pOldPoints[ i ];
2220 pFlags[ i ] = pOldFlags[ i ];
2222 delete[] pOldPoints;
2223 delete[] pOldFlags;
2226 int i = 0;
2227 if( TT_PRIM_LINE == pCurve->wType )
2229 while( i < pCurve->cpfx )
2231 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2232 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2233 ++i;
2234 pPoints[ nPnt ] = Point( nX, nY );
2235 pFlags[ nPnt ] = POLY_NORMAL;
2236 ++nPnt;
2239 else if( TT_PRIM_QSPLINE == pCurve->wType )
2241 bHasOfflinePoints = true;
2242 while( i < pCurve->cpfx )
2244 // get control point of quadratic bezier spline
2245 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2246 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2247 ++i;
2248 Point aControlP( nX, nY );
2250 // calculate first cubic control point
2251 // P0 = 1/3 * (PBeg + 2 * PQControl)
2252 nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X();
2253 nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y();
2254 pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
2255 pFlags[ nPnt+0 ] = POLY_CONTROL;
2257 // calculate endpoint of segment
2258 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2259 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2261 if ( i+1 >= pCurve->cpfx )
2263 // endpoint is either last point in segment => advance
2264 ++i;
2266 else
2268 // or endpoint is the middle of two control points
2269 nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x );
2270 nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y );
2271 nX = (nX + 1) / 2;
2272 nY = (nY + 1) / 2;
2273 // no need to advance, because the current point
2274 // is the control point in next bezier spline
2277 pPoints[ nPnt+2 ] = Point( nX, nY );
2278 pFlags[ nPnt+2 ] = POLY_NORMAL;
2280 // calculate second cubic control point
2281 // P1 = 1/3 * (PEnd + 2 * PQControl)
2282 nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X();
2283 nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y();
2284 pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
2285 pFlags[ nPnt+1 ] = POLY_CONTROL;
2287 nPnt += 3;
2291 // next curve segment
2292 pCurve = (TTPOLYCURVE*)&pCurve->apfx[ i ];
2295 // end point is start point for closed contour
2296 // disabled, because Polygon class closes the contour itself
2297 // pPoints[nPnt++] = pPoints[0];
2298 // #i35928#
2299 // Added again, but add only when not yet closed
2300 if(pPoints[nPnt - 1] != pPoints[0])
2302 if( bHasOfflinePoints )
2303 pFlags[nPnt] = pFlags[0];
2305 pPoints[nPnt++] = pPoints[0];
2308 // convert y-coordinates W32 -> VCL
2309 for( int i = 0; i < nPnt; ++i )
2310 pPoints[i].Y() = -pPoints[i].Y();
2312 // insert into polypolygon
2313 Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : NULL) );
2314 // convert to B2DPolyPolygon
2315 // TODO: get rid of the intermediate PolyPolygon
2316 rB2DPolyPoly.append( aPoly.getB2DPolygon() );
2319 delete[] pPoints;
2320 delete[] pFlags;
2322 delete[] pData;
2324 // rescaling needed for the tools::PolyPolygon conversion
2325 if( rB2DPolyPoly.count() )
2327 const double fFactor(mfCurrentFontScale/256);
2328 rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fFactor, fFactor));
2331 return true;
2334 class ScopedFont
2336 public:
2337 explicit ScopedFont(WinSalGraphics & rData);
2339 ~ScopedFont();
2341 private:
2342 WinSalGraphics & m_rData;
2343 HFONT m_hOrigFont;
2346 ScopedFont::ScopedFont(WinSalGraphics & rData): m_rData(rData)
2348 m_hOrigFont = m_rData.mhFonts[0];
2349 m_rData.mhFonts[0] = 0; // avoid deletion of current font
2352 ScopedFont::~ScopedFont()
2354 if( m_hOrigFont )
2356 // restore original font, destroy temporary font
2357 HFONT hTempFont = m_rData.mhFonts[0];
2358 m_rData.mhFonts[0] = m_hOrigFont;
2359 SelectObject( m_rData.getHDC(), m_hOrigFont );
2360 DeleteObject( hTempFont );
2364 class ScopedTrueTypeFont
2366 public:
2367 inline ScopedTrueTypeFont(): m_pFont(0) {}
2369 ~ScopedTrueTypeFont();
2371 int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum);
2373 inline TrueTypeFont * get() const { return m_pFont; }
2375 private:
2376 TrueTypeFont * m_pFont;
2379 ScopedTrueTypeFont::~ScopedTrueTypeFont()
2381 if (m_pFont != 0)
2382 CloseTTFont(m_pFont);
2385 int ScopedTrueTypeFont::open(void * pBuffer, sal_uInt32 nLen,
2386 sal_uInt32 nFaceNum)
2388 OSL_ENSURE(m_pFont == 0, "already open");
2389 return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont);
2392 bool WinSalGraphics::CreateFontSubset( const OUString& rToFile,
2393 const PhysicalFontFace* pFont, const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding,
2394 sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
2396 // TODO: use more of the central font-subsetting code, move stuff there if needed
2398 // create matching FontSelectPattern
2399 // we need just enough to get to the font file data
2400 // use height=1000 for easier debugging (to match psprint's font units)
2401 FontSelectPattern aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2403 // TODO: much better solution: move SetFont and restoration of old font to caller
2404 ScopedFont aOldFont(*this);
2405 float fScale = 1.0;
2406 HFONT hOldFont = 0;
2407 ImplDoSetFont( &aIFSD, fScale, hOldFont );
2409 ImplWinFontData* pWinFontData = (ImplWinFontData*)aIFSD.mpFontData;
2411 #if OSL_DEBUG_LEVEL > 1
2412 // get font metrics
2413 TEXTMETRICA aWinMetric;
2414 if( !::GetTextMetricsA( getHDC(), &aWinMetric ) )
2415 return FALSE;
2417 DBG_ASSERT( !(aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "cannot subset device font" );
2418 DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" );
2419 #endif
2421 OUString aSysPath;
2422 if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
2423 return FALSE;
2424 const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
2425 const OString aToFile(OUStringToOString(aSysPath, aThreadEncoding));
2427 // check if the font has a CFF-table
2428 const DWORD nCffTag = CalcTag( "CFF " );
2429 const RawFontData aRawCffData( getHDC(), nCffTag );
2430 if( aRawCffData.get() )
2432 pWinFontData->UpdateFromHDC( getHDC() );
2433 FontCharMapPtr pCharMap = pWinFontData->GetFontCharMap();
2435 sal_GlyphId aRealGlyphIds[ 256 ];
2436 for( int i = 0; i < nGlyphCount; ++i )
2438 // TODO: remap notdef glyph if needed
2439 // TODO: use GDI's GetGlyphIndices instead? Does it handle GSUB properly?
2440 sal_GlyphId aGlyphId = pGlyphIds[i] & GF_IDXMASK;
2441 if( pGlyphIds[i] & GF_ISCHAR ) // remaining pseudo-glyphs need to be translated
2442 aGlyphId = pCharMap->GetGlyphIndex( aGlyphId );
2443 if( (pGlyphIds[i] & (GF_ROTMASK|GF_GSUB)) != 0) // TODO: vertical substitution
2444 {/*####*/}
2446 aRealGlyphIds[i] = aGlyphId;
2449 pCharMap = 0;
2451 // provide a font subset from the CFF-table
2452 FILE* pOutFile = fopen( aToFile.getStr(), "wb" );
2453 rInfo.LoadFont( FontSubsetInfo::CFF_FONT, aRawCffData.get(), aRawCffData.size() );
2454 bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL,
2455 aRealGlyphIds, pEncoding, nGlyphCount, pGlyphWidths );
2456 fclose( pOutFile );
2457 return bRC;
2460 // get raw font file data
2461 const RawFontData xRawFontData( getHDC(), 0 );
2462 if( !xRawFontData.get() )
2463 return FALSE;
2465 // open font file
2466 sal_uInt32 nFaceNum = 0;
2467 if( !*xRawFontData.get() ) // TTC candidate
2468 nFaceNum = ~0U; // indicate "TTC font extracts only"
2470 ScopedTrueTypeFont aSftTTF;
2471 int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
2472 if( nRC != SF_OK )
2473 return FALSE;
2475 TTGlobalFontInfo aTTInfo;
2476 ::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
2477 rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF;
2478 rInfo.m_aPSName = ImplSalGetUniString( aTTInfo.psname );
2479 rInfo.m_nAscent = aTTInfo.winAscent;
2480 rInfo.m_nDescent = aTTInfo.winDescent;
2481 rInfo.m_aFontBBox = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
2482 Point( aTTInfo.xMax, aTTInfo.yMax ) );
2483 rInfo.m_nCapHeight = aTTInfo.yMax; // Well ...
2485 // subset TTF-glyphs and get their properties
2486 // take care that subset fonts require the NotDef glyph in pos 0
2487 int nOrigCount = nGlyphCount;
2488 sal_uInt16 aShortIDs[ 256 ];
2489 sal_uInt8 aTempEncs[ 256 ];
2491 int nNotDef=-1, i;
2492 for( i = 0; i < nGlyphCount; ++i )
2494 aTempEncs[i] = pEncoding[i];
2495 sal_GlyphId aGlyphId = pGlyphIds[i] & GF_IDXMASK;
2496 if( pGlyphIds[i] & GF_ISCHAR )
2498 sal_Unicode cChar = static_cast<sal_Unicode>(aGlyphId); // TODO: sal_UCS4
2499 const bool bVertical = ((pGlyphIds[i] & (GF_ROTMASK|GF_GSUB)) != 0);
2500 aGlyphId = ::MapChar( aSftTTF.get(), cChar, bVertical );
2501 if( (aGlyphId == 0) && pFont->IsSymbolFont() )
2503 // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
2504 cChar = (cChar & 0xF000) ? (cChar & 0x00FF) : (cChar | 0xF000);
2505 aGlyphId = ::MapChar( aSftTTF.get(), cChar, bVertical );
2508 aShortIDs[i] = static_cast<sal_uInt16>( aGlyphId );
2509 if( !aGlyphId )
2510 if( nNotDef < 0 )
2511 nNotDef = i; // first NotDef glyph found
2514 if( nNotDef != 0 )
2516 // add fake NotDef glyph if needed
2517 if( nNotDef < 0 )
2518 nNotDef = nGlyphCount++;
2520 // NotDef glyph must be in pos 0 => swap glyphids
2521 aShortIDs[ nNotDef ] = aShortIDs[0];
2522 aTempEncs[ nNotDef ] = aTempEncs[0];
2523 aShortIDs[0] = 0;
2524 aTempEncs[0] = 0;
2526 DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
2528 // fill pWidth array
2529 TTSimpleGlyphMetrics* pMetrics =
2530 ::GetTTSimpleGlyphMetrics( aSftTTF.get(), aShortIDs, nGlyphCount, aIFSD.mbVertical );
2531 if( !pMetrics )
2532 return FALSE;
2533 sal_uInt16 nNotDefAdv = pMetrics[0].adv;
2534 pMetrics[0].adv = pMetrics[nNotDef].adv;
2535 pMetrics[nNotDef].adv = nNotDefAdv;
2536 for( i = 0; i < nOrigCount; ++i )
2537 pGlyphWidths[i] = pMetrics[i].adv;
2538 free( pMetrics );
2540 // write subset into destination file
2541 nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.getStr(), aShortIDs,
2542 aTempEncs, nGlyphCount, 0, NULL, 0 );
2543 return (nRC == SF_OK);
2546 const void* WinSalGraphics::GetEmbedFontData( const PhysicalFontFace* pFont,
2547 const sal_Unicode* pUnicodes, sal_Int32* pCharWidths, size_t nLen,
2548 FontSubsetInfo& rInfo, long* pDataLen )
2550 // create matching FontSelectPattern
2551 // we need just enough to get to the font file data
2552 FontSelectPattern aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2554 // TODO: much better solution: move SetFont and restoration of old font to caller
2555 ScopedFont aOldFont(*this);
2556 SetFont( &aIFSD, 0 );
2558 // get the raw font file data
2559 RawFontData aRawFontData( getHDC() );
2560 *pDataLen = aRawFontData.size();
2561 if( !aRawFontData.get() )
2562 return NULL;
2564 // get important font properties
2565 TEXTMETRICA aTm;
2566 if( !::GetTextMetricsA( getHDC(), &aTm ) )
2567 *pDataLen = 0;
2568 const bool bPFA = (*aRawFontData.get() < 0x80);
2569 rInfo.m_nFontType = bPFA ? FontSubsetInfo::TYPE1_PFA : FontSubsetInfo::TYPE1_PFB;
2570 WCHAR aFaceName[64];
2571 sal_Int32 nFNLen = ::GetTextFaceW( getHDC(), 64, aFaceName );
2572 // #i59854# strip eventual null byte
2573 while( nFNLen > 0 && aFaceName[nFNLen-1] == 0 )
2574 nFNLen--;
2575 if( nFNLen == 0 )
2576 *pDataLen = 0;
2577 rInfo.m_aPSName = OUString(reinterpret_cast<const sal_Unicode*>(aFaceName), nFNLen);
2578 rInfo.m_nAscent = +aTm.tmAscent;
2579 rInfo.m_nDescent = -aTm.tmDescent;
2580 rInfo.m_aFontBBox = Rectangle( Point( -aTm.tmOverhang, -aTm.tmDescent ),
2581 Point( aTm.tmMaxCharWidth, aTm.tmAscent+aTm.tmExternalLeading ) );
2582 rInfo.m_nCapHeight = aTm.tmAscent; // Well ...
2584 // get individual character widths
2585 for (size_t i = 0; i < nLen; ++i)
2587 int nCharWidth = 0;
2588 const sal_Unicode cChar = pUnicodes[i];
2589 if( !::GetCharWidth32W( getHDC(), cChar, cChar, &nCharWidth ) )
2590 *pDataLen = 0;
2591 pCharWidths[i] = nCharWidth;
2594 if( !*pDataLen )
2595 return NULL;
2597 const unsigned char* pData = aRawFontData.steal();
2598 return (void*)pData;
2601 void WinSalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ )
2603 delete[] reinterpret_cast<char*>(const_cast<void*>(pData));
2606 const Ucs2SIntMap* WinSalGraphics::GetFontEncodingVector( const PhysicalFontFace* pFont, const Ucs2OStrMap** pNonEncoded, std::set<sal_Unicode> const**)
2608 // TODO: even for builtin fonts we get here... why?
2609 if( !pFont->IsEmbeddable() )
2610 return NULL;
2612 // fill the encoding vector
2613 // currently no nonencoded vector
2614 if( pNonEncoded )
2615 *pNonEncoded = NULL;
2617 const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>(pFont);
2618 const Ucs2SIntMap* pEncoding = pWinFontData->GetEncodingVector();
2619 if( pEncoding == NULL )
2621 Ucs2SIntMap* pNewEncoding = new Ucs2SIntMap;
2622 for( sal_Unicode i = 32; i < 256; ++i )
2623 (*pNewEncoding)[i] = i;
2624 pWinFontData->SetEncodingVector( pNewEncoding );
2625 pEncoding = pNewEncoding;
2628 return pEncoding;
2631 void WinSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFont,
2632 bool bVertical,
2633 Int32Vector& rWidths,
2634 Ucs2UIntMap& rUnicodeEnc )
2636 // create matching FontSelectPattern
2637 // we need just enough to get to the font file data
2638 FontSelectPattern aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2640 // TODO: much better solution: move SetFont and restoration of old font to caller
2641 ScopedFont aOldFont(*this);
2643 float fScale = 0.0;
2644 HFONT hOldFont = 0;
2645 ImplDoSetFont( &aIFSD, fScale, hOldFont );
2647 if( pFont->IsSubsettable() )
2649 // get raw font file data
2650 const RawFontData xRawFontData( getHDC() );
2651 if( !xRawFontData.get() )
2652 return;
2654 // open font file
2655 sal_uInt32 nFaceNum = 0;
2656 if( !*xRawFontData.get() ) // TTC candidate
2657 nFaceNum = ~0U; // indicate "TTC font extracts only"
2659 ScopedTrueTypeFont aSftTTF;
2660 int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
2661 if( nRC != SF_OK )
2662 return;
2664 int nGlyphs = GetTTGlyphCount( aSftTTF.get() );
2665 if( nGlyphs > 0 )
2667 rWidths.resize(nGlyphs);
2668 std::vector<sal_uInt16> aGlyphIds(nGlyphs);
2669 for( int i = 0; i < nGlyphs; i++ )
2670 aGlyphIds[i] = sal_uInt16(i);
2671 TTSimpleGlyphMetrics* pMetrics = ::GetTTSimpleGlyphMetrics( aSftTTF.get(),
2672 &aGlyphIds[0],
2673 nGlyphs,
2674 bVertical );
2675 if( pMetrics )
2677 for( int i = 0; i< nGlyphs; i++ )
2678 rWidths[i] = pMetrics[i].adv;
2679 free( pMetrics );
2680 rUnicodeEnc.clear();
2682 const ImplWinFontData* pWinFont = static_cast<const ImplWinFontData*>(pFont);
2683 FontCharMapPtr pMap = pWinFont->GetFontCharMap();
2684 DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" );
2686 int nCharCount = pMap->GetCharCount();
2687 sal_uInt32 nChar = pMap->GetFirstChar();
2688 for( int i = 0; i < nCharCount; i++ )
2690 if( nChar < 0x00010000 )
2692 sal_uInt16 nGlyph = ::MapChar( aSftTTF.get(),
2693 static_cast<sal_Ucs>(nChar),
2694 bVertical );
2695 if( nGlyph )
2696 rUnicodeEnc[ static_cast<sal_Unicode>(nChar) ] = nGlyph;
2698 nChar = pMap->GetNextChar( nChar );
2701 pMap = 0;
2704 else if( pFont->IsEmbeddable() )
2706 // get individual character widths
2707 rWidths.clear();
2708 rUnicodeEnc.clear();
2709 rWidths.reserve( 224 );
2710 for( sal_Unicode i = 32; i < 256; ++i )
2712 int nCharWidth = 0;
2713 if( ::GetCharWidth32W( getHDC(), i, i, &nCharWidth ) )
2715 rUnicodeEnc[ i ] = rWidths.size();
2716 rWidths.push_back( nCharWidth );
2722 void WinSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
2725 SystemFontData WinSalGraphics::GetSysFontData( int nFallbacklevel ) const
2727 SystemFontData aSysFontData;
2729 if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
2730 if (nFallbacklevel < 0 ) nFallbacklevel = 0;
2732 aSysFontData.hFont = mhFonts[nFallbacklevel];
2734 OSL_TRACE("\r\n:WinSalGraphics::GetSysFontData(): FontID: %p, Fallback level: %d",
2735 aSysFontData.hFont, nFallbacklevel);
2737 return aSysFontData;
2740 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */