1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
34 #include <tools/prewin.h>
36 #include <tools/postwin.h>
37 #include <vcl/sysdata.hxx>
38 #include "tools/svwin.h"
40 #include "wincomp.hxx"
41 #include "saldata.hxx"
44 #include "vcl/svapp.hxx"
45 #include "vcl/outfont.hxx"
46 #include "vcl/font.hxx"
47 #include "vcl/fontsubset.hxx"
48 #include "vcl/sallayout.hxx"
50 #include "vcl/outdev.h" // for ImplGlyphFallbackFontSubstitution
51 #include "unotools/fontcfg.hxx" // for IMPL_FONT_ATTR_SYMBOL
53 #include "rtl/logfile.hxx"
54 #include "rtl/tencinfo.h"
55 #include "rtl/textcvt.h"
56 #include "rtl/bootstrap.hxx"
58 #include "i18npool/mslangid.hxx"
60 #include "osl/module.h"
61 #include "osl/file.hxx"
62 #include "osl/thread.hxx"
63 #include "osl/process.h"
65 #include "tools/poly.hxx"
66 #include "tools/debug.hxx"
67 #include "tools/stream.hxx"
69 #include "basegfx/polygon/b2dpolygon.hxx"
70 #include "basegfx/polygon/b2dpolypolygon.hxx"
71 #include "basegfx/matrix/b2dhommatrix.hxx"
72 #include <basegfx/matrix/b2dhommatrixtools.hxx>
80 #ifdef ENABLE_GRAPHITE
81 #include <graphite/GrClient.h>
82 #include <graphite/WinFont.h>
91 static const int MAXFONTHEIGHT
= 2048;
97 inline FIXED
FixedFromDouble( double d
)
99 const long l
= (long) ( d
* 65536. );
103 // -----------------------------------------------------------------------
105 inline int IntTimes256FromFixed(FIXED f
)
107 int nFixedTimes256
= (f
.value
<< 8) + ((f
.fract
+0x80) >> 8);
108 return nFixedTimes256
;
111 // =======================================================================
113 // these variables can be static because they store system wide settings
114 static bool bImplSalCourierScalable
= false;
115 static bool bImplSalCourierNew
= false;
118 // =======================================================================
120 // -----------------------------------------------------------------------
122 // TODO: also support temporary TTC font files
123 typedef std::map
< String
, ImplDevFontAttributes
> FontAttrMap
;
125 class ImplFontAttrCache
128 FontAttrMap aFontAttributes
;
129 rtl::OUString aCacheFileName
;
134 String
OptimizeURL( const String
& rURL
) const;
136 enum{ MAGIC
= 0x12349876 }; // change if fontattrcache format changes
139 ImplFontAttrCache( const String
& rCacheFileName
, const String
& rBaseURL
);
140 ~ImplFontAttrCache();
142 ImplDevFontAttributes
GetFontAttr( const String
& rFontFileName
) const;
143 void AddFontAttr( const String
& rFontFileName
, const ImplDevFontAttributes
& );
146 ImplFontAttrCache::ImplFontAttrCache( const String
& rFileNameURL
, const String
& rBaseURL
) : aBaseURL( rBaseURL
)
149 aBaseURL
.ToLowerAscii(); // Windows only, no problem...
151 // open the cache file
152 osl::FileBase::getSystemPathFromFileURL( rFileNameURL
, aCacheFileName
);
153 SvFileStream
aCacheFile( aCacheFileName
, STREAM_READ
);
154 if( !aCacheFile
.IsOpen() )
157 // check the cache version
158 sal_uInt32 nCacheMagic
;
159 aCacheFile
>> nCacheMagic
;
160 if( nCacheMagic
!= ImplFontAttrCache::MAGIC
)
161 return; // ignore cache and rewrite if no match
163 // read the cache entries from the file
164 String aFontFileURL
, aFontName
;
165 ImplDevFontAttributes aDFA
;
168 aCacheFile
.ReadByteString( aFontFileURL
, RTL_TEXTENCODING_UTF8
);
169 if( !aFontFileURL
.Len() )
171 aCacheFile
.ReadByteString( aDFA
.maName
, RTL_TEXTENCODING_UTF8
);
174 aCacheFile
>> n
; aDFA
.meWeight
= static_cast<FontWeight
>(n
);
175 aCacheFile
>> n
; aDFA
.meItalic
= static_cast<FontItalic
>(n
);
176 aCacheFile
>> n
; aDFA
.mePitch
= static_cast<FontPitch
>(n
);
177 aCacheFile
>> n
; aDFA
.meWidthType
= static_cast<FontWidth
>(n
);
178 aCacheFile
>> n
; aDFA
.meFamily
= static_cast<FontFamily
>(n
);
179 aCacheFile
>> n
; aDFA
.mbSymbolFlag
= (n
!= 0);
181 aCacheFile
.ReadByteStringLine( aDFA
.maStyleName
, RTL_TEXTENCODING_UTF8
);
183 aFontAttributes
[ aFontFileURL
] = aDFA
;
187 ImplFontAttrCache::~ImplFontAttrCache()
191 SvFileStream
aCacheFile( aCacheFileName
, STREAM_WRITE
|STREAM_TRUNC
);
192 if ( aCacheFile
.IsWritable() )
194 sal_uInt32 nCacheMagic
= ImplFontAttrCache::MAGIC
;
195 aCacheFile
<< nCacheMagic
;
197 // write the cache entries to the file
198 FontAttrMap::const_iterator aIter
= aFontAttributes
.begin();
199 while ( aIter
!= aFontAttributes
.end() )
201 const String
rFontFileURL( (*aIter
).first
);
202 const ImplDevFontAttributes
& rDFA( (*aIter
).second
);
203 aCacheFile
.WriteByteString( rFontFileURL
, RTL_TEXTENCODING_UTF8
);
204 aCacheFile
.WriteByteString( rDFA
.maName
, RTL_TEXTENCODING_UTF8
);
206 aCacheFile
<< static_cast<short>(rDFA
.meWeight
);
207 aCacheFile
<< static_cast<short>(rDFA
.meItalic
);
208 aCacheFile
<< static_cast<short>(rDFA
.mePitch
);
209 aCacheFile
<< static_cast<short>(rDFA
.meWidthType
);
210 aCacheFile
<< static_cast<short>(rDFA
.meFamily
);
211 aCacheFile
<< static_cast<short>(rDFA
.mbSymbolFlag
!= false);
213 aCacheFile
.WriteByteStringLine( rDFA
.maStyleName
, RTL_TEXTENCODING_UTF8
);
219 aCacheFile
.WriteByteString( aEmptyStr
, RTL_TEXTENCODING_UTF8
);
224 String
ImplFontAttrCache::OptimizeURL( const String
& rURL
) const
226 String
aOptimizedFontFileURL( rURL
);
227 aOptimizedFontFileURL
.ToLowerAscii(); // Windows only, no problem...
228 if ( aOptimizedFontFileURL
.CompareTo( aBaseURL
, aBaseURL
.Len() ) == COMPARE_EQUAL
)
229 aOptimizedFontFileURL
= aOptimizedFontFileURL
.Copy( aBaseURL
.Len() );
230 return aOptimizedFontFileURL
;
233 ImplDevFontAttributes
ImplFontAttrCache::GetFontAttr( const String
& rFontFileName
) const
235 ImplDevFontAttributes aDFA
;
236 FontAttrMap::const_iterator it
= aFontAttributes
.find( OptimizeURL( rFontFileName
) );
237 if( it
!= aFontAttributes
.end() )
244 void ImplFontAttrCache::AddFontAttr( const String
& rFontFileName
, const ImplDevFontAttributes
& rDFA
)
246 DBG_ASSERT( rFontFileName
.Len() && rDFA
.maName
.Len(), "ImplFontNameCache::AddFontName - invalid data!" );
247 if ( rFontFileName
.Len() && rDFA
.maName
.Len() )
249 aFontAttributes
.insert( FontAttrMap::value_type( OptimizeURL( rFontFileName
), rDFA
) );
254 // =======================================================================
256 // raw font data with a scoped lifetime
260 explicit RawFontData( HDC
, DWORD nTableTag
=0 );
261 ~RawFontData() { delete[] mpRawBytes
; }
262 const unsigned char* get() const { return mpRawBytes
; }
263 const unsigned char* steal() { unsigned char* p
= mpRawBytes
; mpRawBytes
= NULL
; return p
; }
264 const int size() const { return mnByteCount
; }
267 unsigned char* mpRawBytes
;
271 RawFontData::RawFontData( HDC hDC
, DWORD nTableTag
)
275 // get required size in bytes
276 mnByteCount
= ::GetFontData( hDC
, nTableTag
, 0, NULL
, 0 );
277 if( mnByteCount
== GDI_ERROR
)
279 else if( !mnByteCount
)
282 // allocate the array
283 mpRawBytes
= new unsigned char[ mnByteCount
];
285 // get raw data in chunks small enough for GetFontData()
287 DWORD nMaxChunkSize
= 0x100000;
290 // calculate remaining raw data to get
291 DWORD nFDGet
= mnByteCount
- nRawDataOfs
;
294 // #i56745# limit GetFontData requests
295 if( nFDGet
> nMaxChunkSize
)
296 nFDGet
= nMaxChunkSize
;
297 const DWORD nFDGot
= ::GetFontData( hDC
, nTableTag
, nRawDataOfs
,
298 (void*)(mpRawBytes
+ nRawDataOfs
), nFDGet
);
301 else if( nFDGot
!= GDI_ERROR
)
302 nRawDataOfs
+= nFDGot
;
305 // was the chunk too big? reduce it
307 if( nMaxChunkSize
< 0x10000 )
312 // cleanup if the raw data is incomplete
313 if( nRawDataOfs
!= mnByteCount
)
320 // ===========================================================================
321 // platform specific font substitution hooks for glyph fallback enhancement
322 // TODO: move into i18n module (maybe merge with svx/ucsubset.*
323 // or merge with i18nutil/source/utility/unicode_data.h)
324 struct Unicode2LangType
328 LanguageType mnLangID
;
331 // entries marked with default-CJK get replaced with the default-CJK language
332 #define LANGUAGE_DEFAULT_CJK 0xFFF0
334 // map unicode ranges to languages supported by OOo
335 // NOTE: due to the binary search used this list must be sorted by mnMinCode
336 static Unicode2LangType aLangFromCodeChart
[]= {
337 {0x0000, 0x007F, LANGUAGE_ENGLISH
}, // Basic Latin
338 {0x0080, 0x024F, LANGUAGE_ENGLISH
}, // Latin Extended-A and Latin Extended-B
339 {0x0250, 0x02AF, LANGUAGE_SYSTEM
}, // IPA Extensions
340 {0x0370, 0x03FF, LANGUAGE_GREEK
}, // Greek
341 {0x0590, 0x05FF, LANGUAGE_HEBREW
}, // Hebrew
342 {0x0600, 0x06FF, LANGUAGE_ARABIC_PRIMARY_ONLY
}, // Arabic
343 {0x0900, 0x097F, LANGUAGE_HINDI
}, // Devanagari
344 {0x0980, 0x09FF, LANGUAGE_BENGALI
}, // Bengali
345 {0x0A80, 0x0AFF, LANGUAGE_GUJARATI
}, // Gujarati
346 {0x0B00, 0x0B7F, LANGUAGE_ORIYA
}, // Oriya
347 {0x0B80, 0x0BFF, LANGUAGE_TAMIL
}, // Tamil
348 {0x0C00, 0x0C7F, LANGUAGE_TELUGU
}, // Telugu
349 {0x0C80, 0x0CFF, LANGUAGE_KANNADA
}, // Kannada
350 {0x0D00, 0x0D7F, LANGUAGE_MALAYALAM
}, // Malayalam
351 {0x0D80, 0x0D7F, LANGUAGE_SINHALESE_SRI_LANKA
}, // Sinhala
352 {0x0E00, 0x0E7F, LANGUAGE_THAI
}, // Thai
353 {0x0E80, 0x0EFF, LANGUAGE_LAO
}, // Lao
354 {0x0F00, 0x0FFF, LANGUAGE_TIBETAN
}, // Tibetan
355 {0x1000, 0x109F, LANGUAGE_BURMESE
}, // Burmese
356 {0x10A0, 0x10FF, LANGUAGE_GEORGIAN
}, // Georgian
357 {0x1100, 0x11FF, LANGUAGE_KOREAN
}, // Hangul Jamo, Korean-specific
358 // {0x1200, 0x139F, LANGUAGE_AMHARIC_ETHIOPIA}, // Ethiopic
359 // {0x1200, 0x139F, LANGUAGE_TIGRIGNA_ETHIOPIA}, // Ethiopic
360 {0x13A0, 0x13FF, LANGUAGE_CHEROKEE_UNITED_STATES
}, // Cherokee
361 // {0x1400, 0x167F, LANGUAGE_CANADIAN_ABORIGINAL}, // Canadian Aboriginial Syllabics
362 // {0x1680, 0x169F, LANGUAGE_OGHAM}, // Ogham
363 // {0x16A0, 0x16F0, LANGUAGE_RUNIC}, // Runic
364 // {0x1700, 0x171F, LANGUAGE_TAGALOG}, // Tagalog
365 // {0x1720, 0x173F, LANGUAGE_HANUNOO}, // Hanunoo
366 // {0x1740, 0x175F, LANGUAGE_BUHID}, // Buhid
367 // {0x1760, 0x177F, LANGUAGE_TAGBANWA}, // Tagbanwa
368 {0x1780, 0x17FF, LANGUAGE_KHMER
}, // Khmer
369 {0x18A0, 0x18AF, LANGUAGE_MONGOLIAN
}, // Mongolian
370 // {0x1900, 0x194F, LANGUAGE_LIMBU}, // Limbu
371 // {0x1950, 0x197F, LANGUAGE_TAILE}, // Tai Le
372 // {0x1980, 0x19DF, LANGUAGE_TAILUE}, // Tai Lue
373 {0x19E0, 0x19FF, LANGUAGE_KHMER
}, // Khmer Symbols
374 // {0x1A00, 0x1A1F, LANGUAGE_BUGINESE}, // Buginese/Lontara
375 // {0x1B00, 0x1B7F, LANGUAGE_BALINESE}, // Balinese
376 // {0x1D00, 0x1DFF, LANGUAGE_NONE}, // Phonetic Symbols
377 {0x1E00, 0x1EFF, LANGUAGE_ENGLISH
}, // Latin Extended Additional
378 {0x1F00, 0x1FFF, LANGUAGE_GREEK
}, // Greek Extended
379 {0x2C60, 0x2C7F, LANGUAGE_ENGLISH
}, // Latin Extended-C
380 {0x2E80, 0x2FFf, LANGUAGE_CHINESE_SIMPLIFIED
}, // CJK Radicals Supplement + Kangxi Radical + Ideographic Description Characters
381 {0x3000, 0x303F, LANGUAGE_DEFAULT_CJK
}, // CJK Symbols and punctuation
382 {0x3040, 0x30FF, LANGUAGE_JAPANESE
}, // Japanese Hiragana + Katakana
383 {0x3100, 0x312F, LANGUAGE_CHINESE_TRADITIONAL
}, // Bopomofo
384 {0x3130, 0x318F, LANGUAGE_KOREAN
}, // Hangul Compatibility Jamo, Kocrean-specific
385 {0x3190, 0x319F, LANGUAGE_JAPANESE
}, // Kanbun
386 {0x31A0, 0x31BF, LANGUAGE_CHINESE_TRADITIONAL
}, // Bopomofo Extended
387 {0x31C0, 0x31EF, LANGUAGE_DEFAULT_CJK
}, // CJK Ideographs
388 {0x31F0, 0x31FF, LANGUAGE_JAPANESE
}, // Japanese Katakana Phonetic Extensions
389 {0x3200, 0x321F, LANGUAGE_KOREAN
}, // Parenthesized Hangul
390 {0x3220, 0x325F, LANGUAGE_DEFAULT_CJK
}, // Parenthesized Ideographs
391 {0x3260, 0x327F, LANGUAGE_KOREAN
}, // Circled Hangul
392 {0x3280, 0x32CF, LANGUAGE_DEFAULT_CJK
}, // Circled Ideographs
393 {0x32d0, 0x32FF, LANGUAGE_JAPANESE
}, // Japanese Circled Katakana
394 {0x3400, 0x4DBF, LANGUAGE_DEFAULT_CJK
}, // CJK Unified Ideographs Extension A
395 {0x4E00, 0x9FCF, LANGUAGE_DEFAULT_CJK
}, // Unified CJK Ideographs
396 {0xA720, 0xA7FF, LANGUAGE_ENGLISH
}, // Latin Extended-D
397 {0xAC00, 0xD7AF, LANGUAGE_KOREAN
}, // Hangul Syllables, Korean-specific
398 {0xF900, 0xFAFF, LANGUAGE_DEFAULT_CJK
}, // CJK Compatibility Ideographs
399 {0xFB00, 0xFB4F, LANGUAGE_HEBREW
}, // Hebrew Presentation Forms
400 {0xFB50, 0xFDFF, LANGUAGE_ARABIC_PRIMARY_ONLY
}, // Arabic Presentation Forms-A
401 {0xFE70, 0xFEFE, LANGUAGE_ARABIC_PRIMARY_ONLY
}, // Arabic Presentation Forms-B
402 {0xFF65, 0xFF9F, LANGUAGE_JAPANESE
}, // Japanese Halfwidth Katakana variant
403 {0xFFA0, 0xFFDC, LANGUAGE_KOREAN
}, // Kocrean halfwidth hangual variant
404 {0x10140, 0x1018F, LANGUAGE_GREEK
}, // Ancient Greak numbers
405 {0x1D200, 0x1D24F, LANGUAGE_GREEK
}, // Ancient Greek Musical
406 {0x20000, 0x2A6DF, LANGUAGE_DEFAULT_CJK
}, // CJK Unified Ideographs Extension B
407 {0x2F800, 0x2FA1F, LANGUAGE_DEFAULT_CJK
} // CJK Compatibility Ideographs Supplement
410 // get language matching to the missing char
411 LanguageType
MapCharToLanguage( sal_UCS4 uChar
)
413 // entries marked with default-CJK get replaced with the prefered CJK language
414 static bool bFirst
= true;
419 // use method suggested in #i97086# to determnine the systems default language
420 // TODO: move into i18npool or sal/osl/w32/nlsupport.c
421 LanguageType nDefaultLang
= 0;
423 LONG lResult
= ::RegOpenKeyExA( HKEY_LOCAL_MACHINE
,
424 "SYSTEM\\CurrentControlSet\\Control\\Nls\\Language",
425 0, KEY_QUERY_VALUE
, &hKey
);
427 DWORD nKeyValSize
= sizeof(aKeyValBuf
);
428 if( ERROR_SUCCESS
== lResult
)
429 lResult
= RegQueryValueExA( hKey
, "Default", NULL
, NULL
, (LPBYTE
)aKeyValBuf
, &nKeyValSize
);
430 aKeyValBuf
[ sizeof(aKeyValBuf
)-1 ] = '\0';
431 if( ERROR_SUCCESS
== lResult
)
432 nDefaultLang
= (LanguageType
)rtl_str_toInt32( aKeyValBuf
, 16 );
434 // TODO: use the default-CJK language selected in
435 // Tools->Options->LangSettings->Languages when it becomes available here
437 nDefaultLang
= Application::GetSettings().GetUILanguage();
439 LanguageType nDefaultCJK
= LANGUAGE_CHINESE
;
440 switch( nDefaultLang
)
442 case LANGUAGE_JAPANESE
:
443 case LANGUAGE_KOREAN
:
444 case LANGUAGE_KOREAN_JOHAB
:
445 case LANGUAGE_CHINESE_SIMPLIFIED
:
446 case LANGUAGE_CHINESE_TRADITIONAL
:
447 case LANGUAGE_CHINESE_SINGAPORE
:
448 case LANGUAGE_CHINESE_HONGKONG
:
449 case LANGUAGE_CHINESE_MACAU
:
450 nDefaultCJK
= nDefaultLang
;
453 nDefaultCJK
= LANGUAGE_CHINESE
;
457 // change the marked entries to prefered language
458 static const int nCount
= (sizeof(aLangFromCodeChart
) / sizeof(*aLangFromCodeChart
));
459 for( int i
= 0; i
< nCount
; ++i
)
461 if( aLangFromCodeChart
[ i
].mnLangID
== LANGUAGE_DEFAULT_CJK
)
462 aLangFromCodeChart
[ i
].mnLangID
= nDefaultCJK
;
468 int nHigh
= (sizeof(aLangFromCodeChart
) / sizeof(*aLangFromCodeChart
)) - 1;
469 while( nLow
<= nHigh
)
471 int nMiddle
= (nHigh
+ nLow
) / 2;
472 if( uChar
< aLangFromCodeChart
[ nMiddle
].mnMinCode
)
474 else if( uChar
> aLangFromCodeChart
[ nMiddle
].mnMaxCode
)
477 return aLangFromCodeChart
[ nMiddle
].mnLangID
;
480 return LANGUAGE_DONTKNOW
;
483 class WinGlyphFallbackSubstititution
484 : public ImplGlyphFallbackFontSubstitution
487 explicit WinGlyphFallbackSubstititution( HDC
);
489 bool FindFontSubstitute( ImplFontSelectData
&, rtl::OUString
& rMissingChars
) const;
492 bool HasMissingChars( const ImplFontData
*, const rtl::OUString
& rMissingChars
) const;
495 inline WinGlyphFallbackSubstititution::WinGlyphFallbackSubstititution( HDC hDC
)
499 void ImplGetLogFontFromFontSelect( HDC
, const ImplFontSelectData
*,
500 LOGFONTW
&, bool /*bTestVerticalAvail*/ );
502 // does a font face hold the given missing characters?
503 bool WinGlyphFallbackSubstititution::HasMissingChars( const ImplFontData
* pFace
, const rtl::OUString
& rMissingChars
) const
505 const ImplWinFontData
* pWinFont
= static_cast<const ImplWinFontData
*>(pFace
);
506 const ImplFontCharMap
* pCharMap
= pWinFont
->GetImplFontCharMap();
509 // construct a Size structure as the parameter of constructor of class ImplFontSelectData
510 const Size
aSize( pFace
->GetWidth(), pFace
->GetHeight() );
511 // create a ImplFontSelectData object for getting s LOGFONT
512 const ImplFontSelectData
aFSD( *pFace
, aSize
, (float)aSize
.Height(), 0, false );
513 // construct log font
515 ImplGetLogFontFromFontSelect( mhDC
, &aFSD
, aLogFont
, true );
517 // create HFONT from log font
518 HFONT hNewFont
= ::CreateFontIndirectW( &aLogFont
);
519 // select the new font into device
520 HFONT hOldFont
= ::SelectFont( mhDC
, hNewFont
);
522 // read CMAP table to update their pCharMap
523 pWinFont
->UpdateFromHDC( mhDC
);;
525 // cleanup temporary font
526 ::SelectFont( mhDC
, hOldFont
);
527 ::DeleteFont( hNewFont
);
529 // get the new charmap
530 pCharMap
= pWinFont
->GetImplFontCharMap();
533 // avoid fonts with unknown CMAP subtables for glyph fallback
534 if( !pCharMap
|| pCharMap
->IsDefaultMap() )
536 pCharMap
->AddReference();
539 // static const int nMaxMatchCount = 1; // TODO: tolerate more missing characters?
540 const sal_Int32 nStrLen
= rMissingChars
.getLength();
541 for( sal_Int32 nStrIdx
= 0; nStrIdx
< nStrLen
; ++nStrIdx
)
543 const sal_UCS4 uChar
= rMissingChars
.iterateCodePoints( &nStrIdx
);
544 nMatchCount
+= pCharMap
->HasChar( uChar
);
547 pCharMap
->DeReference();
549 const bool bHasMatches
= (nMatchCount
> 0);
553 // find a fallback font for missing characters
554 // TODO: should stylistic matches be searched and prefered?
555 bool WinGlyphFallbackSubstititution::FindFontSubstitute( ImplFontSelectData
& rFontSelData
, rtl::OUString
& rMissingChars
) const
557 // guess a locale matching to the missing chars
558 com::sun::star::lang::Locale aLocale
;
560 sal_Int32 nStrIdx
= 0;
561 const sal_Int32 nStrLen
= rMissingChars
.getLength();
562 while( nStrIdx
< nStrLen
)
564 const sal_UCS4 uChar
= rMissingChars
.iterateCodePoints( &nStrIdx
);
565 const LanguageType eLang
= MapCharToLanguage( uChar
);
566 if( eLang
== LANGUAGE_DONTKNOW
)
568 MsLangId::convertLanguageToLocale( eLang
, aLocale
);
572 // fall back to default UI locale if the missing characters are inconclusive
573 if( nStrIdx
>= nStrLen
)
574 aLocale
= Application::GetSettings().GetUILocale();
576 // first level fallback:
577 // try use the locale specific default fonts defined in VCL.xcu
578 const ImplDevFontList
* pDevFontList
= ImplGetSVData()->maGDIData
.mpScreenFontList
;
579 /*const*/ ImplDevFontListData
* pDevFont
= pDevFontList
->ImplFindByLocale( aLocale
);
582 const ImplFontData
* pFace
= pDevFont
->FindBestFontFace( rFontSelData
);
583 if( HasMissingChars( pFace
, rMissingChars
) )
585 rFontSelData
.maSearchName
= pDevFont
->GetSearchName();
590 // are the missing characters symbols?
591 pDevFont
= pDevFontList
->ImplFindByAttributes( IMPL_FONT_ATTR_SYMBOL
,
592 rFontSelData
.meWeight
, rFontSelData
.meWidthType
,
593 rFontSelData
.meFamily
, rFontSelData
.meItalic
, rFontSelData
.maSearchName
);
596 const ImplFontData
* pFace
= pDevFont
->FindBestFontFace( rFontSelData
);
597 if( HasMissingChars( pFace
, rMissingChars
) )
599 rFontSelData
.maSearchName
= pDevFont
->GetSearchName();
604 // last level fallback, check each font type face one by one
605 const ImplGetDevFontList
* pTestFontList
= pDevFontList
->GetDevFontList();
606 // limit the count of fonts to be checked to prevent hangs
607 static const int MAX_GFBFONT_COUNT
= 600;
608 int nTestFontCount
= pTestFontList
->Count();
609 if( nTestFontCount
> MAX_GFBFONT_COUNT
)
610 nTestFontCount
= MAX_GFBFONT_COUNT
;
612 for( int i
= 0; i
< nTestFontCount
; ++i
)
614 const ImplFontData
* pFace
= pTestFontList
->Get( i
);
615 if( !HasMissingChars( pFace
, rMissingChars
) )
617 rFontSelData
.maSearchName
= pFace
->maName
;
624 // =======================================================================
629 ImplDevFontList
* mpList
;
631 LOGFONTA
* mpLogFontA
;
632 LOGFONTW
* mpLogFontW
;
633 UINT mnPreferedCharSet
;
635 bool mbImplSalCourierScalable
;
636 bool mbImplSalCourierNew
;
641 // =======================================================================
643 static CharSet
ImplCharSetToSal( BYTE nCharSet
)
645 rtl_TextEncoding eTextEncoding
;
647 if ( nCharSet
== OEM_CHARSET
)
649 UINT nCP
= (sal_uInt16
)GetOEMCP();
652 // It is unclear why these two (undefined?) code page numbers are
653 // handled specially here:
654 case 1004: eTextEncoding
= RTL_TEXTENCODING_MS_1252
; break;
655 case 65400: eTextEncoding
= RTL_TEXTENCODING_SYMBOL
; break;
657 eTextEncoding
= rtl_getTextEncodingFromWindowsCodePage(nCP
);
664 eTextEncoding
= rtl_getTextEncodingFromWindowsCharset( nCharSet
);
666 eTextEncoding
= RTL_TEXTENCODING_UNICODE
;
669 return eTextEncoding
;
672 // -----------------------------------------------------------------------
674 static FontFamily
ImplFamilyToSal( BYTE nFamily
)
676 switch ( nFamily
& 0xF0 )
679 return FAMILY_DECORATIVE
;
682 return FAMILY_MODERN
;
688 return FAMILY_SCRIPT
;
697 return FAMILY_DONTKNOW
;
700 // -----------------------------------------------------------------------
702 static BYTE
ImplFamilyToWin( FontFamily eFamily
)
706 case FAMILY_DECORATIVE
:
707 return FF_DECORATIVE
;
731 // -----------------------------------------------------------------------
733 static FontWeight
ImplWeightToSal( int nWeight
)
735 if ( nWeight
<= FW_THIN
)
737 else if ( nWeight
<= FW_ULTRALIGHT
)
738 return WEIGHT_ULTRALIGHT
;
739 else if ( nWeight
<= FW_LIGHT
)
741 else if ( nWeight
< FW_MEDIUM
)
742 return WEIGHT_NORMAL
;
743 else if ( nWeight
== FW_MEDIUM
)
744 return WEIGHT_MEDIUM
;
745 else if ( nWeight
<= FW_SEMIBOLD
)
746 return WEIGHT_SEMIBOLD
;
747 else if ( nWeight
<= FW_BOLD
)
749 else if ( nWeight
<= FW_ULTRABOLD
)
750 return WEIGHT_ULTRABOLD
;
755 // -----------------------------------------------------------------------
757 static int ImplWeightToWin( FontWeight eWeight
)
764 case WEIGHT_ULTRALIGHT
:
765 return FW_ULTRALIGHT
;
770 case WEIGHT_SEMILIGHT
:
777 case WEIGHT_SEMIBOLD
:
783 case WEIGHT_ULTRABOLD
:
796 // -----------------------------------------------------------------------
798 inline FontPitch
ImplLogPitchToSal( BYTE nPitch
)
800 if ( nPitch
& FIXED_PITCH
)
803 return PITCH_VARIABLE
;
806 // -----------------------------------------------------------------------
808 inline FontPitch
ImplMetricPitchToSal( BYTE nPitch
)
810 // Sausaecke bei MS !! siehe NT Hilfe
811 if ( !(nPitch
& TMPF_FIXED_PITCH
) )
814 return PITCH_VARIABLE
;
817 // -----------------------------------------------------------------------
819 inline BYTE
ImplPitchToWin( FontPitch ePitch
)
821 if ( ePitch
== PITCH_FIXED
)
823 else if ( ePitch
== PITCH_VARIABLE
)
824 return VARIABLE_PITCH
;
826 return DEFAULT_PITCH
;
829 // -----------------------------------------------------------------------
831 static ImplDevFontAttributes
WinFont2DevFontAttributes( const ENUMLOGFONTEXA
& rEnumFont
,
832 const NEWTEXTMETRICA
& rMetric
, DWORD nFontType
)
834 ImplDevFontAttributes aDFA
;
836 const LOGFONTA rLogFont
= rEnumFont
.elfLogFont
;
838 // get font face attributes
839 aDFA
.meFamily
= ImplFamilyToSal( rLogFont
.lfPitchAndFamily
);
840 aDFA
.meWidthType
= WIDTH_DONTKNOW
;
841 aDFA
.meWeight
= ImplWeightToSal( rLogFont
.lfWeight
);
842 aDFA
.meItalic
= (rLogFont
.lfItalic
) ? ITALIC_NORMAL
: ITALIC_NONE
;
843 aDFA
.mePitch
= ImplLogPitchToSal( rLogFont
.lfPitchAndFamily
);
844 aDFA
.mbSymbolFlag
= (rLogFont
.lfCharSet
== SYMBOL_CHARSET
);
846 // get the font face name
847 aDFA
.maName
= ImplSalGetUniString( rLogFont
.lfFaceName
);
849 // use the face's style name only if it looks reasonable
850 const char* pStyleName
= (const char*)rEnumFont
.elfStyle
;
851 const char* pEnd
= pStyleName
+ sizeof( rEnumFont
.elfStyle
);
852 const char* p
= pStyleName
;
853 for(; *p
&& (p
< pEnd
); ++p
)
854 if( (0x00 < *p
) && (*p
< 0x20) )
857 aDFA
.maStyleName
= ImplSalGetUniString( pStyleName
);
859 // get device specific font attributes
860 aDFA
.mbOrientation
= (nFontType
& RASTER_FONTTYPE
) == 0;
861 aDFA
.mbDevice
= (rMetric
.tmPitchAndFamily
& TMPF_DEVICE
) != 0;
863 aDFA
.mbEmbeddable
= false;
864 aDFA
.mbSubsettable
= false;
865 if( 0 != (rMetric
.ntmFlags
& (NTM_TT_OPENTYPE
| NTM_PS_OPENTYPE
))
866 || 0 != (rMetric
.tmPitchAndFamily
& TMPF_TRUETYPE
))
867 aDFA
.mbSubsettable
= true;
868 else if( 0 != (rMetric
.ntmFlags
& NTM_TYPE1
) ) // TODO: implement subsetting for type1 too
869 aDFA
.mbEmbeddable
= true;
871 // heuristics for font quality
872 // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
873 // - subsetting > embedding > none
875 if( rMetric
.tmPitchAndFamily
& TMPF_TRUETYPE
)
876 aDFA
.mnQuality
+= 50;
877 if( 0 != (rMetric
.ntmFlags
& (NTM_TT_OPENTYPE
| NTM_PS_OPENTYPE
)) )
878 aDFA
.mnQuality
+= 10;
879 if( aDFA
.mbSubsettable
)
880 aDFA
.mnQuality
+= 200;
881 else if( aDFA
.mbEmbeddable
)
882 aDFA
.mnQuality
+= 100;
884 // #i38665# prefer Type1 versions of the standard postscript fonts
885 if( aDFA
.mbEmbeddable
)
887 if( aDFA
.maName
.EqualsAscii( "AvantGarde" )
888 || aDFA
.maName
.EqualsAscii( "Bookman" )
889 || aDFA
.maName
.EqualsAscii( "Courier" )
890 || aDFA
.maName
.EqualsAscii( "Helvetica" )
891 || aDFA
.maName
.EqualsAscii( "NewCenturySchlbk" )
892 || aDFA
.maName
.EqualsAscii( "Palatino" )
893 || aDFA
.maName
.EqualsAscii( "Symbol" )
894 || aDFA
.maName
.EqualsAscii( "Times" )
895 || aDFA
.maName
.EqualsAscii( "ZapfChancery" )
896 || aDFA
.maName
.EqualsAscii( "ZapfDingbats" ) )
897 aDFA
.mnQuality
+= 500;
900 // TODO: add alias names
904 // -----------------------------------------------------------------------
906 static ImplDevFontAttributes
WinFont2DevFontAttributes( const ENUMLOGFONTEXW
& rEnumFont
,
907 const NEWTEXTMETRICW
& rMetric
, DWORD nFontType
)
909 ImplDevFontAttributes aDFA
;
911 const LOGFONTW rLogFont
= rEnumFont
.elfLogFont
;
913 // get font face attributes
914 aDFA
.meFamily
= ImplFamilyToSal( rLogFont
.lfPitchAndFamily
);
915 aDFA
.meWidthType
= WIDTH_DONTKNOW
;
916 aDFA
.meWeight
= ImplWeightToSal( rLogFont
.lfWeight
);
917 aDFA
.meItalic
= (rLogFont
.lfItalic
) ? ITALIC_NORMAL
: ITALIC_NONE
;
918 aDFA
.mePitch
= ImplLogPitchToSal( rLogFont
.lfPitchAndFamily
);
919 aDFA
.mbSymbolFlag
= (rLogFont
.lfCharSet
== SYMBOL_CHARSET
);
921 // get the font face name
922 aDFA
.maName
= reinterpret_cast<const sal_Unicode
*>(rLogFont
.lfFaceName
);
924 // use the face's style name only if it looks reasonable
925 const wchar_t* pStyleName
= rEnumFont
.elfStyle
;
926 const wchar_t* pEnd
= pStyleName
+ sizeof(rEnumFont
.elfStyle
)/sizeof(*rEnumFont
.elfStyle
);
927 const wchar_t* p
= pStyleName
;
928 for(; *p
&& (p
< pEnd
); ++p
)
932 aDFA
.maStyleName
= reinterpret_cast<const sal_Unicode
*>(pStyleName
);
934 // get device specific font attributes
935 aDFA
.mbOrientation
= (nFontType
& RASTER_FONTTYPE
) == 0;
936 aDFA
.mbDevice
= (rMetric
.tmPitchAndFamily
& TMPF_DEVICE
) != 0;
938 aDFA
.mbEmbeddable
= false;
939 aDFA
.mbSubsettable
= false;
940 if( 0 != (rMetric
.ntmFlags
& (NTM_TT_OPENTYPE
| NTM_PS_OPENTYPE
))
941 || 0 != (rMetric
.tmPitchAndFamily
& TMPF_TRUETYPE
))
942 aDFA
.mbSubsettable
= true;
943 else if( 0 != (rMetric
.ntmFlags
& NTM_TYPE1
) ) // TODO: implement subsetting for type1 too
944 aDFA
.mbEmbeddable
= true;
946 // heuristics for font quality
947 // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
948 // - subsetting > embedding > none
950 if( rMetric
.tmPitchAndFamily
& TMPF_TRUETYPE
)
951 aDFA
.mnQuality
+= 50;
952 if( 0 != (rMetric
.ntmFlags
& (NTM_TT_OPENTYPE
| NTM_PS_OPENTYPE
)) )
953 aDFA
.mnQuality
+= 10;
954 if( aDFA
.mbSubsettable
)
955 aDFA
.mnQuality
+= 200;
956 else if( aDFA
.mbEmbeddable
)
957 aDFA
.mnQuality
+= 100;
959 // #i38665# prefer Type1 versions of the standard postscript fonts
960 if( aDFA
.mbEmbeddable
)
962 if( aDFA
.maName
.EqualsAscii( "AvantGarde" )
963 || aDFA
.maName
.EqualsAscii( "Bookman" )
964 || aDFA
.maName
.EqualsAscii( "Courier" )
965 || aDFA
.maName
.EqualsAscii( "Helvetica" )
966 || aDFA
.maName
.EqualsAscii( "NewCenturySchlbk" )
967 || aDFA
.maName
.EqualsAscii( "Palatino" )
968 || aDFA
.maName
.EqualsAscii( "Symbol" )
969 || aDFA
.maName
.EqualsAscii( "Times" )
970 || aDFA
.maName
.EqualsAscii( "ZapfChancery" )
971 || aDFA
.maName
.EqualsAscii( "ZapfDingbats" ) )
972 aDFA
.mnQuality
+= 500;
975 // TODO: add alias names
979 // -----------------------------------------------------------------------
981 static ImplWinFontData
* ImplLogMetricToDevFontDataA( const ENUMLOGFONTEXA
* pLogFont
,
982 const NEWTEXTMETRICA
* pMetric
,
986 if ( nFontType
& RASTER_FONTTYPE
)
987 nHeight
= pMetric
->tmHeight
- pMetric
->tmInternalLeading
;
989 ImplWinFontData
* pData
= new ImplWinFontData(
990 WinFont2DevFontAttributes(*pLogFont
, *pMetric
, nFontType
),
992 pLogFont
->elfLogFont
.lfCharSet
,
993 pMetric
->tmPitchAndFamily
);
998 // -----------------------------------------------------------------------
1000 static ImplWinFontData
* ImplLogMetricToDevFontDataW( const ENUMLOGFONTEXW
* pLogFont
,
1001 const NEWTEXTMETRICW
* pMetric
,
1005 if ( nFontType
& RASTER_FONTTYPE
)
1006 nHeight
= pMetric
->tmHeight
- pMetric
->tmInternalLeading
;
1008 ImplWinFontData
* pData
= new ImplWinFontData(
1009 WinFont2DevFontAttributes(*pLogFont
, *pMetric
, nFontType
),
1011 pLogFont
->elfLogFont
.lfCharSet
,
1012 pMetric
->tmPitchAndFamily
);
1017 // -----------------------------------------------------------------------
1019 void ImplSalLogFontToFontA( HDC hDC
, const LOGFONTA
& rLogFont
, Font
& rFont
)
1021 String
aFontName( ImplSalGetUniString( rLogFont
.lfFaceName
) );
1022 if ( aFontName
.Len() )
1024 rFont
.SetName( aFontName
);
1025 rFont
.SetCharSet( ImplCharSetToSal( rLogFont
.lfCharSet
) );
1026 rFont
.SetFamily( ImplFamilyToSal( rLogFont
.lfPitchAndFamily
) );
1027 rFont
.SetPitch( ImplLogPitchToSal( rLogFont
.lfPitchAndFamily
) );
1028 rFont
.SetWeight( ImplWeightToSal( rLogFont
.lfWeight
) );
1030 long nFontHeight
= rLogFont
.lfHeight
;
1031 if ( nFontHeight
< 0 )
1032 nFontHeight
= -nFontHeight
;
1033 long nDPIY
= GetDeviceCaps( hDC
, LOGPIXELSY
);
1037 nFontHeight
+= nDPIY
/2;
1038 nFontHeight
/= nDPIY
;
1039 rFont
.SetSize( Size( 0, nFontHeight
) );
1040 rFont
.SetOrientation( (short)rLogFont
.lfEscapement
);
1041 if ( rLogFont
.lfItalic
)
1042 rFont
.SetItalic( ITALIC_NORMAL
);
1044 rFont
.SetItalic( ITALIC_NONE
);
1045 if ( rLogFont
.lfUnderline
)
1046 rFont
.SetUnderline( UNDERLINE_SINGLE
);
1048 rFont
.SetUnderline( UNDERLINE_NONE
);
1049 if ( rLogFont
.lfStrikeOut
)
1050 rFont
.SetStrikeout( STRIKEOUT_SINGLE
);
1052 rFont
.SetStrikeout( STRIKEOUT_NONE
);
1056 // -----------------------------------------------------------------------
1058 void ImplSalLogFontToFontW( HDC hDC
, const LOGFONTW
& rLogFont
, Font
& rFont
)
1060 XubString
aFontName( reinterpret_cast<const xub_Unicode
*>(rLogFont
.lfFaceName
) );
1061 if ( aFontName
.Len() )
1063 rFont
.SetName( aFontName
);
1064 rFont
.SetCharSet( ImplCharSetToSal( rLogFont
.lfCharSet
) );
1065 rFont
.SetFamily( ImplFamilyToSal( rLogFont
.lfPitchAndFamily
) );
1066 rFont
.SetPitch( ImplLogPitchToSal( rLogFont
.lfPitchAndFamily
) );
1067 rFont
.SetWeight( ImplWeightToSal( rLogFont
.lfWeight
) );
1069 long nFontHeight
= rLogFont
.lfHeight
;
1070 if ( nFontHeight
< 0 )
1071 nFontHeight
= -nFontHeight
;
1072 long nDPIY
= GetDeviceCaps( hDC
, LOGPIXELSY
);
1076 nFontHeight
+= nDPIY
/2;
1077 nFontHeight
/= nDPIY
;
1078 rFont
.SetSize( Size( 0, nFontHeight
) );
1079 rFont
.SetOrientation( (short)rLogFont
.lfEscapement
);
1080 if ( rLogFont
.lfItalic
)
1081 rFont
.SetItalic( ITALIC_NORMAL
);
1083 rFont
.SetItalic( ITALIC_NONE
);
1084 if ( rLogFont
.lfUnderline
)
1085 rFont
.SetUnderline( UNDERLINE_SINGLE
);
1087 rFont
.SetUnderline( UNDERLINE_NONE
);
1088 if ( rLogFont
.lfStrikeOut
)
1089 rFont
.SetStrikeout( STRIKEOUT_SINGLE
);
1091 rFont
.SetStrikeout( STRIKEOUT_NONE
);
1095 // =======================================================================
1097 ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes
& rDFS
,
1098 int nHeight
, BYTE eWinCharSet
, BYTE nPitchAndFamily
)
1099 : ImplFontData( rDFS
, 0 ),
1100 meWinCharSet( eWinCharSet
),
1101 mnPitchAndFamily( nPitchAndFamily
),
1102 mpFontCharSets( NULL
),
1103 mpUnicodeMap( NULL
),
1104 mbGsubRead( false ),
1105 mbDisableGlyphApi( false ),
1106 mbHasKoreanRange( false ),
1107 mbHasCJKSupport( false ),
1108 #ifdef ENABLE_GRAPHITE
1109 mbHasGraphiteSupport( false ),
1111 mbHasArabicSupport ( false ),
1112 mbAliasSymbolsLow( false ),
1113 mbAliasSymbolsHigh( false ),
1115 mpEncodingVector( NULL
)
1117 SetBitmapSize( 0, nHeight
);
1119 if( eWinCharSet
== SYMBOL_CHARSET
)
1121 if( (nPitchAndFamily
& TMPF_TRUETYPE
) != 0 )
1123 // truetype fonts need their symbols as U+F0xx
1124 mbAliasSymbolsHigh
= true;
1126 else if( (nPitchAndFamily
& (TMPF_VECTOR
|TMPF_DEVICE
))
1127 == (TMPF_VECTOR
|TMPF_DEVICE
) )
1129 // scalable device fonts (e.g. builtin printer fonts)
1130 // need their symbols as U+00xx
1131 mbAliasSymbolsLow
= true;
1133 else if( (nPitchAndFamily
& (TMPF_VECTOR
|TMPF_TRUETYPE
)) == 0 )
1135 // bitmap fonts need their symbols as U+F0xx
1136 mbAliasSymbolsHigh
= true;
1141 // -----------------------------------------------------------------------
1143 ImplWinFontData::~ImplWinFontData()
1145 delete[] mpFontCharSets
;
1148 mpUnicodeMap
->DeReference();
1149 delete mpEncodingVector
;
1152 // -----------------------------------------------------------------------
1154 sal_IntPtr
ImplWinFontData::GetFontId() const
1159 // -----------------------------------------------------------------------
1161 void ImplWinFontData::UpdateFromHDC( HDC hDC
) const
1163 // short circuit if already initialized
1164 if( mpUnicodeMap
!= NULL
)
1167 ReadCmapTable( hDC
);
1168 ReadOs2Table( hDC
);
1169 #ifdef ENABLE_GRAPHITE
1170 static const char* pDisableGraphiteText
= getenv( "SAL_DISABLE_GRAPHITE" );
1171 if( !pDisableGraphiteText
|| (pDisableGraphiteText
[0] == '0') )
1173 mbHasGraphiteSupport
= gr::WinFont::FontHasGraphiteTables(hDC
);
1177 // even if the font works some fonts have problems with the glyph API
1178 // => the heuristic below tries to figure out which fonts have the problem
1179 TEXTMETRICA aTextMetric
;
1180 if( ::GetTextMetricsA( hDC
, &aTextMetric
) )
1181 if( !(aTextMetric
.tmPitchAndFamily
& TMPF_TRUETYPE
)
1182 || (aTextMetric
.tmPitchAndFamily
& TMPF_DEVICE
) )
1183 mbDisableGlyphApi
= true;
1186 // #110548# more important than #107885# => TODO: better solution
1187 DWORD nFLI
= GetFontLanguageInfo( hDC
);
1188 if( 0 == (nFLI
& GCP_GLYPHSHAPE
) )
1189 mbDisableGlyphApi
= true;
1193 // -----------------------------------------------------------------------
1195 bool ImplWinFontData::HasGSUBstitutions( HDC hDC
) const
1198 ReadGsubTable( hDC
);
1199 return !maGsubTable
.empty();
1202 // -----------------------------------------------------------------------
1204 bool ImplWinFontData::IsGSUBstituted( sal_UCS4 cChar
) const
1206 return( maGsubTable
.find( cChar
) != maGsubTable
.end() );
1209 // -----------------------------------------------------------------------
1211 const ImplFontCharMap
* ImplWinFontData::GetImplFontCharMap() const
1215 return mpUnicodeMap
;
1218 // -----------------------------------------------------------------------
1220 static unsigned GetUInt( const unsigned char* p
) { return((p
[0]<<24)+(p
[1]<<16)+(p
[2]<<8)+p
[3]);}
1221 static unsigned GetUShort( const unsigned char* p
){ return((p
[0]<<8)+p
[1]);}
1222 //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
1223 static inline DWORD
CalcTag( const char p
[4]) { return (p
[0]+(p
[1]<<8)+(p
[2]<<16)+(p
[3]<<24)); }
1225 void ImplWinFontData::ReadOs2Table( HDC hDC
) const
1227 const DWORD Os2Tag
= CalcTag( "OS/2" );
1228 DWORD nLength
= ::GetFontData( hDC
, Os2Tag
, 0, NULL
, 0 );
1229 if( (nLength
== GDI_ERROR
) || !nLength
)
1231 std::vector
<unsigned char> aOS2map( nLength
);
1232 unsigned char* pOS2map
= &aOS2map
[0];
1233 ::GetFontData( hDC
, Os2Tag
, 0, pOS2map
, nLength
);
1234 sal_uInt32 nVersion
= GetUShort( pOS2map
);
1235 if ( nVersion
>= 0x0001 && nLength
>= 58 )
1237 // We need at least version 0x0001 (TrueType rev 1.66)
1238 // to have access to the needed struct members.
1239 sal_uInt32 ulUnicodeRange1
= GetUInt( pOS2map
+ 42 );
1240 sal_uInt32 ulUnicodeRange2
= GetUInt( pOS2map
+ 46 );
1242 sal_uInt32 ulUnicodeRange3
= GetUInt( pOS2map
+ 50 );
1243 sal_uInt32 ulUnicodeRange4
= GetUInt( pOS2map
+ 54 );
1246 // Check for CJK capabilities of the current font
1247 mbHasCJKSupport
= (ulUnicodeRange2
& 0x2DF00000);
1248 mbHasKoreanRange
= (ulUnicodeRange1
& 0x10000000)
1249 | (ulUnicodeRange2
& 0x01100000);
1250 mbHasArabicSupport
= (ulUnicodeRange1
& 0x00002000);
1254 // -----------------------------------------------------------------------
1256 void ImplWinFontData::ReadGsubTable( HDC hDC
) const
1260 // check the existence of a GSUB table
1261 const DWORD GsubTag
= CalcTag( "GSUB" );
1262 DWORD nRC
= ::GetFontData( hDC
, GsubTag
, 0, NULL
, 0 );
1263 if( (nRC
== GDI_ERROR
) || !nRC
)
1266 // parse the GSUB table through sft
1267 // TODO: parse it directly
1269 // sft needs the full font file data => get it
1270 const RawFontData
aRawFontData( hDC
);
1271 if( !aRawFontData
.get() )
1275 sal_uInt32 nFaceNum
= 0;
1276 if( !*aRawFontData
.get() ) // TTC candidate
1277 nFaceNum
= ~0U; // indicate "TTC font extracts only"
1279 TrueTypeFont
* pTTFont
= NULL
;
1280 ::OpenTTFontBuffer( (void*)aRawFontData
.get(), aRawFontData
.size(), nFaceNum
, &pTTFont
);
1284 // add vertically substituted characters to list
1285 static const sal_Unicode aGSUBCandidates
[] = {
1286 0x0020, 0x0080, // ASCII
1287 0x2000, 0x2600, // misc
1288 0x3000, 0x3100, // CJK punctutation
1289 0x3300, 0x3400, // squared words
1290 0xFF00, 0xFFF0, // halfwidth|fullwidth forms
1293 for( const sal_Unicode
* pPair
= aGSUBCandidates
; *pPair
; pPair
+= 2 )
1294 for( sal_Unicode cChar
= pPair
[0]; cChar
< pPair
[1]; ++cChar
)
1295 if( ::MapChar( pTTFont
, cChar
, 0 ) != ::MapChar( pTTFont
, cChar
, 1 ) )
1296 maGsubTable
.insert( cChar
); // insert GSUBbed unicodes
1298 CloseTTFont( pTTFont
);
1301 // -----------------------------------------------------------------------
1303 void ImplWinFontData::ReadCmapTable( HDC hDC
) const
1305 if( mpUnicodeMap
!= NULL
)
1308 bool bIsSymbolFont
= (meWinCharSet
== SYMBOL_CHARSET
);
1309 // get the CMAP table from the font which is selected into the DC
1310 const DWORD nCmapTag
= CalcTag( "cmap" );
1311 const RawFontData
aRawFontData( hDC
, nCmapTag
);
1312 // parse the CMAP table if available
1313 if( aRawFontData
.get() ) {
1315 ParseCMAP( aRawFontData
.get(), aRawFontData
.size(), aResult
);
1316 mbDisableGlyphApi
|= aResult
.mbRecoded
;
1317 aResult
.mbSymbolic
= bIsSymbolFont
;
1318 if( aResult
.mnRangeCount
> 0 )
1319 mpUnicodeMap
= new ImplFontCharMap( aResult
);
1323 mpUnicodeMap
= ImplFontCharMap::GetDefaultMap( bIsSymbolFont
);
1324 mpUnicodeMap
->AddReference();
1327 // =======================================================================
1329 void WinSalGraphics::SetTextColor( SalColor nSalColor
)
1331 COLORREF aCol
= PALETTERGB( SALCOLOR_RED( nSalColor
),
1332 SALCOLOR_GREEN( nSalColor
),
1333 SALCOLOR_BLUE( nSalColor
) );
1336 GetSalData()->mhDitherPal
&&
1337 ImplIsSysColorEntry( nSalColor
) )
1339 aCol
= PALRGB_TO_RGB( aCol
);
1342 ::SetTextColor( mhDC
, aCol
);
1345 // -----------------------------------------------------------------------
1347 int CALLBACK
SalEnumQueryFontProcExW( const ENUMLOGFONTEXW
*,
1348 const NEWTEXTMETRICEXW
*,
1349 DWORD
, LPARAM lParam
)
1351 *((bool*)(void*)lParam
) = true;
1355 // -----------------------------------------------------------------------
1357 int CALLBACK
SalEnumQueryFontProcExA( const ENUMLOGFONTEXA
*,
1358 const NEWTEXTMETRICEXA
*,
1359 DWORD
, LPARAM lParam
)
1361 *((bool*)(void*)lParam
) = true;
1365 // -----------------------------------------------------------------------
1367 bool ImplIsFontAvailable( HDC hDC
, const UniString
& rName
)
1369 // Test, if Font available
1371 memset( &aLogFont
, 0, sizeof( aLogFont
) );
1372 aLogFont
.lfCharSet
= DEFAULT_CHARSET
;
1374 UINT nNameLen
= rName
.Len();
1375 if ( nNameLen
> (sizeof( aLogFont
.lfFaceName
)/sizeof( wchar_t ))-1 )
1376 nNameLen
= (sizeof( aLogFont
.lfFaceName
)/sizeof( wchar_t ))-1;
1377 memcpy( aLogFont
.lfFaceName
, rName
.GetBuffer(), nNameLen
*sizeof( wchar_t ) );
1378 aLogFont
.lfFaceName
[nNameLen
] = 0;
1380 bool bAvailable
= false;
1381 EnumFontFamiliesExW( hDC
, &aLogFont
, (FONTENUMPROCW
)SalEnumQueryFontProcExW
,
1382 (LPARAM
)(void*)&bAvailable
, 0 );
1387 // -----------------------------------------------------------------------
1389 void ImplGetLogFontFromFontSelect( HDC hDC
,
1390 const ImplFontSelectData
* pFont
,
1392 bool /*bTestVerticalAvail*/ )
1395 if ( pFont
->mpFontData
)
1396 aName
= pFont
->mpFontData
->maName
;
1398 aName
= pFont
->maName
.GetToken( 0 );
1400 UINT nNameLen
= aName
.Len();
1401 if ( nNameLen
> (sizeof( rLogFont
.lfFaceName
)/sizeof( wchar_t ))-1 )
1402 nNameLen
= (sizeof( rLogFont
.lfFaceName
)/sizeof( wchar_t ))-1;
1403 memcpy( rLogFont
.lfFaceName
, aName
.GetBuffer(), nNameLen
*sizeof( wchar_t ) );
1404 rLogFont
.lfFaceName
[nNameLen
] = 0;
1406 if( !pFont
->mpFontData
)
1408 rLogFont
.lfCharSet
= pFont
->IsSymbolFont() ? SYMBOL_CHARSET
: DEFAULT_CHARSET
;
1409 rLogFont
.lfPitchAndFamily
= ImplPitchToWin( pFont
->mePitch
)
1410 | ImplFamilyToWin( pFont
->meFamily
);
1414 const ImplWinFontData
* pWinFontData
= static_cast<const ImplWinFontData
*>( pFont
->mpFontData
);
1415 rLogFont
.lfCharSet
= pWinFontData
->GetCharSet();
1416 rLogFont
.lfPitchAndFamily
= pWinFontData
->GetPitchAndFamily();
1419 rLogFont
.lfWeight
= ImplWeightToWin( pFont
->meWeight
);
1420 rLogFont
.lfHeight
= (LONG
)-pFont
->mnHeight
;
1421 rLogFont
.lfWidth
= (LONG
)pFont
->mnWidth
;
1422 rLogFont
.lfUnderline
= 0;
1423 rLogFont
.lfStrikeOut
= 0;
1424 rLogFont
.lfItalic
= (pFont
->meItalic
) != ITALIC_NONE
;
1425 rLogFont
.lfEscapement
= pFont
->mnOrientation
;
1426 rLogFont
.lfOrientation
= rLogFont
.lfEscapement
;
1427 rLogFont
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
1428 rLogFont
.lfQuality
= DEFAULT_QUALITY
;
1429 rLogFont
.lfOutPrecision
= OUT_TT_PRECIS
;
1430 if ( pFont
->mnOrientation
)
1431 rLogFont
.lfClipPrecision
|= CLIP_LH_ANGLES
;
1433 // disable antialiasing if requested
1434 if ( pFont
->mbNonAntialiased
)
1435 rLogFont
.lfQuality
= NONANTIALIASED_QUALITY
;
1437 // select vertical mode if requested and available
1438 if( pFont
->mbVertical
&& nNameLen
)
1440 // vertical fonts start with an '@'
1441 memmove( &rLogFont
.lfFaceName
[1], &rLogFont
.lfFaceName
[0],
1442 sizeof(rLogFont
.lfFaceName
)-sizeof(rLogFont
.lfFaceName
[0]) );
1443 rLogFont
.lfFaceName
[0] = '@';
1445 // check availability of vertical mode for this font
1446 bool bAvailable
= false;
1447 EnumFontFamiliesExW( hDC
, &rLogFont
, (FONTENUMPROCW
)SalEnumQueryFontProcExW
,
1448 (LPARAM
)&bAvailable
, 0 );
1452 // restore non-vertical name if not vertical mode isn't available
1453 memcpy( &rLogFont
.lfFaceName
[0], aName
.GetBuffer(), nNameLen
*sizeof(wchar_t) );
1454 if( nNameLen
< LF_FACESIZE
)
1455 rLogFont
.lfFaceName
[nNameLen
] = '\0';
1460 // -----------------------------------------------------------------------
1462 static void ImplGetLogFontFromFontSelect( HDC hDC
,
1463 const ImplFontSelectData
* pFont
,
1465 bool /*bTestVerticalAvail*/ )
1468 if( pFont
->mpFontData
)
1469 aName
= ImplSalGetWinAnsiString( pFont
->mpFontData
->maName
);
1471 aName
= ImplSalGetWinAnsiString( pFont
->maName
.GetToken( 0 ) );
1473 int nNameLen
= aName
.Len();
1474 if( nNameLen
> LF_FACESIZE
)
1475 nNameLen
= LF_FACESIZE
;
1476 memcpy( rLogFont
.lfFaceName
, aName
.GetBuffer(), nNameLen
);
1477 if( nNameLen
< LF_FACESIZE
)
1478 rLogFont
.lfFaceName
[nNameLen
] = '\0';
1480 if( !pFont
->mpFontData
)
1482 rLogFont
.lfCharSet
= pFont
->IsSymbolFont() ? SYMBOL_CHARSET
: DEFAULT_CHARSET
;
1483 rLogFont
.lfPitchAndFamily
= ImplPitchToWin( pFont
->mePitch
)
1484 | ImplFamilyToWin( pFont
->meFamily
);
1488 const ImplWinFontData
* pWinFontData
= static_cast<const ImplWinFontData
*>( pFont
->mpFontData
);
1489 rLogFont
.lfCharSet
= pWinFontData
->GetCharSet();
1490 rLogFont
.lfPitchAndFamily
= pWinFontData
->GetPitchAndFamily();
1493 rLogFont
.lfWeight
= ImplWeightToWin( pFont
->meWeight
);
1494 rLogFont
.lfHeight
= (LONG
)-pFont
->mnHeight
;
1495 rLogFont
.lfWidth
= (LONG
)pFont
->mnWidth
;
1496 rLogFont
.lfUnderline
= 0;
1497 rLogFont
.lfStrikeOut
= 0;
1498 rLogFont
.lfItalic
= (pFont
->meItalic
) != ITALIC_NONE
;
1499 rLogFont
.lfEscapement
= pFont
->mnOrientation
;
1500 rLogFont
.lfOrientation
= rLogFont
.lfEscapement
; // ignored by W98
1501 rLogFont
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
1502 rLogFont
.lfQuality
= DEFAULT_QUALITY
;
1503 rLogFont
.lfOutPrecision
= OUT_TT_PRECIS
;
1504 if( pFont
->mnOrientation
)
1505 rLogFont
.lfClipPrecision
|= CLIP_LH_ANGLES
;
1507 // disable antialiasing if requested
1508 if( pFont
->mbNonAntialiased
)
1509 rLogFont
.lfQuality
= NONANTIALIASED_QUALITY
;
1511 // select vertical mode if requested and available
1512 if( pFont
->mbVertical
&& nNameLen
)
1514 // vertical fonts start with an '@'
1515 memmove( &rLogFont
.lfFaceName
[1], &rLogFont
.lfFaceName
[0],
1516 sizeof(rLogFont
.lfFaceName
)-sizeof(rLogFont
.lfFaceName
[0]) );
1517 rLogFont
.lfFaceName
[0] = '@';
1519 // check availability of vertical mode for this font
1520 bool bAvailable
= false;
1521 EnumFontFamiliesExA( hDC
, &rLogFont
, (FONTENUMPROCA
)SalEnumQueryFontProcExA
,
1522 (LPARAM
)&bAvailable
, 0 );
1526 // restore non-vertical name if vertical mode is not supported
1527 memcpy( rLogFont
.lfFaceName
, aName
.GetBuffer(), nNameLen
);
1528 if( nNameLen
< LF_FACESIZE
)
1529 rLogFont
.lfFaceName
[nNameLen
] = '\0';
1534 // -----------------------------------------------------------------------
1536 HFONT
WinSalGraphics::ImplDoSetFont( ImplFontSelectData
* i_pFont
, float& o_rFontScale
, HFONT
& o_rOldFont
)
1542 // only required for virtual devices, see below for details
1543 hdcScreen
= GetDC(0);
1545 if( true/*aSalShlData.mbWNT*/ )
1548 ImplGetLogFontFromFontSelect( mhDC
, i_pFont
, aLogFont
, true );
1550 // on the display we prefer Courier New when Courier is a
1551 // bitmap only font and we need to stretch or rotate it
1553 && (i_pFont
->mnWidth
!= 0
1554 || i_pFont
->mnOrientation
!= 0
1555 || i_pFont
->mpFontData
== NULL
1556 || (i_pFont
->mpFontData
->GetHeight() != i_pFont
->mnHeight
))
1557 && !bImplSalCourierScalable
1558 && bImplSalCourierNew
1559 && (ImplSalWICompareAscii( aLogFont
.lfFaceName
, "Courier" ) == 0) )
1560 lstrcpynW( aLogFont
.lfFaceName
, L
"Courier New", 11 );
1562 // #i47675# limit font requests to MAXFONTHEIGHT
1563 // TODO: share MAXFONTHEIGHT font instance
1564 if( (-aLogFont
.lfHeight
<= MAXFONTHEIGHT
)
1565 && (+aLogFont
.lfWidth
<= MAXFONTHEIGHT
) )
1569 else if( -aLogFont
.lfHeight
>= +aLogFont
.lfWidth
)
1571 o_rFontScale
= -aLogFont
.lfHeight
/ (float)MAXFONTHEIGHT
;
1572 aLogFont
.lfHeight
= -MAXFONTHEIGHT
;
1573 aLogFont
.lfWidth
= FRound( aLogFont
.lfWidth
/ o_rFontScale
);
1575 else // #i95867# also limit font widths
1577 o_rFontScale
= +aLogFont
.lfWidth
/ (float)MAXFONTHEIGHT
;
1578 aLogFont
.lfWidth
= +MAXFONTHEIGHT
;
1579 aLogFont
.lfHeight
= FRound( aLogFont
.lfHeight
/ o_rFontScale
);
1582 hNewFont
= ::CreateFontIndirectW( &aLogFont
);
1585 // select font into screen hdc first to get an antialiased font
1586 // see knowledge base article 305290:
1587 // "PRB: Fonts Not Drawn Antialiased on Device Context for DirectDraw Surface"
1588 SelectFont( hdcScreen
, SelectFont( hdcScreen
, hNewFont
) );
1590 o_rOldFont
= ::SelectFont( mhDC
, hNewFont
);
1592 TEXTMETRICW aTextMetricW
;
1593 if( !::GetTextMetricsW( mhDC
, &aTextMetricW
) )
1595 // the selected font doesn't work => try a replacement
1596 // TODO: use its font fallback instead
1597 lstrcpynW( aLogFont
.lfFaceName
, L
"Courier New", 11 );
1598 aLogFont
.lfPitchAndFamily
= FIXED_PITCH
;
1599 HFONT hNewFont2
= CreateFontIndirectW( &aLogFont
);
1600 SelectFont( mhDC
, hNewFont2
);
1601 DeleteFont( hNewFont
);
1602 hNewFont
= hNewFont2
;
1607 ::ReleaseDC( NULL
, hdcScreen
);
1612 sal_uInt16
WinSalGraphics::SetFont( ImplFontSelectData
* pFont
, int nFallbackLevel
)
1614 // return early if there is no new font
1617 // deselect still active font
1619 ::SelectFont( mhDC
, mhDefFont
);
1620 // release no longer referenced font handles
1621 for( int i
= nFallbackLevel
; i
< MAX_FALLBACK
; ++i
)
1624 ::DeleteFont( mhFonts
[i
] );
1631 DBG_ASSERT( pFont
->mpFontData
, "WinSalGraphics mpFontData==NULL");
1632 mpWinFontEntry
[ nFallbackLevel
] = reinterpret_cast<ImplWinFontEntry
*>( pFont
->mpFontEntry
);
1633 mpWinFontData
[ nFallbackLevel
] = static_cast<const ImplWinFontData
*>( pFont
->mpFontData
);
1636 HFONT hNewFont
= ImplDoSetFont( pFont
, mfFontScale
, hOldFont
);
1640 // keep default font
1641 mhDefFont
= hOldFont
;
1645 // release no longer referenced font handles
1646 for( int i
= nFallbackLevel
; i
< MAX_FALLBACK
; ++i
)
1650 ::DeleteFont( mhFonts
[i
] );
1656 // store new font in correct layer
1657 mhFonts
[ nFallbackLevel
] = hNewFont
;
1658 // now the font is live => update font face
1659 if( mpWinFontData
[ nFallbackLevel
] )
1660 mpWinFontData
[ nFallbackLevel
]->UpdateFromHDC( mhDC
);
1662 if( !nFallbackLevel
)
1664 mbFontKernInit
= TRUE
;
1665 if ( mpFontKernPairs
)
1667 delete[] mpFontKernPairs
;
1668 mpFontKernPairs
= NULL
;
1670 mnFontKernPairCount
= 0;
1673 mnFontCharSetCount
= 0;
1675 // some printers have higher internal resolution, so their
1676 // text output would be different from what we calculated
1677 // => suggest DrawTextArray to workaround this problem
1679 return SAL_SETFONT_USEDRAWTEXTARRAY
;
1684 // -----------------------------------------------------------------------
1686 void WinSalGraphics::GetFontMetric( ImplFontMetricData
* pMetric
, int nFallbackLevel
)
1688 // temporarily change the HDC to the font in the fallback level
1689 HFONT hOldFont
= SelectFont( mhDC
, mhFonts
[nFallbackLevel
] );
1691 wchar_t aFaceName
[LF_FACESIZE
+60];
1692 if( ::GetTextFaceW( mhDC
, sizeof(aFaceName
)/sizeof(wchar_t), aFaceName
) )
1693 pMetric
->maName
= reinterpret_cast<const sal_Unicode
*>(aFaceName
);
1695 // get the font metric
1696 TEXTMETRICA aWinMetric
;
1697 const bool bOK
= GetTextMetricsA( mhDC
, &aWinMetric
);
1698 // restore the HDC to the font in the base level
1699 SelectFont( mhDC
, hOldFont
);
1703 // device independent font attributes
1704 pMetric
->meFamily
= ImplFamilyToSal( aWinMetric
.tmPitchAndFamily
);;
1705 pMetric
->mbSymbolFlag
= (aWinMetric
.tmCharSet
== SYMBOL_CHARSET
);
1706 pMetric
->meWeight
= ImplWeightToSal( aWinMetric
.tmWeight
);
1707 pMetric
->mePitch
= ImplMetricPitchToSal( aWinMetric
.tmPitchAndFamily
);
1708 pMetric
->meItalic
= aWinMetric
.tmItalic
? ITALIC_NORMAL
: ITALIC_NONE
;
1709 pMetric
->mnSlant
= 0;
1711 // device dependend font attributes
1712 pMetric
->mbDevice
= (aWinMetric
.tmPitchAndFamily
& TMPF_DEVICE
) != 0;
1713 pMetric
->mbScalableFont
= (aWinMetric
.tmPitchAndFamily
& (TMPF_VECTOR
|TMPF_TRUETYPE
)) != 0;
1714 if( pMetric
->mbScalableFont
)
1716 // check if there are kern pairs
1717 // TODO: does this work with GPOS kerning?
1718 DWORD nKernPairs
= ::GetKerningPairsA( mhDC
, 0, NULL
);
1719 pMetric
->mbKernableFont
= (nKernPairs
> 0);
1723 // bitmap fonts cannot be rotated directly
1724 pMetric
->mnOrientation
= 0;
1725 // bitmap fonts have no kerning
1726 pMetric
->mbKernableFont
= false;
1729 // transformation dependend font metrics
1730 pMetric
->mnWidth
= static_cast<int>( mfFontScale
* aWinMetric
.tmAveCharWidth
);
1731 pMetric
->mnIntLeading
= static_cast<int>( mfFontScale
* aWinMetric
.tmInternalLeading
);
1732 pMetric
->mnExtLeading
= static_cast<int>( mfFontScale
* aWinMetric
.tmExternalLeading
);
1733 pMetric
->mnAscent
= static_cast<int>( mfFontScale
* aWinMetric
.tmAscent
);
1734 pMetric
->mnDescent
= static_cast<int>( mfFontScale
* aWinMetric
.tmDescent
);
1736 // #107888# improved metric compatibility for Asian fonts...
1737 // TODO: assess workaround below for CWS >= extleading
1738 // TODO: evaluate use of aWinMetric.sTypo* members for CJK
1739 if( mpWinFontData
[nFallbackLevel
] && mpWinFontData
[nFallbackLevel
]->SupportsCJK() )
1741 pMetric
->mnIntLeading
+= pMetric
->mnExtLeading
;
1743 // #109280# The line height for Asian fonts is too small.
1744 // Therefore we add half of the external leading to the
1745 // ascent, the other half is added to the descent.
1746 const long nHalfTmpExtLeading
= pMetric
->mnExtLeading
/ 2;
1747 const long nOtherHalfTmpExtLeading
= pMetric
->mnExtLeading
- nHalfTmpExtLeading
;
1749 // #110641# external leading for Asian fonts.
1750 // The factor 0.3 has been confirmed with experiments.
1751 long nCJKExtLeading
= static_cast<long>(0.30 * (pMetric
->mnAscent
+ pMetric
->mnDescent
));
1752 nCJKExtLeading
-= pMetric
->mnExtLeading
;
1753 pMetric
->mnExtLeading
= (nCJKExtLeading
> 0) ? nCJKExtLeading
: 0;
1755 pMetric
->mnAscent
+= nHalfTmpExtLeading
;
1756 pMetric
->mnDescent
+= nOtherHalfTmpExtLeading
;
1759 pMetric
->mnMinKashida
= GetMinKashidaWidth();
1762 // -----------------------------------------------------------------------
1764 int CALLBACK
SalEnumCharSetsProcExA( const ENUMLOGFONTEXA
* pLogFont
,
1765 const NEWTEXTMETRICEXA
* /*pMetric*/,
1766 DWORD
/*nFontType*/, LPARAM lParam
)
1768 WinSalGraphics
* pData
= (WinSalGraphics
*)lParam
;
1769 // Charset already in the list?
1770 for ( BYTE i
= 0; i
< pData
->mnFontCharSetCount
; i
++ )
1772 if ( pData
->mpFontCharSets
[i
] == pLogFont
->elfLogFont
.lfCharSet
)
1775 pData
->mpFontCharSets
[pData
->mnFontCharSetCount
] = pLogFont
->elfLogFont
.lfCharSet
;
1776 pData
->mnFontCharSetCount
++;
1780 // -----------------------------------------------------------------------
1782 static void ImplGetAllFontCharSets( WinSalGraphics
* pData
)
1784 if ( !pData
->mpFontCharSets
)
1785 pData
->mpFontCharSets
= new BYTE
[256];
1788 memset( &aLogFont
, 0, sizeof( aLogFont
) );
1789 aLogFont
.lfCharSet
= DEFAULT_CHARSET
;
1790 GetTextFaceA( pData
->mhDC
, sizeof( aLogFont
.lfFaceName
), aLogFont
.lfFaceName
);
1791 EnumFontFamiliesExA( pData
->mhDC
, &aLogFont
, (FONTENUMPROCA
)SalEnumCharSetsProcExA
,
1792 (LPARAM
)(void*)pData
, 0 );
1795 // -----------------------------------------------------------------------
1797 static void ImplAddKerningPairs( WinSalGraphics
* pData
)
1799 sal_uLong nPairs
= ::GetKerningPairsA( pData
->mhDC
, 0, NULL
);
1804 if ( !TranslateCharsetInfo( (DWORD
*)(sal_uLong
)GetTextCharset( pData
->mhDC
), &aInfo
, TCI_SRCCHARSET
) )
1807 if ( !pData
->mpFontKernPairs
)
1808 pData
->mpFontKernPairs
= new KERNINGPAIR
[nPairs
];
1811 KERNINGPAIR
* pOldPairs
= pData
->mpFontKernPairs
;
1812 pData
->mpFontKernPairs
= new KERNINGPAIR
[nPairs
+pData
->mnFontKernPairCount
];
1813 memcpy( pData
->mpFontKernPairs
, pOldPairs
,
1814 pData
->mnFontKernPairCount
*sizeof( KERNINGPAIR
) );
1818 UINT nCP
= aInfo
.ciACP
;
1819 sal_uLong nOldPairs
= pData
->mnFontKernPairCount
;
1820 KERNINGPAIR
* pTempPair
= pData
->mpFontKernPairs
+pData
->mnFontKernPairCount
;
1821 nPairs
= ::GetKerningPairsA( pData
->mhDC
, nPairs
, pTempPair
);
1822 for ( sal_uLong i
= 0; i
< nPairs
; i
++ )
1824 unsigned char aBuf
[2];
1827 sal_Bool bAdd
= TRUE
;
1829 // None-ASCII?, then we must convert the char
1830 if ( (pTempPair
->wFirst
> 125) || (pTempPair
->wFirst
== 92) )
1832 if ( pTempPair
->wFirst
< 256 )
1834 aBuf
[0] = (unsigned char)pTempPair
->wFirst
;
1839 aBuf
[0] = (unsigned char)(pTempPair
->wFirst
>> 8);
1840 aBuf
[1] = (unsigned char)(pTempPair
->wFirst
& 0xFF);
1843 if ( MultiByteToWideChar( nCP
, MB_PRECOMPOSED
| MB_USEGLYPHCHARS
,
1844 (const char*)aBuf
, nLen
, &nChar
, 1 ) )
1845 pTempPair
->wFirst
= nChar
;
1849 if ( (pTempPair
->wSecond
> 125) || (pTempPair
->wSecond
== 92) )
1851 if ( pTempPair
->wSecond
< 256 )
1853 aBuf
[0] = (unsigned char)pTempPair
->wSecond
;
1858 aBuf
[0] = (unsigned char)(pTempPair
->wSecond
>> 8);
1859 aBuf
[1] = (unsigned char)(pTempPair
->wSecond
& 0xFF);
1862 if ( MultiByteToWideChar( nCP
, MB_PRECOMPOSED
| MB_USEGLYPHCHARS
,
1863 (const char*)aBuf
, nLen
, &nChar
, 1 ) )
1864 pTempPair
->wSecond
= nChar
;
1869 // TODO: get rid of linear search!
1870 KERNINGPAIR
* pTempPair2
= pData
->mpFontKernPairs
;
1871 for ( sal_uLong j
= 0; j
< nOldPairs
; j
++ )
1873 if ( (pTempPair2
->wFirst
== pTempPair
->wFirst
) &&
1874 (pTempPair2
->wSecond
== pTempPair
->wSecond
) )
1884 KERNINGPAIR
* pDestPair
= pData
->mpFontKernPairs
+pData
->mnFontKernPairCount
;
1885 if ( pDestPair
!= pTempPair
)
1886 memcpy( pDestPair
, pTempPair
, sizeof( KERNINGPAIR
) );
1887 pData
->mnFontKernPairCount
++;
1894 // -----------------------------------------------------------------------
1896 sal_uLong
WinSalGraphics::GetKernPairs( sal_uLong nPairs
, ImplKernPairData
* pKernPairs
)
1898 DBG_ASSERT( sizeof( KERNINGPAIR
) == sizeof( ImplKernPairData
),
1899 "WinSalGraphics::GetKernPairs(): KERNINGPAIR != ImplKernPairData" );
1901 if ( mbFontKernInit
)
1903 if( mpFontKernPairs
)
1905 delete[] mpFontKernPairs
;
1906 mpFontKernPairs
= NULL
;
1908 mnFontKernPairCount
= 0;
1910 KERNINGPAIR
* pPairs
= NULL
;
1911 int nCount
= ::GetKerningPairsW( mhDC
, 0, NULL
);
1914 #ifdef GCP_KERN_HACK
1915 pPairs
= new KERNINGPAIR
[ nCount
+1 ];
1916 mpFontKernPairs
= pPairs
;
1917 mnFontKernPairCount
= nCount
;
1918 ::GetKerningPairsW( mhDC
, nCount
, pPairs
);
1919 #else // GCP_KERN_HACK
1920 pPairs
= pKernPairs
;
1921 nCount
= (nCount
< nPairs
) : nCount
: nPairs
;
1922 ::GetKerningPairsW( mhDC
, nCount
, pPairs
);
1924 #endif // GCP_KERN_HACK
1927 mbFontKernInit
= FALSE
;
1929 std::sort( mpFontKernPairs
, mpFontKernPairs
+ mnFontKernPairCount
, ImplCmpKernData
);
1933 return mnFontKernPairCount
;
1934 else if( mpFontKernPairs
)
1936 if ( nPairs
< mnFontKernPairCount
)
1937 nPairs
= mnFontKernPairCount
;
1938 memcpy( pKernPairs
, mpFontKernPairs
,
1939 nPairs
*sizeof( ImplKernPairData
) );
1946 // -----------------------------------------------------------------------
1948 const ImplFontCharMap
* WinSalGraphics::GetImplFontCharMap() const
1950 if( !mpWinFontData
[0] )
1951 return ImplFontCharMap::GetDefaultMap();
1952 return mpWinFontData
[0]->GetImplFontCharMap();
1955 // -----------------------------------------------------------------------
1957 int CALLBACK
SalEnumFontsProcExA( const ENUMLOGFONTEXA
* pLogFont
,
1958 const NEWTEXTMETRICEXA
* pMetric
,
1959 DWORD nFontType
, LPARAM lParam
)
1961 ImplEnumInfo
* pInfo
= (ImplEnumInfo
*)(void*)lParam
;
1962 if ( !pInfo
->mpName
)
1964 // Ignore vertical fonts
1965 if ( pLogFont
->elfLogFont
.lfFaceName
[0] != '@' )
1967 if ( !pInfo
->mbImplSalCourierNew
)
1968 pInfo
->mbImplSalCourierNew
= stricmp( pLogFont
->elfLogFont
.lfFaceName
, "Courier New" ) == 0;
1969 if ( !pInfo
->mbImplSalCourierScalable
)
1970 pInfo
->mbCourier
= stricmp( pLogFont
->elfLogFont
.lfFaceName
, "Courier" ) == 0;
1972 pInfo
->mbCourier
= FALSE
;
1973 String
aName( ImplSalGetUniString( pLogFont
->elfLogFont
.lfFaceName
) );
1974 pInfo
->mpName
= &aName
;
1975 strncpy( pInfo
->mpLogFontA
->lfFaceName
, pLogFont
->elfLogFont
.lfFaceName
, LF_FACESIZE
);
1976 pInfo
->mpLogFontA
->lfCharSet
= pLogFont
->elfLogFont
.lfCharSet
;
1977 EnumFontFamiliesExA( pInfo
->mhDC
, pInfo
->mpLogFontA
, (FONTENUMPROCA
)SalEnumFontsProcExA
,
1978 (LPARAM
)(void*)pInfo
, 0 );
1979 pInfo
->mpLogFontA
->lfFaceName
[0] = '\0';
1980 pInfo
->mpLogFontA
->lfCharSet
= DEFAULT_CHARSET
;
1981 pInfo
->mpName
= NULL
;
1982 pInfo
->mbCourier
= FALSE
;
1987 // ignore non-scalable non-device font on printer
1988 if( pInfo
->mbPrinter
)
1989 if( (nFontType
& RASTER_FONTTYPE
) && !(nFontType
& DEVICE_FONTTYPE
) )
1992 ImplWinFontData
* pData
= ImplLogMetricToDevFontDataA( pLogFont
, &(pMetric
->ntmTm
), nFontType
);
1993 pData
->SetFontId( sal_IntPtr( pInfo
->mnFontCount
++ ) );
1995 // prefer the system character set, so that we get as much as
1996 // possible important characters. In the other case we could only
1997 // display a limited set of characters (#87309#)
1998 if ( pInfo
->mnPreferedCharSet
== pLogFont
->elfLogFont
.lfCharSet
)
1999 pData
->mnQuality
+= 100;
2001 // knowing Courier to be scalable is nice
2002 if( pInfo
->mbCourier
)
2003 pInfo
->mbImplSalCourierScalable
|= pData
->IsScalable();
2005 pInfo
->mpList
->Add( pData
);
2011 // -----------------------------------------------------------------------
2013 int CALLBACK
SalEnumFontsProcExW( const ENUMLOGFONTEXW
* pLogFont
,
2014 const NEWTEXTMETRICEXW
* pMetric
,
2015 DWORD nFontType
, LPARAM lParam
)
2017 ImplEnumInfo
* pInfo
= (ImplEnumInfo
*)(void*)lParam
;
2018 if ( !pInfo
->mpName
)
2020 // Ignore vertical fonts
2021 if ( pLogFont
->elfLogFont
.lfFaceName
[0] != '@' )
2023 if ( !pInfo
->mbImplSalCourierNew
)
2024 pInfo
->mbImplSalCourierNew
= ImplSalWICompareAscii( pLogFont
->elfLogFont
.lfFaceName
, "Courier New" ) == 0;
2025 if ( !pInfo
->mbImplSalCourierScalable
)
2026 pInfo
->mbCourier
= ImplSalWICompareAscii( pLogFont
->elfLogFont
.lfFaceName
, "Courier" ) == 0;
2028 pInfo
->mbCourier
= FALSE
;
2029 String
aName( reinterpret_cast<const sal_Unicode
*>(pLogFont
->elfLogFont
.lfFaceName
) );
2030 pInfo
->mpName
= &aName
;
2031 memcpy( pInfo
->mpLogFontW
->lfFaceName
, pLogFont
->elfLogFont
.lfFaceName
, (aName
.Len()+1)*sizeof( wchar_t ) );
2032 pInfo
->mpLogFontW
->lfCharSet
= pLogFont
->elfLogFont
.lfCharSet
;
2033 EnumFontFamiliesExW( pInfo
->mhDC
, pInfo
->mpLogFontW
, (FONTENUMPROCW
)SalEnumFontsProcExW
,
2034 (LPARAM
)(void*)pInfo
, 0 );
2035 pInfo
->mpLogFontW
->lfFaceName
[0] = '\0';
2036 pInfo
->mpLogFontW
->lfCharSet
= DEFAULT_CHARSET
;
2037 pInfo
->mpName
= NULL
;
2038 pInfo
->mbCourier
= FALSE
;
2043 // ignore non-scalable non-device font on printer
2044 if( pInfo
->mbPrinter
)
2045 if( (nFontType
& RASTER_FONTTYPE
) && !(nFontType
& DEVICE_FONTTYPE
) )
2048 ImplWinFontData
* pData
= ImplLogMetricToDevFontDataW( pLogFont
, &(pMetric
->ntmTm
), nFontType
);
2049 pData
->SetFontId( sal_IntPtr( pInfo
->mnFontCount
++ ) );
2051 // knowing Courier to be scalable is nice
2052 if( pInfo
->mbCourier
)
2053 pInfo
->mbImplSalCourierScalable
|= pData
->IsScalable();
2055 pInfo
->mpList
->Add( pData
);
2061 // -----------------------------------------------------------------------
2065 ::rtl::OUString maFontFilePath
;
2066 ::rtl::OString maResourcePath
;
2067 TempFontItem
* mpNextItem
;
2071 static int WINAPI
__AddFontResourceExW( LPCWSTR lpszfileName
, DWORD fl
, PVOID pdv
)
2073 typedef int (WINAPI
*AddFontResourceExW_FUNC
)(LPCWSTR
, DWORD
, PVOID
);
2075 static AddFontResourceExW_FUNC pFunc
= NULL
;
2076 static HMODULE hmGDI
= NULL
;
2078 if ( !pFunc
&& !hmGDI
)
2080 hmGDI
= GetModuleHandleA( "GDI32" );
2082 pFunc
= reinterpret_cast<AddFontResourceExW_FUNC
>( GetProcAddress( hmGDI
, "AddFontResourceExW" ) );
2086 return pFunc( lpszfileName
, fl
, pdv
);
2089 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
2095 bool ImplAddTempFont( SalData
& rSalData
, const String
& rFontFileURL
)
2098 ::rtl::OUString aUSytemPath
;
2099 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL
, aUSytemPath
) );
2102 nRet
= __AddFontResourceExW( reinterpret_cast<LPCWSTR
>(aUSytemPath
.getStr()), FR_PRIVATE
, NULL
);
2107 static int nCounter
= 0;
2108 char aFileName
[] = "soAA.fot";
2109 aFileName
[2] = sal::static_int_cast
<char>('A' + (15 & (nCounter
>>4)));
2110 aFileName
[3] = sal::static_int_cast
<char>('A' + (15 & nCounter
));
2111 char aResourceName
[512];
2112 int nMaxLen
= sizeof(aResourceName
)/sizeof(*aResourceName
) - 16;
2113 int nLen
= ::GetTempPathA( nMaxLen
, aResourceName
);
2114 ::strncpy( aResourceName
+ nLen
, aFileName
, sizeof( aResourceName
)- nLen
);
2115 // security: end buffer in any case
2116 aResourceName
[ (sizeof(aResourceName
)/sizeof(*aResourceName
))-1 ] = 0;
2117 ::DeleteFileA( aResourceName
);
2119 rtl_TextEncoding theEncoding
= osl_getThreadTextEncoding();
2120 ::rtl::OString aCFileName
= rtl::OUStringToOString( aUSytemPath
, theEncoding
);
2121 // TODO: font should be private => need to investigate why it doesn't work then
2122 if( !::CreateScalableFontResourceA( 0, aResourceName
, aCFileName
.getStr(), NULL
) )
2126 nRet
= ::AddFontResourceA( aResourceName
);
2129 TempFontItem
* pNewItem
= new TempFontItem
;
2130 pNewItem
->maResourcePath
= rtl::OString( aResourceName
);
2131 pNewItem
->maFontFilePath
= aUSytemPath
.getStr();
2132 pNewItem
->mpNextItem
= rSalData
.mpTempFontItem
;
2133 rSalData
.mpTempFontItem
= pNewItem
;
2140 // -----------------------------------------------------------------------
2142 void ImplReleaseTempFonts( SalData
& rSalData
)
2145 while( TempFontItem
* p
= rSalData
.mpTempFontItem
)
2148 if( p
->maResourcePath
.getLength() )
2150 const char* pResourcePath
= p
->maResourcePath
.getStr();
2151 ::RemoveFontResourceA( pResourcePath
);
2152 ::DeleteFileA( pResourcePath
);
2156 ::RemoveFontResourceW( reinterpret_cast<LPCWSTR
>(p
->maFontFilePath
.getStr()) );
2159 rSalData
.mpTempFontItem
= p
->mpNextItem
;
2164 // notify every other application
2165 // unless the temp fonts were installed as private fonts
2167 ::PostMessage( HWND_BROADCAST
, WM_FONTCHANGE
, 0, NULL
);
2168 #endif // FR_PRIVATE
2171 // -----------------------------------------------------------------------
2173 static bool ImplGetFontAttrFromFile( const String
& rFontFileURL
,
2174 ImplDevFontAttributes
& rDFA
)
2176 ::rtl::OUString aUSytemPath
;
2177 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL
, aUSytemPath
) );
2179 // get FontAttributes from a *fot file
2180 // TODO: use GetTTGlobalFontInfo() to access the font directly
2181 rDFA
.mnQuality
= 1000;
2182 rDFA
.mbDevice
= true;
2183 rDFA
.meFamily
= FAMILY_DONTKNOW
;
2184 rDFA
.meWidthType
= WIDTH_DONTKNOW
;
2185 rDFA
.meWeight
= WEIGHT_DONTKNOW
;
2186 rDFA
.meItalic
= ITALIC_DONTKNOW
;
2187 rDFA
.mePitch
= PITCH_DONTKNOW
;;
2188 rDFA
.mbSubsettable
= true;
2189 rDFA
.mbEmbeddable
= false;
2191 // Create temporary file name
2192 char aFileName
[] = "soAAT.fot";
2193 char aResourceName
[512];
2194 int nMaxLen
= sizeof(aResourceName
)/sizeof(*aResourceName
) - 16;
2195 int nLen
= ::GetTempPathA( nMaxLen
, aResourceName
);
2196 ::strncpy( aResourceName
+ nLen
, aFileName
, Max( 0, nMaxLen
- nLen
));
2197 ::DeleteFileA( aResourceName
);
2199 // Create font resource file (typically with a .fot file name extension).
2200 rtl_TextEncoding theEncoding
= osl_getThreadTextEncoding();
2201 ::rtl::OString aCFileName
= rtl::OUStringToOString( aUSytemPath
, theEncoding
);
2202 ::CreateScalableFontResourceA( 0, aResourceName
, aCFileName
.getStr(), NULL
);
2204 // Open and read the font resource file
2205 rtl::OUString aFotFileName
= rtl::OStringToOUString( aResourceName
, osl_getThreadTextEncoding() );
2206 osl::FileBase::getFileURLFromSystemPath( aFotFileName
, aFotFileName
);
2207 osl::File
aFotFile( aFotFileName
);
2208 osl::FileBase::RC aError
= aFotFile
.open( osl_File_OpenFlag_Read
);
2209 if( aError
!= osl::FileBase::E_None
)
2212 sal_uInt64 nBytesRead
= 0;
2214 aFotFile
.read( aBuffer
, sizeof( aBuffer
), nBytesRead
);
2215 // clean up temporary resource file
2217 ::DeleteFileA( aResourceName
);
2219 // retrieve font family name from byte offset 0x4F6
2222 while( (i
< nBytesRead
) && (aBuffer
[i
++] != 0) );
2224 while( (i
< nBytesRead
) && (aBuffer
[i
++] != 0) );
2225 // retrieve font style name
2227 while( (i
< nBytesRead
) && (aBuffer
[i
++] != 0) );
2228 if( i
>= nBytesRead
)
2231 // convert byte strings to unicode
2232 rDFA
.maName
= String( aBuffer
+ nNameOfs
, osl_getThreadTextEncoding() );
2233 rDFA
.maStyleName
= String( aBuffer
+ nStyleOfs
, osl_getThreadTextEncoding() );
2235 // byte offset 0x4C7: OS2_fsSelection
2236 const char nFSS
= aBuffer
[ 0x4C7 ];
2237 if( nFSS
& 0x01 ) // italic
2238 rDFA
.meItalic
= ITALIC_NORMAL
;
2239 //if( nFSS & 0x20 ) // bold
2240 // rDFA.meWeight = WEIGHT_BOLD;
2241 if( nFSS
& 0x40 ) // regular
2243 rDFA
.meWeight
= WEIGHT_NORMAL
;
2244 rDFA
.meItalic
= ITALIC_NONE
;
2247 // byte offsets 0x4D7/0x4D8: wingdi's FW_WEIGHT
2248 int nWinWeight
= (aBuffer
[0x4D7] & 0xFF) + ((aBuffer
[0x4D8] & 0xFF) << 8);
2249 rDFA
.meWeight
= ImplWeightToSal( nWinWeight
);
2251 rDFA
.mbSymbolFlag
= false; // TODO
2252 rDFA
.mePitch
= PITCH_DONTKNOW
; // TODO
2254 // byte offset 0x4DE: pitch&family
2255 rDFA
.meFamily
= ImplFamilyToSal( aBuffer
[0x4DE] );
2257 // byte offsets 0x4C8/0x4C9: emunits
2258 // byte offsets 0x4CE/0x4CF: winascent
2259 // byte offsets 0x4D0/0x4D1: winascent+windescent-emunits
2260 // byte offsets 0x4DF/0x4E0: avgwidth
2266 // -----------------------------------------------------------------------
2268 bool WinSalGraphics::AddTempDevFont( ImplDevFontList
* pFontList
,
2269 const String
& rFontFileURL
, const String
& rFontName
)
2271 RTL_LOGFILE_TRACE1( "WinSalGraphics::AddTempDevFont(): %s", rtl::OUStringToOString( rFontFileURL
, RTL_TEXTENCODING_UTF8
).getStr() );
2273 ImplDevFontAttributes aDFA
;
2274 aDFA
.maName
= rFontName
;
2275 aDFA
.mnQuality
= 1000;
2276 aDFA
.mbDevice
= true;
2278 // Search Font Name in Cache
2279 if( !rFontName
.Len() && mpFontAttrCache
)
2280 aDFA
= mpFontAttrCache
->GetFontAttr( rFontFileURL
);
2282 // Retrieve font name from font resource
2283 if( !aDFA
.maName
.Len() )
2285 ImplGetFontAttrFromFile( rFontFileURL
, aDFA
);
2286 if( mpFontAttrCache
&& aDFA
.maName
.Len() )
2287 mpFontAttrCache
->AddFontAttr( rFontFileURL
, aDFA
);
2290 if ( !aDFA
.maName
.Len() )
2293 // remember temp font for cleanup later
2294 if( !ImplAddTempFont( *GetSalData(), rFontFileURL
) )
2297 UINT nPreferedCharSet
= DEFAULT_CHARSET
;
2299 // create matching FontData struct
2300 aDFA
.mbSymbolFlag
= false; // TODO: how to know it without accessing the font?
2301 aDFA
.meFamily
= FAMILY_DONTKNOW
;
2302 aDFA
.meWidthType
= WIDTH_DONTKNOW
;
2303 aDFA
.meWeight
= WEIGHT_DONTKNOW
;
2304 aDFA
.meItalic
= ITALIC_DONTKNOW
;
2305 aDFA
.mePitch
= PITCH_DONTKNOW
;;
2306 aDFA
.mbSubsettable
= true;
2307 aDFA
.mbEmbeddable
= false;
2310 // TODO: improve ImplDevFontAttributes using the "font resource file"
2311 aDFS.maName = // using "FONTRES:" from file
2312 if( rFontName != aDFS.maName )
2313 aDFS.maMapName = aFontName;
2316 ImplWinFontData
* pFontData
= new ImplWinFontData( aDFA
, 0,
2317 sal::static_int_cast
<BYTE
>(nPreferedCharSet
),
2318 sal::static_int_cast
<BYTE
>(TMPF_VECTOR
|TMPF_TRUETYPE
) );
2319 pFontData
->SetFontId( reinterpret_cast<sal_IntPtr
>(pFontData
) );
2320 pFontList
->Add( pFontData
);
2324 // -----------------------------------------------------------------------
2326 void WinSalGraphics::GetDevFontList( ImplDevFontList
* pFontList
)
2328 // make sure all fonts are registered at least temporarily
2329 static bool bOnce
= true;
2334 // determine font path
2335 // since we are only interested in fonts that could not be
2336 // registered before because of missing administration rights
2337 // only the font path of the user installation is needed
2338 ::rtl::OUString aPath
;
2339 osl_getExecutableFile( &aPath
.pData
);
2340 ::rtl::OUString
aExecutableFile( aPath
);
2341 aPath
= aPath
.copy( 0, aPath
.lastIndexOf('/') );
2342 String aFontDirUrl
= aPath
.copy( 0, aPath
.lastIndexOf('/') );
2343 aFontDirUrl
+= String( RTL_CONSTASCII_USTRINGPARAM("/Basis/share/fonts/truetype") );
2345 // collect fonts in font path that could not be registered
2346 osl::Directory
aFontDir( aFontDirUrl
);
2347 osl::FileBase::RC rcOSL
= aFontDir
.open();
2348 if( rcOSL
== osl::FileBase::E_None
)
2350 osl::DirectoryItem aDirItem
;
2351 String aEmptyString
;
2353 ::rtl::OUString aBootStrap
;
2354 rtl::Bootstrap::get( String( RTL_CONSTASCII_USTRINGPARAM( "BRAND_BASE_DIR" ) ), aBootStrap
);
2355 aBootStrap
+= String( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
2356 rtl::Bootstrap
aBootstrap( aBootStrap
);
2357 ::rtl::OUString aUserPath
;
2358 aBootstrap
.getFrom( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserInstallation" ) ), aUserPath
);
2359 aUserPath
+= String( RTL_CONSTASCII_USTRINGPARAM("/user/config/fontnames.dat") );
2360 String aBaseURL
= aPath
.copy( 0, aPath
.lastIndexOf('/')+1 );
2361 mpFontAttrCache
= new ImplFontAttrCache( aUserPath
, aBaseURL
);
2363 while( aFontDir
.getNextItem( aDirItem
, 10 ) == osl::FileBase::E_None
)
2365 osl::FileStatus
aFileStatus( FileStatusMask_FileURL
);
2366 rcOSL
= aDirItem
.getFileStatus( aFileStatus
);
2367 if ( rcOSL
== osl::FileBase::E_None
)
2368 AddTempDevFont( pFontList
, aFileStatus
.getFileURL(), aEmptyString
);
2371 delete mpFontAttrCache
; // destructor rewrites the cache file if needed
2372 mpFontAttrCache
= NULL
;
2378 aInfo
.mpList
= pFontList
;
2379 aInfo
.mpName
= NULL
;
2380 aInfo
.mpLogFontA
= NULL
;
2381 aInfo
.mpLogFontW
= NULL
;
2382 aInfo
.mbCourier
= false;
2383 aInfo
.mbPrinter
= mbPrinter
;
2384 aInfo
.mnFontCount
= 0;
2387 aInfo
.mbImplSalCourierScalable
= false;
2388 aInfo
.mbImplSalCourierNew
= false;
2392 aInfo
.mbImplSalCourierScalable
= true;
2393 aInfo
.mbImplSalCourierNew
= true;
2396 aInfo
.mnPreferedCharSet
= DEFAULT_CHARSET
;
2397 DWORD nCP
= GetACP();
2398 CHARSETINFO aCharSetInfo
;
2399 if ( TranslateCharsetInfo( (DWORD
*)nCP
, &aCharSetInfo
, TCI_SRCCODEPAGE
) )
2400 aInfo
.mnPreferedCharSet
= aCharSetInfo
.ciCharset
;
2403 memset( &aLogFont
, 0, sizeof( aLogFont
) );
2404 aLogFont
.lfCharSet
= DEFAULT_CHARSET
;
2405 aInfo
.mpLogFontW
= &aLogFont
;
2406 EnumFontFamiliesExW( mhDC
, &aLogFont
,
2407 (FONTENUMPROCW
)SalEnumFontsProcExW
, (LPARAM
)(void*)&aInfo
, 0 );
2409 // Feststellen, was es fuer Courier-Schriften auf dem Bildschirm gibt,
2410 // um in SetFont() evt. Courier auf Courier New zu mappen
2413 bImplSalCourierScalable
= aInfo
.mbImplSalCourierScalable
;
2414 bImplSalCourierNew
= aInfo
.mbImplSalCourierNew
;
2417 // set glyph fallback hook
2418 static WinGlyphFallbackSubstititution
aSubstFallback( mhDC
);
2419 pFontList
->SetFallbackHook( &aSubstFallback
);
2422 // ----------------------------------------------------------------------------
2424 void WinSalGraphics::GetDevFontSubstList( OutputDevice
* )
2427 // -----------------------------------------------------------------------
2429 sal_Bool
WinSalGraphics::GetGlyphBoundRect( long nIndex
, Rectangle
& rRect
)
2435 aMat
.eM11
= aMat
.eM22
= FixedFromDouble( 1.0 );
2436 aMat
.eM12
= aMat
.eM21
= FixedFromDouble( 0.0 );
2438 UINT nGGOFlags
= GGO_METRICS
;
2439 if( !(nIndex
& GF_ISCHAR
) )
2440 nGGOFlags
|= GGO_GLYPH_INDEX
;
2441 nIndex
&= GF_IDXMASK
;
2444 aGM
.gmptGlyphOrigin
.x
= aGM
.gmptGlyphOrigin
.y
= 0;
2445 aGM
.gmBlackBoxX
= aGM
.gmBlackBoxY
= 0;
2446 DWORD nSize
= ::GetGlyphOutlineW( hDC
, nIndex
, nGGOFlags
, &aGM
, 0, NULL
, &aMat
);
2447 if( nSize
== GDI_ERROR
)
2450 rRect
= Rectangle( Point( +aGM
.gmptGlyphOrigin
.x
, -aGM
.gmptGlyphOrigin
.y
),
2451 Size( aGM
.gmBlackBoxX
, aGM
.gmBlackBoxY
) );
2452 rRect
.Left() = static_cast<int>( mfFontScale
* rRect
.Left() );
2453 rRect
.Right() = static_cast<int>( mfFontScale
* rRect
.Right() );
2454 rRect
.Top() = static_cast<int>( mfFontScale
* rRect
.Top() );
2455 rRect
.Bottom() = static_cast<int>( mfFontScale
* rRect
.Bottom() );
2459 // -----------------------------------------------------------------------
2461 sal_Bool
WinSalGraphics::GetGlyphOutline( long nIndex
,
2462 ::basegfx::B2DPolyPolygon
& rB2DPolyPoly
)
2464 rB2DPolyPoly
.clear();
2470 aMat
.eM11
= aMat
.eM22
= FixedFromDouble( 1.0 );
2471 aMat
.eM12
= aMat
.eM21
= FixedFromDouble( 0.0 );
2473 UINT nGGOFlags
= GGO_NATIVE
;
2474 if( !(nIndex
& GF_ISCHAR
) )
2475 nGGOFlags
|= GGO_GLYPH_INDEX
;
2476 nIndex
&= GF_IDXMASK
;
2478 GLYPHMETRICS aGlyphMetrics
;
2479 const DWORD nSize1
= ::GetGlyphOutlineW( hDC
, nIndex
, nGGOFlags
, &aGlyphMetrics
, 0, NULL
, &aMat
);
2480 if( !nSize1
) // blank glyphs are ok
2482 else if( nSize1
== GDI_ERROR
)
2485 BYTE
* pData
= new BYTE
[ nSize1
];
2486 const DWORD nSize2
= ::GetGlyphOutlineW( hDC
, nIndex
, nGGOFlags
,
2487 &aGlyphMetrics
, nSize1
, pData
, &aMat
);
2489 if( nSize1
!= nSize2
)
2492 // TODO: avoid tools polygon by creating B2DPolygon directly
2494 Point
* pPoints
= new Point
[ nPtSize
];
2495 BYTE
* pFlags
= new BYTE
[ nPtSize
];
2497 TTPOLYGONHEADER
* pHeader
= (TTPOLYGONHEADER
*)pData
;
2498 while( (BYTE
*)pHeader
< pData
+nSize2
)
2500 // only outline data is interesting
2501 if( pHeader
->dwType
!= TT_POLYGON_TYPE
)
2504 // get start point; next start points are end points
2505 // of previous segment
2508 long nX
= IntTimes256FromFixed( pHeader
->pfxStart
.x
);
2509 long nY
= IntTimes256FromFixed( pHeader
->pfxStart
.y
);
2510 pPoints
[ nPnt
] = Point( nX
, nY
);
2511 pFlags
[ nPnt
++ ] = POLY_NORMAL
;
2513 bool bHasOfflinePoints
= false;
2514 TTPOLYCURVE
* pCurve
= (TTPOLYCURVE
*)( pHeader
+ 1 );
2515 pHeader
= (TTPOLYGONHEADER
*)( (BYTE
*)pHeader
+ pHeader
->cb
);
2516 while( (BYTE
*)pCurve
< (BYTE
*)pHeader
)
2518 int nNeededSize
= nPnt
+ 16 + 3 * pCurve
->cpfx
;
2519 if( nPtSize
< nNeededSize
)
2521 Point
* pOldPoints
= pPoints
;
2522 BYTE
* pOldFlags
= pFlags
;
2523 nPtSize
= 2 * nNeededSize
;
2524 pPoints
= new Point
[ nPtSize
];
2525 pFlags
= new BYTE
[ nPtSize
];
2526 for( USHORT i
= 0; i
< nPnt
; ++i
)
2528 pPoints
[ i
] = pOldPoints
[ i
];
2529 pFlags
[ i
] = pOldFlags
[ i
];
2531 delete[] pOldPoints
;
2536 if( TT_PRIM_LINE
== pCurve
->wType
)
2538 while( i
< pCurve
->cpfx
)
2540 nX
= IntTimes256FromFixed( pCurve
->apfx
[ i
].x
);
2541 nY
= IntTimes256FromFixed( pCurve
->apfx
[ i
].y
);
2543 pPoints
[ nPnt
] = Point( nX
, nY
);
2544 pFlags
[ nPnt
] = POLY_NORMAL
;
2548 else if( TT_PRIM_QSPLINE
== pCurve
->wType
)
2550 bHasOfflinePoints
= true;
2551 while( i
< pCurve
->cpfx
)
2553 // get control point of quadratic bezier spline
2554 nX
= IntTimes256FromFixed( pCurve
->apfx
[ i
].x
);
2555 nY
= IntTimes256FromFixed( pCurve
->apfx
[ i
].y
);
2557 Point
aControlP( nX
, nY
);
2559 // calculate first cubic control point
2560 // P0 = 1/3 * (PBeg + 2 * PQControl)
2561 nX
= pPoints
[ nPnt
-1 ].X() + 2 * aControlP
.X();
2562 nY
= pPoints
[ nPnt
-1 ].Y() + 2 * aControlP
.Y();
2563 pPoints
[ nPnt
+0 ] = Point( (2*nX
+3)/6, (2*nY
+3)/6 );
2564 pFlags
[ nPnt
+0 ] = POLY_CONTROL
;
2566 // calculate endpoint of segment
2567 nX
= IntTimes256FromFixed( pCurve
->apfx
[ i
].x
);
2568 nY
= IntTimes256FromFixed( pCurve
->apfx
[ i
].y
);
2570 if ( i
+1 >= pCurve
->cpfx
)
2572 // endpoint is either last point in segment => advance
2577 // or endpoint is the middle of two control points
2578 nX
+= IntTimes256FromFixed( pCurve
->apfx
[ i
-1 ].x
);
2579 nY
+= IntTimes256FromFixed( pCurve
->apfx
[ i
-1 ].y
);
2582 // no need to advance, because the current point
2583 // is the control point in next bezier spline
2586 pPoints
[ nPnt
+2 ] = Point( nX
, nY
);
2587 pFlags
[ nPnt
+2 ] = POLY_NORMAL
;
2589 // calculate second cubic control point
2590 // P1 = 1/3 * (PEnd + 2 * PQControl)
2591 nX
= pPoints
[ nPnt
+2 ].X() + 2 * aControlP
.X();
2592 nY
= pPoints
[ nPnt
+2 ].Y() + 2 * aControlP
.Y();
2593 pPoints
[ nPnt
+1 ] = Point( (2*nX
+3)/6, (2*nY
+3)/6 );
2594 pFlags
[ nPnt
+1 ] = POLY_CONTROL
;
2600 // next curve segment
2601 pCurve
= (TTPOLYCURVE
*)&pCurve
->apfx
[ i
];
2604 // end point is start point for closed contour
2605 // disabled, because Polygon class closes the contour itself
2606 // pPoints[nPnt++] = pPoints[0];
2608 // Added again, but add only when not yet closed
2609 if(pPoints
[nPnt
- 1] != pPoints
[0])
2611 if( bHasOfflinePoints
)
2612 pFlags
[nPnt
] = pFlags
[0];
2614 pPoints
[nPnt
++] = pPoints
[0];
2617 // convert y-coordinates W32 -> VCL
2618 for( int i
= 0; i
< nPnt
; ++i
)
2619 pPoints
[i
].Y() = -pPoints
[i
].Y();
2621 // insert into polypolygon
2622 Polygon
aPoly( nPnt
, pPoints
, (bHasOfflinePoints
? pFlags
: NULL
) );
2623 // convert to B2DPolyPolygon
2624 // TODO: get rid of the intermediate PolyPolygon
2625 rB2DPolyPoly
.append( aPoly
.getB2DPolygon() );
2633 // rescaling needed for the PolyPolygon conversion
2634 if( rB2DPolyPoly
.count() )
2636 const double fFactor(mfFontScale
/256);
2637 rB2DPolyPoly
.transform(basegfx::tools::createScaleB2DHomMatrix(fFactor
, fFactor
));
2643 // -----------------------------------------------------------------------
2648 explicit ScopedFont(WinSalGraphics
& rData
);
2653 WinSalGraphics
& m_rData
;
2657 ScopedFont::ScopedFont(WinSalGraphics
& rData
): m_rData(rData
)
2659 m_hOrigFont
= m_rData
.mhFonts
[0];
2660 m_rData
.mhFonts
[0] = 0; // avoid deletion of current font
2663 ScopedFont::~ScopedFont()
2667 // restore original font, destroy temporary font
2668 HFONT hTempFont
= m_rData
.mhFonts
[0];
2669 m_rData
.mhFonts
[0] = m_hOrigFont
;
2670 SelectObject( m_rData
.mhDC
, m_hOrigFont
);
2671 DeleteObject( hTempFont
);
2675 class ScopedTrueTypeFont
2678 inline ScopedTrueTypeFont(): m_pFont(0) {}
2680 ~ScopedTrueTypeFont();
2682 int open(void * pBuffer
, sal_uInt32 nLen
, sal_uInt32 nFaceNum
);
2684 inline TrueTypeFont
* get() const { return m_pFont
; }
2687 TrueTypeFont
* m_pFont
;
2690 ScopedTrueTypeFont::~ScopedTrueTypeFont()
2693 CloseTTFont(m_pFont
);
2696 int ScopedTrueTypeFont::open(void * pBuffer
, sal_uInt32 nLen
,
2697 sal_uInt32 nFaceNum
)
2699 OSL_ENSURE(m_pFont
== 0, "already open");
2700 return OpenTTFontBuffer(pBuffer
, nLen
, nFaceNum
, &m_pFont
);
2703 sal_Bool
WinSalGraphics::CreateFontSubset( const rtl::OUString
& rToFile
,
2704 const ImplFontData
* pFont
, long* pGlyphIDs
, sal_uInt8
* pEncoding
,
2705 sal_Int32
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& rInfo
)
2707 // TODO: use more of the central font-subsetting code, move stuff there if needed
2709 // create matching ImplFontSelectData
2710 // we need just enough to get to the font file data
2711 // use height=1000 for easier debugging (to match psprint's font units)
2712 ImplFontSelectData
aIFSD( *pFont
, Size(0,1000), 1000.0, 0, false );
2714 // TODO: much better solution: move SetFont and restoration of old font to caller
2715 ScopedFont
aOldFont(*this);
2718 ImplDoSetFont( &aIFSD
, fScale
, hOldFont
);
2720 ImplWinFontData
* pWinFontData
= (ImplWinFontData
*)aIFSD
.mpFontData
;
2722 #if OSL_DEBUG_LEVEL > 1
2724 TEXTMETRICA aWinMetric
;
2725 if( !::GetTextMetricsA( mhDC
, &aWinMetric
) )
2728 DBG_ASSERT( !(aWinMetric
.tmPitchAndFamily
& TMPF_DEVICE
), "cannot subset device font" );
2729 DBG_ASSERT( aWinMetric
.tmPitchAndFamily
& TMPF_TRUETYPE
, "can only subset TT font" );
2732 rtl::OUString aSysPath
;
2733 if( osl_File_E_None
!= osl_getSystemPathFromFileURL( rToFile
.pData
, &aSysPath
.pData
) )
2735 const rtl_TextEncoding aThreadEncoding
= osl_getThreadTextEncoding();
2736 const ByteString
aToFile( aSysPath
.getStr(), (xub_StrLen
)aSysPath
.getLength(), aThreadEncoding
);
2738 // check if the font has a CFF-table
2739 const DWORD nCffTag
= CalcTag( "CFF " );
2740 const RawFontData
aRawCffData( mhDC
, nCffTag
);
2741 if( aRawCffData
.get() )
2743 pWinFontData
->UpdateFromHDC( mhDC
);
2744 const ImplFontCharMap
* pCharMap
= pWinFontData
->GetImplFontCharMap();
2745 pCharMap
->AddReference();
2747 long nRealGlyphIds
[ 256 ];
2748 for( int i
= 0; i
< nGlyphCount
; ++i
)
2750 // TODO: remap notdef glyph if needed
2751 // TODO: use GDI's GetGlyphIndices instead? Does it handle GSUB properly?
2752 sal_uInt32 nGlyphIdx
= pGlyphIDs
[i
] & GF_IDXMASK
;
2753 if( pGlyphIDs
[i
] & GF_ISCHAR
) // remaining pseudo-glyphs need to be translated
2754 nGlyphIdx
= pCharMap
->GetGlyphIndex( nGlyphIdx
);
2755 if( (pGlyphIDs
[i
] & (GF_ROTMASK
|GF_GSUB
)) != 0) // TODO: vertical substitution
2758 nRealGlyphIds
[i
] = nGlyphIdx
;
2761 pCharMap
->DeReference(); // TODO: and and use a RAII object
2763 // provide a font subset from the CFF-table
2764 FILE* pOutFile
= fopen( aToFile
.GetBuffer(), "wb" );
2765 rInfo
.LoadFont( FontSubsetInfo::CFF_FONT
, aRawCffData
.get(), aRawCffData
.size() );
2766 bool bRC
= rInfo
.CreateFontSubset( FontSubsetInfo::TYPE1_PFB
, pOutFile
, NULL
,
2767 nRealGlyphIds
, pEncoding
, nGlyphCount
, pGlyphWidths
);
2772 // get raw font file data
2773 const RawFontData
xRawFontData( mhDC
, NULL
);
2774 if( !xRawFontData
.get() )
2778 sal_uInt32 nFaceNum
= 0;
2779 if( !*xRawFontData
.get() ) // TTC candidate
2780 nFaceNum
= ~0U; // indicate "TTC font extracts only"
2782 ScopedTrueTypeFont aSftTTF
;
2783 int nRC
= aSftTTF
.open( (void*)xRawFontData
.get(), xRawFontData
.size(), nFaceNum
);
2787 TTGlobalFontInfo aTTInfo
;
2788 ::GetTTGlobalFontInfo( aSftTTF
.get(), &aTTInfo
);
2789 rInfo
.m_nFontType
= FontSubsetInfo::SFNT_TTF
;
2790 rInfo
.m_aPSName
= ImplSalGetUniString( aTTInfo
.psname
);
2791 rInfo
.m_nAscent
= +aTTInfo
.winAscent
;
2792 rInfo
.m_nDescent
= -aTTInfo
.winDescent
;
2793 rInfo
.m_aFontBBox
= Rectangle( Point( aTTInfo
.xMin
, aTTInfo
.yMin
),
2794 Point( aTTInfo
.xMax
, aTTInfo
.yMax
) );
2795 rInfo
.m_nCapHeight
= aTTInfo
.yMax
; // Well ...
2797 // subset TTF-glyphs and get their properties
2798 // take care that subset fonts require the NotDef glyph in pos 0
2799 int nOrigCount
= nGlyphCount
;
2800 sal_uInt16 aShortIDs
[ 256 ];
2801 sal_uInt8 aTempEncs
[ 256 ];
2804 for( i
= 0; i
< nGlyphCount
; ++i
)
2806 aTempEncs
[i
] = pEncoding
[i
];
2807 sal_uInt32 nGlyphIdx
= pGlyphIDs
[i
] & GF_IDXMASK
;
2808 if( pGlyphIDs
[i
] & GF_ISCHAR
)
2810 sal_Unicode cChar
= static_cast<sal_Unicode
>(nGlyphIdx
); // TODO: sal_UCS4
2811 const bool bVertical
= ((pGlyphIDs
[i
] & (GF_ROTMASK
|GF_GSUB
)) != 0);
2812 nGlyphIdx
= ::MapChar( aSftTTF
.get(), cChar
, bVertical
);
2813 if( (nGlyphIdx
== 0) && pFont
->IsSymbolFont() )
2815 // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
2816 cChar
= (cChar
& 0xF000) ? (cChar
& 0x00FF) : (cChar
| 0xF000);
2817 nGlyphIdx
= ::MapChar( aSftTTF
.get(), cChar
, bVertical
);
2820 aShortIDs
[i
] = static_cast<sal_uInt16
>( nGlyphIdx
);
2823 nNotDef
= i
; // first NotDef glyph found
2828 // add fake NotDef glyph if needed
2830 nNotDef
= nGlyphCount
++;
2832 // NotDef glyph must be in pos 0 => swap glyphids
2833 aShortIDs
[ nNotDef
] = aShortIDs
[0];
2834 aTempEncs
[ nNotDef
] = aTempEncs
[0];
2838 DBG_ASSERT( nGlyphCount
< 257, "too many glyphs for subsetting" );
2840 // fill pWidth array
2841 TTSimpleGlyphMetrics
* pMetrics
=
2842 ::GetTTSimpleGlyphMetrics( aSftTTF
.get(), aShortIDs
, nGlyphCount
, aIFSD
.mbVertical
);
2845 sal_uInt16 nNotDefAdv
= pMetrics
[0].adv
;
2846 pMetrics
[0].adv
= pMetrics
[nNotDef
].adv
;
2847 pMetrics
[nNotDef
].adv
= nNotDefAdv
;
2848 for( i
= 0; i
< nOrigCount
; ++i
)
2849 pGlyphWidths
[i
] = pMetrics
[i
].adv
;
2852 // write subset into destination file
2853 nRC
= ::CreateTTFromTTGlyphs( aSftTTF
.get(), aToFile
.GetBuffer(), aShortIDs
,
2854 aTempEncs
, nGlyphCount
, 0, NULL
, 0 );
2855 return (nRC
== SF_OK
);
2858 //--------------------------------------------------------------------------
2860 const void* WinSalGraphics::GetEmbedFontData( const ImplFontData
* pFont
,
2861 const sal_Unicode
* pUnicodes
, sal_Int32
* pCharWidths
,
2862 FontSubsetInfo
& rInfo
, long* pDataLen
)
2864 // create matching ImplFontSelectData
2865 // we need just enough to get to the font file data
2866 ImplFontSelectData
aIFSD( *pFont
, Size(0,1000), 1000.0, 0, false );
2868 // TODO: much better solution: move SetFont and restoration of old font to caller
2869 ScopedFont
aOldFont(*this);
2870 SetFont( &aIFSD
, 0 );
2872 // get the raw font file data
2873 RawFontData
aRawFontData( mhDC
);
2874 *pDataLen
= aRawFontData
.size();
2875 if( !aRawFontData
.get() )
2878 // get important font properties
2880 if( !::GetTextMetricsA( mhDC
, &aTm
) )
2882 const bool bPFA
= (*aRawFontData
.get() < 0x80);
2883 rInfo
.m_nFontType
= bPFA
? FontSubsetInfo::TYPE1_PFA
: FontSubsetInfo::TYPE1_PFB
;
2884 WCHAR aFaceName
[64];
2885 int nFNLen
= ::GetTextFaceW( mhDC
, 64, aFaceName
);
2886 // #i59854# strip eventual null byte
2887 while( nFNLen
> 0 && aFaceName
[nFNLen
-1] == 0 )
2891 rInfo
.m_aPSName
= String( reinterpret_cast<const sal_Unicode
*>(aFaceName
), sal::static_int_cast
<sal_uInt16
>(nFNLen
) );
2892 rInfo
.m_nAscent
= +aTm
.tmAscent
;
2893 rInfo
.m_nDescent
= -aTm
.tmDescent
;
2894 rInfo
.m_aFontBBox
= Rectangle( Point( -aTm
.tmOverhang
, -aTm
.tmDescent
),
2895 Point( aTm
.tmMaxCharWidth
, aTm
.tmAscent
+aTm
.tmExternalLeading
) );
2896 rInfo
.m_nCapHeight
= aTm
.tmAscent
; // Well ...
2898 // get individual character widths
2899 for( int i
= 0; i
< 256; ++i
)
2902 const sal_Unicode cChar
= pUnicodes
[i
];
2903 if( !::GetCharWidth32W( mhDC
, cChar
, cChar
, &nCharWidth
) )
2905 pCharWidths
[i
] = nCharWidth
;
2911 const unsigned char* pData
= aRawFontData
.steal();
2912 return (void*)pData
;
2915 //--------------------------------------------------------------------------
2917 void WinSalGraphics::FreeEmbedFontData( const void* pData
, long /*nLen*/ )
2919 delete[] reinterpret_cast<char*>(const_cast<void*>(pData
));
2922 //--------------------------------------------------------------------------
2924 const Ucs2SIntMap
* WinSalGraphics::GetFontEncodingVector( const ImplFontData
* pFont
, const Ucs2OStrMap
** pNonEncoded
)
2926 // TODO: even for builtin fonts we get here... why?
2927 if( !pFont
->IsEmbeddable() )
2930 // fill the encoding vector
2931 // currently no nonencoded vector
2933 *pNonEncoded
= NULL
;
2935 const ImplWinFontData
* pWinFontData
= static_cast<const ImplWinFontData
*>(pFont
);
2936 const Ucs2SIntMap
* pEncoding
= pWinFontData
->GetEncodingVector();
2937 if( pEncoding
== NULL
)
2939 Ucs2SIntMap
* pNewEncoding
= new Ucs2SIntMap
;
2941 // TODO: get correct encoding vector
2943 aGlyphSet
.cbThis
= sizeof(aGlyphSet
);
2944 DWORD aW
= ::GetFontUnicodeRanges( mhDC
, &aGlyphSet
);
2946 for( sal_Unicode i
= 32; i
< 256; ++i
)
2947 (*pNewEncoding
)[i
] = i
;
2949 pWinFontData
->SetEncodingVector( pNewEncoding
);
2950 pEncoding
= pNewEncoding
;
2956 //--------------------------------------------------------------------------
2958 void WinSalGraphics::GetGlyphWidths( const ImplFontData
* pFont
,
2960 Int32Vector
& rWidths
,
2961 Ucs2UIntMap
& rUnicodeEnc
)
2963 // create matching ImplFontSelectData
2964 // we need just enough to get to the font file data
2965 ImplFontSelectData
aIFSD( *pFont
, Size(0,1000), 1000.0, 0, false );
2967 // TODO: much better solution: move SetFont and restoration of old font to caller
2968 ScopedFont
aOldFont(*this);
2972 ImplDoSetFont( &aIFSD
, fScale
, hOldFont
);
2974 if( pFont
->IsSubsettable() )
2976 // get raw font file data
2977 const RawFontData
xRawFontData( mhDC
);
2978 if( !xRawFontData
.get() )
2982 sal_uInt32 nFaceNum
= 0;
2983 if( !*xRawFontData
.get() ) // TTC candidate
2984 nFaceNum
= ~0U; // indicate "TTC font extracts only"
2986 ScopedTrueTypeFont aSftTTF
;
2987 int nRC
= aSftTTF
.open( (void*)xRawFontData
.get(), xRawFontData
.size(), nFaceNum
);
2991 int nGlyphs
= GetTTGlyphCount( aSftTTF
.get() );
2994 rWidths
.resize(nGlyphs
);
2995 std::vector
<sal_uInt16
> aGlyphIds(nGlyphs
);
2996 for( int i
= 0; i
< nGlyphs
; i
++ )
2997 aGlyphIds
[i
] = sal_uInt16(i
);
2998 TTSimpleGlyphMetrics
* pMetrics
= ::GetTTSimpleGlyphMetrics( aSftTTF
.get(),
3001 bVertical
? 1 : 0 );
3004 for( int i
= 0; i
< nGlyphs
; i
++ )
3005 rWidths
[i
] = pMetrics
[i
].adv
;
3007 rUnicodeEnc
.clear();
3009 const ImplWinFontData
* pWinFont
= static_cast<const ImplWinFontData
*>(pFont
);
3010 const ImplFontCharMap
* pMap
= pWinFont
->GetImplFontCharMap();
3011 DBG_ASSERT( pMap
&& pMap
->GetCharCount(), "no map" );
3012 pMap
->AddReference();
3014 int nCharCount
= pMap
->GetCharCount();
3015 sal_uInt32 nChar
= pMap
->GetFirstChar();
3016 for( int i
= 0; i
< nCharCount
; i
++ )
3018 if( nChar
< 0x00010000 )
3020 sal_uInt16 nGlyph
= ::MapChar( aSftTTF
.get(),
3021 static_cast<sal_Ucs
>(nChar
),
3022 bVertical
? 1 : 0 );
3024 rUnicodeEnc
[ static_cast<sal_Unicode
>(nChar
) ] = nGlyph
;
3026 nChar
= pMap
->GetNextChar( nChar
);
3029 pMap
->DeReference(); // TODO: and and use a RAII object
3032 else if( pFont
->IsEmbeddable() )
3034 // get individual character widths
3036 rUnicodeEnc
.clear();
3037 rWidths
.reserve( 224 );
3038 for( sal_Unicode i
= 32; i
< 256; ++i
)
3041 if( ::GetCharWidth32W( mhDC
, i
, i
, &nCharWidth
) )
3043 rUnicodeEnc
[ i
] = rWidths
.size();
3044 rWidths
.push_back( nCharWidth
);
3050 //--------------------------------------------------------------------------
3052 void WinSalGraphics::DrawServerFontLayout( const ServerFontLayout
& )
3055 //--------------------------------------------------------------------------
3057 SystemFontData
WinSalGraphics::GetSysFontData( int nFallbacklevel
) const
3059 SystemFontData aSysFontData
;
3061 if (nFallbacklevel
>= MAX_FALLBACK
) nFallbacklevel
= MAX_FALLBACK
- 1;
3062 if (nFallbacklevel
< 0 ) nFallbacklevel
= 0;
3064 aSysFontData
.nSize
= sizeof( SystemFontData
);
3065 aSysFontData
.hFont
= mhFonts
[nFallbacklevel
];
3066 aSysFontData
.bFakeBold
= false;
3067 aSysFontData
.bFakeItalic
= false;
3068 aSysFontData
.bAntialias
= true;
3069 aSysFontData
.bVerticalCharacterType
= false;
3071 OSL_TRACE("\r\n:WinSalGraphics::GetSysFontData(): FontID: %p, Fallback level: %d",
3075 return aSysFontData
;
3078 //--------------------------------------------------------------------------