1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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"
46 #include "PhysicalFontCollection.hxx"
47 #include "PhysicalFontFace.hxx"
49 #include "win/saldata.hxx"
50 #include "win/salgdi.h"
54 static const int MAXFONTHEIGHT
= 2048;
58 inline FIXED
FixedFromDouble( double d
)
60 const long l
= (long) ( d
* 65536. );
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
80 FontAttrMap aFontAttributes
;
81 OUString aCacheFileName
;
86 OUString
OptimizeURL( const OUString
& rURL
) const;
88 enum{ MAGIC
= 0x12349876 }; // change if fontattrcache format changes
91 ImplFontAttrCache(const OUString
& rCacheFileName
,
92 const OUString
& rBaseURL
);
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
)
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() )
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
;
121 aFontFileURL
= read_uInt16_lenPrefixed_uInt8s_ToOUString(aCacheFile
, RTL_TEXTENCODING_UTF8
);
122 if( aFontFileURL
.isEmpty() )
124 aDFA
.SetFamilyName(read_uInt16_lenPrefixed_uInt8s_ToOUString(aCacheFile
, RTL_TEXTENCODING_UTF8
));
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);
141 aCacheFile
.ReadByteStringLine( styleName
, RTL_TEXTENCODING_UTF8
);
142 aDFA
.SetStyleName( styleName
);
144 aFontAttributes
[ aFontFileURL
] = aDFA
;
148 ImplFontAttrCache::~ImplFontAttrCache()
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
);
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() )
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
) );
214 // raw font data with a scoped lifetime
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
; }
225 unsigned char* mpRawBytes
;
226 unsigned mnByteCount
;
229 RawFontData::RawFontData( HDC hDC
, DWORD nTableTag
)
233 // get required size in bytes
234 mnByteCount
= ::GetFontData( hDC
, nTableTag
, 0, NULL
, 0 );
235 if( mnByteCount
== GDI_ERROR
)
237 else if( !mnByteCount
)
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;
248 // calculate remaining raw data to get
249 DWORD nFDGet
= mnByteCount
- nRawDataOfs
;
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
);
259 else if( nFDGot
!= GDI_ERROR
)
260 nRawDataOfs
+= nFDGot
;
263 // was the chunk too big? reduce it
265 if( nMaxChunkSize
< 0x10000 )
270 // cleanup if the raw data is incomplete
271 if( nRawDataOfs
!= mnByteCount
)
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
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;
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;
380 LONG lResult
= ::RegOpenKeyExA( HKEY_LOCAL_MACHINE
,
381 "SYSTEM\\CurrentControlSet\\Control\\Nls\\Language",
382 0, KEY_QUERY_VALUE
, &hKey
);
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
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
;
409 int nHigh
= SAL_N_ELEMENTS(aLangFromCodeChart
) - 1;
410 while( nLow
<= nHigh
)
412 int nMiddle
= (nHigh
+ nLow
) / 2;
413 if( uChar
< aLangFromCodeChart
[ nMiddle
].mnMinCode
)
415 else if( uChar
> aLangFromCodeChart
[ nMiddle
].mnMaxCode
)
418 return aLangFromCodeChart
[ nMiddle
].mnLangID
;
421 return LANGUAGE_DONTKNOW
;
424 class WinGlyphFallbackSubstititution
425 : public ImplGlyphFallbackFontSubstitution
428 explicit WinGlyphFallbackSubstititution( HDC
);
430 bool FindFontSubstitute( FontSelectPattern
&, OUString
& rMissingChars
) const;
433 bool HasMissingChars( PhysicalFontFace
*, const OUString
& rMissingChars
) const;
436 inline WinGlyphFallbackSubstititution::WinGlyphFallbackSubstititution( HDC 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();
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
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() )
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
);
490 const bool bHasMatches
= (nMatchCount
> 0);
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
)
523 aLanguageTag
.reset( eLang
);
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
);
537 PhysicalFontFace
* pFace
= pFontFamily
->FindBestFontFace( rFontSelData
);
538 if( HasMissingChars( pFace
, rMissingChars
) )
540 rFontSelData
.maSearchName
= pFontFamily
->GetSearchName();
545 // are the missing characters symbols?
546 pFontFamily
= pFontCollection
->ImplFindByAttributes( ImplFontAttrs::Symbol
,
547 rFontSelData
.GetWeight(),
548 rFontSelData
.GetWidthType(),
549 rFontSelData
.GetSlant(),
550 rFontSelData
.maSearchName
);
553 PhysicalFontFace
* pFace
= pFontFamily
->FindBestFontFace( rFontSelData
);
554 if( HasMissingChars( pFace
, rMissingChars
) )
556 rFontSelData
.maSearchName
= pFontFamily
->GetSearchName();
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
;
570 for( int i
= 0; i
< nTestFontCount
; ++i
)
572 PhysicalFontFace
* pFace
= pTestFontList
->Get( i
);
573 bFound
= HasMissingChars( pFace
, rMissingChars
);
576 rFontSelData
.maSearchName
= pFace
->GetFamilyName();
580 delete pTestFontList
;
588 PhysicalFontCollection
* mpList
;
590 LOGFONTA
* mpLogFontA
;
591 LOGFONTW
* mpLogFontW
;
592 UINT mnPreferredCharSet
;
594 bool mbImplSalCourierScalable
;
595 bool mbImplSalCourierNew
;
600 static rtl_TextEncoding
ImplCharSetToSal( BYTE nCharSet
)
602 rtl_TextEncoding eTextEncoding
;
604 if ( nCharSet
== OEM_CHARSET
)
606 UINT nCP
= (sal_uInt16
)GetOEMCP();
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;
614 eTextEncoding
= rtl_getTextEncodingFromWindowsCodePage(nCP
);
621 eTextEncoding
= rtl_getTextEncodingFromWindowsCharset( nCharSet
);
623 eTextEncoding
= RTL_TEXTENCODING_UNICODE
;
626 return eTextEncoding
;
629 static FontFamily
ImplFamilyToSal( BYTE nFamily
)
631 switch ( nFamily
& 0xF0 )
634 return FAMILY_DECORATIVE
;
637 return FAMILY_MODERN
;
643 return FAMILY_SCRIPT
;
652 return FAMILY_DONTKNOW
;
655 static BYTE
ImplFamilyToWin( FontFamily eFamily
)
659 case FAMILY_DECORATIVE
:
660 return FF_DECORATIVE
;
684 static FontWeight
ImplWeightToSal( int nWeight
)
686 if ( nWeight
<= FW_THIN
)
688 else if ( nWeight
<= FW_ULTRALIGHT
)
689 return WEIGHT_ULTRALIGHT
;
690 else if ( nWeight
<= FW_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
)
700 else if ( nWeight
<= FW_ULTRABOLD
)
701 return WEIGHT_ULTRABOLD
;
706 static int ImplWeightToWin( FontWeight eWeight
)
713 case WEIGHT_ULTRALIGHT
:
714 return FW_ULTRALIGHT
;
719 case WEIGHT_SEMILIGHT
:
726 case WEIGHT_SEMIBOLD
:
732 case WEIGHT_ULTRABOLD
:
745 inline FontPitch
ImplLogPitchToSal( BYTE nPitch
)
747 if ( nPitch
& FIXED_PITCH
)
750 return PITCH_VARIABLE
;
753 inline FontPitch
ImplMetricPitchToSal( BYTE nPitch
)
755 // Grrrr! See NT help
756 if ( !(nPitch
& TMPF_FIXED_PITCH
) )
759 return PITCH_VARIABLE
;
762 inline BYTE
ImplPitchToWin( FontPitch ePitch
)
764 if ( ePitch
== PITCH_FIXED
)
766 else if ( ePitch
== PITCH_VARIABLE
)
767 return VARIABLE_PITCH
;
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) )
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
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
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
)
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
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
918 static ImplWinFontData
* ImplLogMetricToDevFontDataA( const ENUMLOGFONTEXA
* pLogFont
,
919 const NEWTEXTMETRICA
* pMetric
,
923 if ( nFontType
& RASTER_FONTTYPE
)
924 nHeight
= pMetric
->tmHeight
- pMetric
->tmInternalLeading
;
926 ImplWinFontData
* pData
= new ImplWinFontData(
927 WinFont2DevFontAttributes(*pLogFont
, *pMetric
, nFontType
),
929 pLogFont
->elfLogFont
.lfCharSet
,
930 pMetric
->tmPitchAndFamily
);
935 static ImplWinFontData
* ImplLogMetricToDevFontDataW( const ENUMLOGFONTEXW
* pLogFont
,
936 const NEWTEXTMETRICW
* pMetric
,
940 if ( nFontType
& RASTER_FONTTYPE
)
941 nHeight
= pMetric
->tmHeight
- pMetric
->tmInternalLeading
;
943 ImplWinFontData
* pData
= new ImplWinFontData(
944 WinFont2DevFontAttributes(*pLogFont
, *pMetric
, nFontType
),
946 pLogFont
->elfLogFont
.lfCharSet
,
947 pMetric
->tmPitchAndFamily
);
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
);
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
);
977 rFont
.SetItalic( ITALIC_NONE
);
978 if ( rLogFont
.lfUnderline
)
979 rFont
.SetUnderline( UNDERLINE_SINGLE
);
981 rFont
.SetUnderline( UNDERLINE_NONE
);
982 if ( rLogFont
.lfStrikeOut
)
983 rFont
.SetStrikeout( STRIKEOUT_SINGLE
);
985 rFont
.SetStrikeout( STRIKEOUT_NONE
);
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
);
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
);
1021 mpFace
= gr_make_face(this, getGrTable
,
1022 gr_face_preloadGlyphs
| gr_face_cacheCmap
);
1024 fprintf(grLog(), "gr_make_face %lx for WinFontData %lx\n", (unsigned long)mpFace
,
1025 (unsigned long)this);
1030 GrFontData::~GrFontData()
1035 fprintf(grLog(), "gr_face_destroy %lx for WinFontData %lx\n", (unsigned long)mpFace
,
1036 (unsigned long)this);
1038 gr_face_destroy(mpFace
);
1041 std::vector
<RawFontData
*>::iterator i
= mvData
.begin();
1042 while (i
!= mvData
.end())
1050 const void * GrFontData::getTable(unsigned int name
, size_t *len
) const
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))
1073 *len
= data
->size();
1074 return reinterpret_cast<const void *>(data
->get());
1085 ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes
& rDFS
,
1086 int nHeight
, BYTE eWinCharSet
, BYTE nPitchAndFamily
)
1087 : PhysicalFontFace( rDFS
, 0 ),
1089 mbHasKoreanRange( false ),
1090 mbHasCJKSupport( false ),
1092 mpGraphiteData(NULL
),
1093 mbHasGraphiteSupport( false ),
1095 mbHasArabicSupport ( false ),
1096 mbFontCapabilitiesRead( false ),
1097 mpUnicodeMap( NULL
),
1098 mpEncodingVector( NULL
),
1099 meWinCharSet( eWinCharSet
),
1100 mnPitchAndFamily( nPitchAndFamily
),
1101 mbAliasSymbolsHigh( false ),
1102 mbAliasSymbolsLow( 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;
1128 fprintf(grLog(), "ImplWinFontData::ImplWinFontData() %lx\n", (unsigned long)this);
1132 ImplWinFontData::~ImplWinFontData()
1138 mpGraphiteData
->DeReference();
1140 fprintf(grLog(), "ImplWinFontData::~ImplWinFontData %lx\n", (unsigned long)this);
1142 #endif // ENABLE_GRAPHITE
1143 delete mpEncodingVector
;
1146 sal_IntPtr
ImplWinFontData::GetFontId() const
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
)
1160 ReadCmapTable( hDC
);
1161 GetFontCapabilities( hDC
);
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
)
1172 fprintf(grLog(), "ImplWinFontData::UpdateFromHDC %lx\n",
1173 (unsigned long)this);
1175 if (mpGraphiteData
== NULL
)
1177 mpGraphiteData
= new GrFontData(hDC
);
1178 if (!mpGraphiteData
->getFace())
1180 mbHasGraphiteSupport
= false;
1181 delete mpGraphiteData
;
1182 mpGraphiteData
= NULL
;
1191 const gr_face
* ImplWinFontData::GraphiteFace() const
1194 fprintf(grLog(), "ImplWinFontData::GraphiteFace %lx has face %lx\n",
1195 (unsigned long)this, mpGraphiteData
? mpGraphiteData
->getFace(): 0);
1197 return (mpGraphiteData
)? mpGraphiteData
->getFace() : NULL
;
1201 bool ImplWinFontData::HasGSUBstitutions( HDC hDC
) const
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
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
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
)
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() )
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
);
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
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
)
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() ) {
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
;
1294 mpUnicodeMap
= FontCharMap::GetDefaultMap( bIsSymbolFont
);
1298 void ImplWinFontData::GetFontCapabilities( HDC hDC
) const
1300 // read this only once per font
1301 if( mbFontCapabilitiesRead
)
1304 mbFontCapabilitiesRead
= true;
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
);
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
) );
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;
1366 void ImplGetLogFontFromFontSelect( HDC hDC
,
1367 const FontSelectPattern
* pFont
,
1369 bool /*bTestVerticalAvail*/ )
1372 if ( pFont
->mpFontData
)
1373 aName
= pFont
->mpFontData
->GetFamilyName();
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() );
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 );
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
)
1443 // only required for virtual devices, see below for details
1444 hdcScreen
= GetDC(0);
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
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
) )
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
);
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
;
1505 ::ReleaseDC( NULL
, hdcScreen
);
1510 sal_uInt16
WinSalGraphics::SetFont( FontSelectPattern
* pFont
, int nFallbackLevel
)
1512 // return early if there is no new font
1515 // deselect still active font
1517 ::SelectFont( getHDC(), mhDefFont
);
1518 mfCurrentFontScale
= mfFontScale
[nFallbackLevel
];
1519 // release no longer referenced font handles
1520 for( int i
= nFallbackLevel
; i
< MAX_FALLBACK
; ++i
)
1523 ::DeleteFont( mhFonts
[i
] );
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
);
1535 HFONT hNewFont
= ImplDoSetFont( pFont
, mfFontScale
[ nFallbackLevel
], hOldFont
);
1536 mfCurrentFontScale
= mfFontScale
[nFallbackLevel
];
1540 // keep default font
1541 mhDefFont
= hOldFont
;
1545 // release no longer referenced font handles
1546 for( int i
= nFallbackLevel
; i
< MAX_FALLBACK
; ++i
)
1550 ::DeleteFont( mhFonts
[i
] );
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
1566 return SAL_SETFONT_USEDRAWTEXTARRAY
;
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
);
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);
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] )
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;
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
;
1694 // ignore non-scalable non-device font on printer
1695 if( pInfo
->mbPrinter
)
1696 if( (nFontType
& RASTER_FONTTYPE
) && !(nFontType
& DEVICE_FONTTYPE
) )
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
);
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;
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
;
1748 // ignore non-scalable non-device font on printer
1749 if( pInfo
->mbPrinter
)
1750 if( (nFontType
& RASTER_FONTTYPE
) && !(nFontType
& DEVICE_FONTTYPE
) )
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
);
1768 OUString maFontFilePath
;
1769 OString maResourcePath
;
1770 TempFontItem
* mpNextItem
;
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" );
1785 pFunc
= reinterpret_cast<AddFontResourceExW_FUNC
>( GetProcAddress( hmGDI
, "AddFontResourceExW" ) );
1789 return pFunc( lpszfileName
, fl
, pdv
);
1792 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1798 bool ImplAddTempFont( SalData
& rSalData
, const OUString
& rFontFileURL
)
1801 OUString aUSytemPath
;
1802 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL
, aUSytemPath
) );
1805 nRet
= __AddFontResourceExW( reinterpret_cast<LPCWSTR
>(aUSytemPath
.getStr()), FR_PRIVATE
, NULL
);
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
) )
1829 nRet
= ::AddFontResourceA( aResourceName
);
1832 TempFontItem
* pNewItem
= new TempFontItem
;
1833 pNewItem
->maResourcePath
= OString( aResourceName
);
1834 pNewItem
->maFontFilePath
= aUSytemPath
.getStr();
1835 pNewItem
->mpNextItem
= rSalData
.mpTempFontItem
;
1836 rSalData
.mpTempFontItem
= pNewItem
;
1843 void ImplReleaseTempFonts( SalData
& rSalData
)
1846 while( TempFontItem
* p
= rSalData
.mpTempFontItem
)
1849 if( p
->maResourcePath
.getLength() )
1851 const char* pResourcePath
= p
->maResourcePath
.getStr();
1852 ::RemoveFontResourceA( pResourcePath
);
1853 ::DeleteFileA( pResourcePath
);
1857 ::RemoveFontResourceW( reinterpret_cast<LPCWSTR
>(p
->maFontFilePath
.getStr()) );
1860 rSalData
.mpTempFontItem
= p
->mpNextItem
;
1865 // notify every other application
1866 // unless the temp fonts were installed as private fonts
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
)
1911 sal_uInt64 nBytesRead
= 0;
1913 aFotFile
.read( aBuffer
, sizeof( aBuffer
), nBytesRead
);
1914 // clean up temporary resource file
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) );
1923 while( (i
< nBytesRead
) && (aBuffer
[i
++] != 0) );
1924 // retrieve font style name
1926 while( (i
< nBytesRead
) && (aBuffer
[i
++] != 0) );
1927 if( i
>= nBytesRead
)
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
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() )
1991 // remember temp font for cleanup later
1992 if( !ImplAddTempFont( *GetSalData(), rFontFileURL
) )
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
);
2022 void WinSalGraphics::GetDevFontList( PhysicalFontCollection
* pFontCollection
)
2024 // make sure all fonts are registered at least temporarily
2025 static bool bOnce
= true;
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
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
);
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
;
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;
2082 aInfo
.mbImplSalCourierScalable
= false;
2083 aInfo
.mbImplSalCourierNew
= false;
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
;
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()
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
)
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
;
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
)
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() );
2152 bool WinSalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId
,
2153 ::basegfx::B2DPolyPolygon
& rB2DPolyPoly
)
2155 rB2DPolyPoly
.clear();
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
2173 else if( nSize1
== GDI_ERROR
)
2176 BYTE
* pData
= new BYTE
[ nSize1
];
2177 const DWORD nSize2
= ::GetGlyphOutlineW( hDC
, aGlyphId
, nGGOFlags
,
2178 &aGlyphMetrics
, nSize1
, pData
, &aMat
);
2180 if( nSize1
!= nSize2
)
2183 // TODO: avoid tools polygon by creating B2DPolygon directly
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
)
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
;
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
);
2234 pPoints
[ nPnt
] = Point( nX
, nY
);
2235 pFlags
[ nPnt
] = POLY_NORMAL
;
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
);
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
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
);
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
;
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];
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() );
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
));
2337 explicit ScopedFont(WinSalGraphics
& rData
);
2342 WinSalGraphics
& m_rData
;
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()
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
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
; }
2376 TrueTypeFont
* m_pFont
;
2379 ScopedTrueTypeFont::~ScopedTrueTypeFont()
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);
2407 ImplDoSetFont( &aIFSD
, fScale
, hOldFont
);
2409 ImplWinFontData
* pWinFontData
= (ImplWinFontData
*)aIFSD
.mpFontData
;
2411 #if OSL_DEBUG_LEVEL > 1
2413 TEXTMETRICA aWinMetric
;
2414 if( !::GetTextMetricsA( getHDC(), &aWinMetric
) )
2417 DBG_ASSERT( !(aWinMetric
.tmPitchAndFamily
& TMPF_DEVICE
), "cannot subset device font" );
2418 DBG_ASSERT( aWinMetric
.tmPitchAndFamily
& TMPF_TRUETYPE
, "can only subset TT font" );
2422 if( osl_File_E_None
!= osl_getSystemPathFromFileURL( rToFile
.pData
, &aSysPath
.pData
) )
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
2446 aRealGlyphIds
[i
] = aGlyphId
;
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
);
2460 // get raw font file data
2461 const RawFontData
xRawFontData( getHDC(), 0 );
2462 if( !xRawFontData
.get() )
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
);
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 ];
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
);
2511 nNotDef
= i
; // first NotDef glyph found
2516 // add fake NotDef glyph if needed
2518 nNotDef
= nGlyphCount
++;
2520 // NotDef glyph must be in pos 0 => swap glyphids
2521 aShortIDs
[ nNotDef
] = aShortIDs
[0];
2522 aTempEncs
[ nNotDef
] = aTempEncs
[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
);
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
;
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() )
2564 // get important font properties
2566 if( !::GetTextMetricsA( getHDC(), &aTm
) )
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 )
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
)
2588 const sal_Unicode cChar
= pUnicodes
[i
];
2589 if( !::GetCharWidth32W( getHDC(), cChar
, cChar
, &nCharWidth
) )
2591 pCharWidths
[i
] = nCharWidth
;
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() )
2612 // fill the encoding vector
2613 // currently no nonencoded vector
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
;
2631 void WinSalGraphics::GetGlyphWidths( const PhysicalFontFace
* pFont
,
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);
2645 ImplDoSetFont( &aIFSD
, fScale
, hOldFont
);
2647 if( pFont
->IsSubsettable() )
2649 // get raw font file data
2650 const RawFontData
xRawFontData( getHDC() );
2651 if( !xRawFontData
.get() )
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
);
2664 int nGlyphs
= GetTTGlyphCount( aSftTTF
.get() );
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(),
2677 for( int i
= 0; i
< nGlyphs
; i
++ )
2678 rWidths
[i
] = pMetrics
[i
].adv
;
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
),
2696 rUnicodeEnc
[ static_cast<sal_Unicode
>(nChar
) ] = nGlyph
;
2698 nChar
= pMap
->GetNextChar( nChar
);
2704 else if( pFont
->IsEmbeddable() )
2706 // get individual character widths
2708 rUnicodeEnc
.clear();
2709 rWidths
.reserve( 224 );
2710 for( sal_Unicode i
= 32; i
< 256; ++i
)
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: */