1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26
27 #include <string.h>
28 #include <malloc.h>
29
30 #include "rtl/logfile.hxx"
31 #include "rtl/tencinfo.h"
32 #include "rtl/textcvt.h"
33 #include "rtl/bootstrap.hxx"
34
35 #include "i18npool/mslangid.hxx"
36
37 #include "osl/module.h"
38 #include "osl/file.hxx"
39 #include "osl/thread.hxx"
40 #include "osl/process.h"
41
42 #include "basegfx/polygon/b2dpolygon.hxx"
43 #include "basegfx/polygon/b2dpolypolygon.hxx"
44 #include "basegfx/matrix/b2dhommatrix.hxx"
45 #include "basegfx/matrix/b2dhommatrixtools.hxx"
46
47 #include "unotools/fontcfg.hxx" // for IMPL_FONT_ATTR_SYMBOL
48
49 #include "vcl/font.hxx"
50 #include "vcl/svapp.hxx"
51
52 #include "tools/poly.hxx"
53 #include "tools/debug.hxx"
54 #include "tools/stream.hxx"
55
56 #include <tools/prewin.h>
57 #include <windows.h>
58 #include <tools/postwin.h>
59
60 #include <vcl/sysdata.hxx>
61
62 #include "win/wincomp.hxx"
63 #include "win/saldata.hxx"
64 #include "win/salgdi.h"
65
66 #include "outfont.hxx"
67 #include "fontsubset.hxx"
68 #include "sallayout.hxx"
69 #include "outdev.h" // for ImplGlyphFallbackFontSubstitution
70 #include "sft.hxx"
71
72 #ifdef GCP_KERN_HACK
73 #include <algorithm>
74 #endif
75
76 #ifdef ENABLE_GRAPHITE
77 #include <graphite/GrClient.h>
78 #include <graphite/WinFont.h>
79 #endif
80
81 #include <vector>
82 #include <set>
83 #include <map>
84
85 using namespace vcl;
86
87 static const int MAXFONTHEIGHT = 2048;
88
89 // -----------
90 // - Inlines -
91 // -----------
92
FixedFromDouble(double d)93 inline FIXED FixedFromDouble( double d )
94 {
95 const long l = (long) ( d * 65536. );
96 return *(FIXED*) &l;
97 }
98
99 // -----------------------------------------------------------------------
100
IntTimes256FromFixed(FIXED f)101 inline int IntTimes256FromFixed(FIXED f)
102 {
103 int nFixedTimes256 = (f.value << 8) + ((f.fract+0x80) >> 8);
104 return nFixedTimes256;
105 }
106
107 // =======================================================================
108
109 // these variables can be static because they store system wide settings
110 static bool bImplSalCourierScalable = false;
111 static bool bImplSalCourierNew = false;
112
113
114 // =======================================================================
115
116 // -----------------------------------------------------------------------
117
118 // TODO: also support temporary TTC font files
119 typedef std::map< String, ImplDevFontAttributes > FontAttrMap;
120
121 class ImplFontAttrCache
122 {
123 private:
124 FontAttrMap aFontAttributes;
125 rtl::OUString aCacheFileName;
126 String aBaseURL;
127 sal_Bool bModified;
128
129 protected:
130 String OptimizeURL( const String& rURL ) const;
131
132 enum{ MAGIC = 0x12349876 }; // change if fontattrcache format changes
133
134 public:
135 ImplFontAttrCache( const String& rCacheFileName, const String& rBaseURL );
136 ~ImplFontAttrCache();
137
138 ImplDevFontAttributes GetFontAttr( const String& rFontFileName ) const;
139 void AddFontAttr( const String& rFontFileName, const ImplDevFontAttributes& );
140 };
141
ImplFontAttrCache(const String & rFileNameURL,const String & rBaseURL)142 ImplFontAttrCache::ImplFontAttrCache( const String& rFileNameURL, const String& rBaseURL ) : aBaseURL( rBaseURL )
143 {
144 bModified = FALSE;
145 aBaseURL.ToLowerAscii(); // Windows only, no problem...
146
147 // open the cache file
148 osl::FileBase::getSystemPathFromFileURL( rFileNameURL, aCacheFileName );
149 SvFileStream aCacheFile( aCacheFileName, STREAM_READ );
150 if( !aCacheFile.IsOpen() )
151 return;
152
153 // check the cache version
154 sal_uInt32 nCacheMagic;
155 aCacheFile >> nCacheMagic;
156 if( nCacheMagic != ImplFontAttrCache::MAGIC )
157 return; // ignore cache and rewrite if no match
158
159 // read the cache entries from the file
160 String aFontFileURL, aFontName;
161 ImplDevFontAttributes aDFA;
162 for(;;)
163 {
164 aCacheFile.ReadByteString( aFontFileURL, RTL_TEXTENCODING_UTF8 );
165 if( !aFontFileURL.Len() )
166 break;
167 aCacheFile.ReadByteString( aDFA.maName, RTL_TEXTENCODING_UTF8 );
168
169 short n;
170 aCacheFile >> n; aDFA.meWeight = static_cast<FontWeight>(n);
171 aCacheFile >> n; aDFA.meItalic = static_cast<FontItalic>(n);
172 aCacheFile >> n; aDFA.mePitch = static_cast<FontPitch>(n);
173 aCacheFile >> n; aDFA.meWidthType = static_cast<FontWidth>(n);
174 aCacheFile >> n; aDFA.meFamily = static_cast<FontFamily>(n);
175 aCacheFile >> n; aDFA.mbSymbolFlag = (n != 0);
176
177 aCacheFile.ReadByteStringLine( aDFA.maStyleName, RTL_TEXTENCODING_UTF8 );
178
179 aFontAttributes[ aFontFileURL ] = aDFA;
180 }
181 }
182
~ImplFontAttrCache()183 ImplFontAttrCache::~ImplFontAttrCache()
184 {
185 if ( bModified )
186 {
187 SvFileStream aCacheFile( aCacheFileName, STREAM_WRITE|STREAM_TRUNC );
188 if ( aCacheFile.IsWritable() )
189 {
190 sal_uInt32 nCacheMagic = ImplFontAttrCache::MAGIC;
191 aCacheFile << nCacheMagic;
192
193 // write the cache entries to the file
194 FontAttrMap::const_iterator aIter = aFontAttributes.begin();
195 while ( aIter != aFontAttributes.end() )
196 {
197 const String rFontFileURL( (*aIter).first );
198 const ImplDevFontAttributes& rDFA( (*aIter).second );
199 aCacheFile.WriteByteString( rFontFileURL, RTL_TEXTENCODING_UTF8 );
200 aCacheFile.WriteByteString( rDFA.maName, RTL_TEXTENCODING_UTF8 );
201
202 aCacheFile << static_cast<short>(rDFA.meWeight);
203 aCacheFile << static_cast<short>(rDFA.meItalic);
204 aCacheFile << static_cast<short>(rDFA.mePitch);
205 aCacheFile << static_cast<short>(rDFA.meWidthType);
206 aCacheFile << static_cast<short>(rDFA.meFamily);
207 aCacheFile << static_cast<short>(rDFA.mbSymbolFlag != false);
208
209 aCacheFile.WriteByteStringLine( rDFA.maStyleName, RTL_TEXTENCODING_UTF8 );
210
211 aIter++;
212 }
213 // EOF Marker
214 String aEmptyStr;
215 aCacheFile.WriteByteString( aEmptyStr, RTL_TEXTENCODING_UTF8 );
216 }
217 }
218 }
219
OptimizeURL(const String & rURL) const220 String ImplFontAttrCache::OptimizeURL( const String& rURL ) const
221 {
222 String aOptimizedFontFileURL( rURL );
223 aOptimizedFontFileURL.ToLowerAscii(); // Windows only, no problem...
224 if ( aOptimizedFontFileURL.CompareTo( aBaseURL, aBaseURL.Len() ) == COMPARE_EQUAL )
225 aOptimizedFontFileURL = aOptimizedFontFileURL.Copy( aBaseURL.Len() );
226 return aOptimizedFontFileURL;
227 }
228
GetFontAttr(const String & rFontFileName) const229 ImplDevFontAttributes ImplFontAttrCache::GetFontAttr( const String& rFontFileName ) const
230 {
231 ImplDevFontAttributes aDFA;
232 FontAttrMap::const_iterator it = aFontAttributes.find( OptimizeURL( rFontFileName ) );
233 if( it != aFontAttributes.end() )
234 {
235 aDFA = it->second;
236 }
237 return aDFA;
238 }
239
AddFontAttr(const String & rFontFileName,const ImplDevFontAttributes & rDFA)240 void ImplFontAttrCache::AddFontAttr( const String& rFontFileName, const ImplDevFontAttributes& rDFA )
241 {
242 DBG_ASSERT( rFontFileName.Len() && rDFA.maName.Len(), "ImplFontNameCache::AddFontName - invalid data!" );
243 if ( rFontFileName.Len() && rDFA.maName.Len() )
244 {
245 aFontAttributes.insert( FontAttrMap::value_type( OptimizeURL( rFontFileName ), rDFA ) );
246 bModified = TRUE;
247 }
248 }
249
250 // =======================================================================
251
252 // raw font data with a scoped lifetime
253 class RawFontData
254 {
255 public:
256 explicit RawFontData( HDC, DWORD nTableTag=0 );
~RawFontData()257 ~RawFontData() { delete[] mpRawBytes; }
get() const258 const unsigned char* get() const { return mpRawBytes; }
steal()259 const unsigned char* steal() { unsigned char* p = mpRawBytes; mpRawBytes = NULL; return p; }
size() const260 const int size() const { return mnByteCount; }
261
262 private:
263 unsigned char* mpRawBytes;
264 int mnByteCount;
265 };
266
RawFontData(HDC hDC,DWORD nTableTag)267 RawFontData::RawFontData( HDC hDC, DWORD nTableTag )
268 : mpRawBytes( NULL )
269 , mnByteCount( 0 )
270 {
271 // get required size in bytes
272 mnByteCount = ::GetFontData( hDC, nTableTag, 0, NULL, 0 );
273 if( mnByteCount == GDI_ERROR )
274 return;
275 else if( !mnByteCount )
276 return;
277
278 // allocate the array
279 mpRawBytes = new unsigned char[ mnByteCount ];
280
281 // get raw data in chunks small enough for GetFontData()
282 int nRawDataOfs = 0;
283 DWORD nMaxChunkSize = 0x100000;
284 for(;;)
285 {
286 // calculate remaining raw data to get
287 DWORD nFDGet = mnByteCount - nRawDataOfs;
288 if( nFDGet <= 0 )
289 break;
290 // #i56745# limit GetFontData requests
291 if( nFDGet > nMaxChunkSize )
292 nFDGet = nMaxChunkSize;
293 const DWORD nFDGot = ::GetFontData( hDC, nTableTag, nRawDataOfs,
294 (void*)(mpRawBytes + nRawDataOfs), nFDGet );
295 if( !nFDGot )
296 break;
297 else if( nFDGot != GDI_ERROR )
298 nRawDataOfs += nFDGot;
299 else
300 {
301 // was the chunk too big? reduce it
302 nMaxChunkSize /= 2;
303 if( nMaxChunkSize < 0x10000 )
304 break;
305 }
306 }
307
308 // cleanup if the raw data is incomplete
309 if( nRawDataOfs != mnByteCount )
310 {
311 delete[] mpRawBytes;
312 mpRawBytes = NULL;
313 }
314 }
315
316 // ===========================================================================
317 // platform specific font substitution hooks for glyph fallback enhancement
318 // TODO: move into i18n module (maybe merge with svx/ucsubset.*
319 // or merge with i18nutil/source/utility/unicode_data.h)
320 struct Unicode2LangType
321 {
322 sal_UCS4 mnMinCode;
323 sal_UCS4 mnMaxCode;
324 LanguageType mnLangID;
325 };
326
327 // entries marked with default-CJK get replaced with the default-CJK language
328 #define LANGUAGE_DEFAULT_CJK 0xFFF0
329
330 // map unicode ranges to languages supported by OOo
331 // NOTE: due to the binary search used this list must be sorted by mnMinCode
332 static Unicode2LangType aLangFromCodeChart[]= {
333 {0x0000, 0x007F, LANGUAGE_ENGLISH}, // Basic Latin
334 {0x0080, 0x024F, LANGUAGE_ENGLISH}, // Latin Extended-A and Latin Extended-B
335 {0x0250, 0x02AF, LANGUAGE_SYSTEM}, // IPA Extensions
336 {0x0370, 0x03FF, LANGUAGE_GREEK}, // Greek
337 {0x0590, 0x05FF, LANGUAGE_HEBREW}, // Hebrew
338 {0x0600, 0x06FF, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic
339 {0x0900, 0x097F, LANGUAGE_HINDI}, // Devanagari
340 {0x0980, 0x09FF, LANGUAGE_BENGALI}, // Bengali
341 {0x0A80, 0x0AFF, LANGUAGE_GUJARATI}, // Gujarati
342 {0x0B00, 0x0B7F, LANGUAGE_ORIYA}, // Oriya
343 {0x0B80, 0x0BFF, LANGUAGE_TAMIL}, // Tamil
344 {0x0C00, 0x0C7F, LANGUAGE_TELUGU}, // Telugu
345 {0x0C80, 0x0CFF, LANGUAGE_KANNADA}, // Kannada
346 {0x0D00, 0x0D7F, LANGUAGE_MALAYALAM}, // Malayalam
347 {0x0D80, 0x0D7F, LANGUAGE_SINHALESE_SRI_LANKA}, // Sinhala
348 {0x0E00, 0x0E7F, LANGUAGE_THAI}, // Thai
349 {0x0E80, 0x0EFF, LANGUAGE_LAO}, // Lao
350 {0x0F00, 0x0FFF, LANGUAGE_TIBETAN}, // Tibetan
351 {0x1000, 0x109F, LANGUAGE_BURMESE}, // Burmese
352 {0x10A0, 0x10FF, LANGUAGE_GEORGIAN}, // Georgian
353 {0x1100, 0x11FF, LANGUAGE_KOREAN}, // Hangul Jamo, Korean-specific
354 // {0x1200, 0x139F, LANGUAGE_AMHARIC_ETHIOPIA}, // Ethiopic
355 // {0x1200, 0x139F, LANGUAGE_TIGRIGNA_ETHIOPIA}, // Ethiopic
356 {0x13A0, 0x13FF, LANGUAGE_CHEROKEE_UNITED_STATES}, // Cherokee
357 // {0x1400, 0x167F, LANGUAGE_CANADIAN_ABORIGINAL}, // Canadian Aboriginial Syllabics
358 // {0x1680, 0x169F, LANGUAGE_OGHAM}, // Ogham
359 // {0x16A0, 0x16F0, LANGUAGE_RUNIC}, // Runic
360 // {0x1700, 0x171F, LANGUAGE_TAGALOG}, // Tagalog
361 // {0x1720, 0x173F, LANGUAGE_HANUNOO}, // Hanunoo
362 // {0x1740, 0x175F, LANGUAGE_BUHID}, // Buhid
363 // {0x1760, 0x177F, LANGUAGE_TAGBANWA}, // Tagbanwa
364 {0x1780, 0x17FF, LANGUAGE_KHMER}, // Khmer
365 {0x18A0, 0x18AF, LANGUAGE_MONGOLIAN}, // Mongolian
366 // {0x1900, 0x194F, LANGUAGE_LIMBU}, // Limbu
367 // {0x1950, 0x197F, LANGUAGE_TAILE}, // Tai Le
368 // {0x1980, 0x19DF, LANGUAGE_TAILUE}, // Tai Lue
369 {0x19E0, 0x19FF, LANGUAGE_KHMER}, // Khmer Symbols
370 // {0x1A00, 0x1A1F, LANGUAGE_BUGINESE}, // Buginese/Lontara
371 // {0x1B00, 0x1B7F, LANGUAGE_BALINESE}, // Balinese
372 // {0x1D00, 0x1DFF, LANGUAGE_NONE}, // Phonetic Symbols
373 {0x1E00, 0x1EFF, LANGUAGE_ENGLISH}, // Latin Extended Additional
374 {0x1F00, 0x1FFF, LANGUAGE_GREEK}, // Greek Extended
375 {0x2C60, 0x2C7F, LANGUAGE_ENGLISH}, // Latin Extended-C
376 {0x2E80, 0x2FFf, LANGUAGE_CHINESE_SIMPLIFIED}, // CJK Radicals Supplement + Kangxi Radical + Ideographic Description Characters
377 {0x3000, 0x303F, LANGUAGE_DEFAULT_CJK}, // CJK Symbols and punctuation
378 {0x3040, 0x30FF, LANGUAGE_JAPANESE}, // Japanese Hiragana + Katakana
379 {0x3100, 0x312F, LANGUAGE_CHINESE_TRADITIONAL}, // Bopomofo
380 {0x3130, 0x318F, LANGUAGE_KOREAN}, // Hangul Compatibility Jamo, Kocrean-specific
381 {0x3190, 0x319F, LANGUAGE_JAPANESE}, // Kanbun
382 {0x31A0, 0x31BF, LANGUAGE_CHINESE_TRADITIONAL}, // Bopomofo Extended
383 {0x31C0, 0x31EF, LANGUAGE_DEFAULT_CJK}, // CJK Ideographs
384 {0x31F0, 0x31FF, LANGUAGE_JAPANESE}, // Japanese Katakana Phonetic Extensions
385 {0x3200, 0x321F, LANGUAGE_KOREAN}, // Parenthesized Hangul
386 {0x3220, 0x325F, LANGUAGE_DEFAULT_CJK}, // Parenthesized Ideographs
387 {0x3260, 0x327F, LANGUAGE_KOREAN}, // Circled Hangul
388 {0x3280, 0x32CF, LANGUAGE_DEFAULT_CJK}, // Circled Ideographs
389 {0x32d0, 0x32FF, LANGUAGE_JAPANESE}, // Japanese Circled Katakana
390 {0x3400, 0x4DBF, LANGUAGE_DEFAULT_CJK}, // CJK Unified Ideographs Extension A
391 {0x4E00, 0x9FCF, LANGUAGE_DEFAULT_CJK}, // Unified CJK Ideographs
392 {0xA720, 0xA7FF, LANGUAGE_ENGLISH}, // Latin Extended-D
393 {0xAC00, 0xD7AF, LANGUAGE_KOREAN}, // Hangul Syllables, Korean-specific
394 {0xF900, 0xFAFF, LANGUAGE_DEFAULT_CJK}, // CJK Compatibility Ideographs
395 {0xFB00, 0xFB4F, LANGUAGE_HEBREW}, // Hebrew Presentation Forms
396 {0xFB50, 0xFDFF, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic Presentation Forms-A
397 {0xFE70, 0xFEFE, LANGUAGE_ARABIC_PRIMARY_ONLY}, // Arabic Presentation Forms-B
398 {0xFF65, 0xFF9F, LANGUAGE_JAPANESE}, // Japanese Halfwidth Katakana variant
399 {0xFFA0, 0xFFDC, LANGUAGE_KOREAN}, // Kocrean halfwidth hangual variant
400 {0x10140, 0x1018F, LANGUAGE_GREEK}, // Ancient Greak numbers
401 {0x1D200, 0x1D24F, LANGUAGE_GREEK}, // Ancient Greek Musical
402 {0x20000, 0x2A6DF, LANGUAGE_DEFAULT_CJK}, // CJK Unified Ideographs Extension B
403 {0x2F800, 0x2FA1F, LANGUAGE_DEFAULT_CJK} // CJK Compatibility Ideographs Supplement
404 };
405
406 // get language matching to the missing char
MapCharToLanguage(sal_UCS4 uChar)407 LanguageType MapCharToLanguage( sal_UCS4 uChar )
408 {
409 // entries marked with default-CJK get replaced with the prefered CJK language
410 static bool bFirst = true;
411 if( bFirst )
412 {
413 bFirst = false;
414
415 // use method suggested in #i97086# to determnine the systems default language
416 // TODO: move into i18npool or sal/osl/w32/nlsupport.c
417 LanguageType nDefaultLang = 0;
418 HKEY hKey = NULL;
419 LONG lResult = ::RegOpenKeyExA( HKEY_LOCAL_MACHINE,
420 "SYSTEM\\CurrentControlSet\\Control\\Nls\\Language",
421 0, KEY_QUERY_VALUE, &hKey );
422 char aKeyValBuf[16];
423 DWORD nKeyValSize = sizeof(aKeyValBuf);
424 if( ERROR_SUCCESS == lResult )
425 lResult = RegQueryValueExA( hKey, "Default", NULL, NULL, (LPBYTE)aKeyValBuf, &nKeyValSize );
426 aKeyValBuf[ sizeof(aKeyValBuf)-1 ] = '\0';
427 if( ERROR_SUCCESS == lResult )
428 nDefaultLang = (LanguageType)rtl_str_toInt32( aKeyValBuf, 16 );
429
430 // TODO: use the default-CJK language selected in
431 // Tools->Options->LangSettings->Languages when it becomes available here
432 if( !nDefaultLang )
433 nDefaultLang = Application::GetSettings().GetUILanguage();
434
435 LanguageType nDefaultCJK = LANGUAGE_CHINESE;
436 switch( nDefaultLang )
437 {
438 case LANGUAGE_JAPANESE:
439 case LANGUAGE_KOREAN:
440 case LANGUAGE_KOREAN_JOHAB:
441 case LANGUAGE_CHINESE_SIMPLIFIED:
442 case LANGUAGE_CHINESE_TRADITIONAL:
443 case LANGUAGE_CHINESE_SINGAPORE:
444 case LANGUAGE_CHINESE_HONGKONG:
445 case LANGUAGE_CHINESE_MACAU:
446 nDefaultCJK = nDefaultLang;
447 break;
448 default:
449 nDefaultCJK = LANGUAGE_CHINESE;
450 break;
451 }
452
453 // change the marked entries to prefered language
454 static const int nCount = (sizeof(aLangFromCodeChart) / sizeof(*aLangFromCodeChart));
455 for( int i = 0; i < nCount; ++i )
456 {
457 if( aLangFromCodeChart[ i].mnLangID == LANGUAGE_DEFAULT_CJK )
458 aLangFromCodeChart[ i].mnLangID = nDefaultCJK;
459 }
460 }
461
462 // binary search
463 int nLow = 0;
464 int nHigh = (sizeof(aLangFromCodeChart) / sizeof(*aLangFromCodeChart)) - 1;
465 while( nLow <= nHigh )
466 {
467 int nMiddle = (nHigh + nLow) / 2;
468 if( uChar < aLangFromCodeChart[ nMiddle].mnMinCode )
469 nHigh = nMiddle - 1;
470 else if( uChar > aLangFromCodeChart[ nMiddle].mnMaxCode )
471 nLow = nMiddle + 1;
472 else
473 return aLangFromCodeChart[ nMiddle].mnLangID;
474 }
475
476 return LANGUAGE_DONTKNOW;
477 }
478
479 class WinGlyphFallbackSubstititution
480 : public ImplGlyphFallbackFontSubstitution
481 {
482 public:
483 explicit WinGlyphFallbackSubstititution( HDC );
484
485 bool FindFontSubstitute( ImplFontSelectData&, rtl::OUString& rMissingChars ) const;
486 private:
487 HDC mhDC;
488 bool HasMissingChars( const ImplFontData*, const rtl::OUString& rMissingChars ) const;
489 };
490
WinGlyphFallbackSubstititution(HDC hDC)491 inline WinGlyphFallbackSubstititution::WinGlyphFallbackSubstititution( HDC hDC )
492 : mhDC( hDC )
493 {}
494
495 void ImplGetLogFontFromFontSelect( HDC, const ImplFontSelectData*,
496 LOGFONTW&, bool /*bTestVerticalAvail*/ );
497
498 // does a font face hold the given missing characters?
HasMissingChars(const ImplFontData * pFace,const rtl::OUString & rMissingChars) const499 bool WinGlyphFallbackSubstititution::HasMissingChars( const ImplFontData* pFace, const rtl::OUString& rMissingChars ) const
500 {
501 const ImplWinFontData* pWinFont = static_cast<const ImplWinFontData*>(pFace);
502 const ImplFontCharMap* pCharMap = pWinFont->GetImplFontCharMap();
503 if( !pCharMap )
504 {
505 // construct a Size structure as the parameter of constructor of class ImplFontSelectData
506 const Size aSize( pFace->GetWidth(), pFace->GetHeight() );
507 // create a ImplFontSelectData object for getting s LOGFONT
508 const ImplFontSelectData aFSD( *pFace, aSize, (float)aSize.Height(), 0, false );
509 // construct log font
510 LOGFONTW aLogFont;
511 ImplGetLogFontFromFontSelect( mhDC, &aFSD, aLogFont, true );
512
513 // create HFONT from log font
514 HFONT hNewFont = ::CreateFontIndirectW( &aLogFont );
515 // select the new font into device
516 HFONT hOldFont = ::SelectFont( mhDC, hNewFont );
517
518 // read CMAP table to update their pCharMap
519 pWinFont->UpdateFromHDC( mhDC );;
520
521 // cleanup temporary font
522 ::SelectFont( mhDC, hOldFont );
523 ::DeleteFont( hNewFont );
524
525 // get the new charmap
526 pCharMap = pWinFont->GetImplFontCharMap();
527 }
528
529 // avoid fonts with unknown CMAP subtables for glyph fallback
530 if( !pCharMap || pCharMap->IsDefaultMap() )
531 return false;
532 pCharMap->AddReference();
533
534 int nMatchCount = 0;
535 // static const int nMaxMatchCount = 1; // TODO: tolerate more missing characters?
536 const sal_Int32 nStrLen = rMissingChars.getLength();
537 for( sal_Int32 nStrIdx = 0; nStrIdx < nStrLen; ++nStrIdx )
538 {
539 const sal_UCS4 uChar = rMissingChars.iterateCodePoints( &nStrIdx );
540 nMatchCount += pCharMap->HasChar( uChar );
541 break; // for now
542 }
543 pCharMap->DeReference();
544
545 const bool bHasMatches = (nMatchCount > 0);
546 return bHasMatches;
547 }
548
549 // find a fallback font for missing characters
550 // TODO: should stylistic matches be searched and prefered?
FindFontSubstitute(ImplFontSelectData & rFontSelData,rtl::OUString & rMissingChars) const551 bool WinGlyphFallbackSubstititution::FindFontSubstitute( ImplFontSelectData& rFontSelData, rtl::OUString& rMissingChars ) const
552 {
553 // guess a locale matching to the missing chars
554 com::sun::star::lang::Locale aLocale;
555
556 sal_Int32 nStrIdx = 0;
557 const sal_Int32 nStrLen = rMissingChars.getLength();
558 while( nStrIdx < nStrLen )
559 {
560 const sal_UCS4 uChar = rMissingChars.iterateCodePoints( &nStrIdx );
561 const LanguageType eLang = MapCharToLanguage( uChar );
562 if( eLang == LANGUAGE_DONTKNOW )
563 continue;
564 MsLangId::convertLanguageToLocale( eLang, aLocale );
565 break;
566 }
567
568 // fall back to default UI locale if the missing characters are inconclusive
569 if( nStrIdx >= nStrLen )
570 aLocale = Application::GetSettings().GetUILocale();
571
572 // first level fallback:
573 // try use the locale specific default fonts defined in VCL.xcu
574 const ImplDevFontList* pDevFontList = ImplGetSVData()->maGDIData.mpScreenFontList;
575 /*const*/ ImplDevFontListData* pDevFont = pDevFontList->ImplFindByLocale( aLocale );
576 if( pDevFont )
577 {
578 const ImplFontData* pFace = pDevFont->FindBestFontFace( rFontSelData );
579 if( HasMissingChars( pFace, rMissingChars ) )
580 {
581 rFontSelData.maSearchName = pDevFont->GetSearchName();
582 return true;
583 }
584 }
585
586 // are the missing characters symbols?
587 pDevFont = pDevFontList->ImplFindByAttributes( IMPL_FONT_ATTR_SYMBOL,
588 rFontSelData.meWeight, rFontSelData.meWidthType,
589 rFontSelData.meFamily, rFontSelData.meItalic, rFontSelData.maSearchName );
590 if( pDevFont )
591 {
592 const ImplFontData* pFace = pDevFont->FindBestFontFace( rFontSelData );
593 if( HasMissingChars( pFace, rMissingChars ) )
594 {
595 rFontSelData.maSearchName = pDevFont->GetSearchName();
596 return true;
597 }
598 }
599
600 // last level fallback, check each font type face one by one
601 const ImplGetDevFontList* pTestFontList = pDevFontList->GetDevFontList();
602 // limit the count of fonts to be checked to prevent hangs
603 static const int MAX_GFBFONT_COUNT = 600;
604 int nTestFontCount = pTestFontList->Count();
605 if( nTestFontCount > MAX_GFBFONT_COUNT )
606 nTestFontCount = MAX_GFBFONT_COUNT;
607
608 bool bFound = false;
609 for( int i = 0; i < nTestFontCount; ++i )
610 {
611 const ImplFontData* pFace = pTestFontList->Get( i );
612 bFound = HasMissingChars( pFace, rMissingChars );
613 if( !bFound )
614 continue;
615 rFontSelData.maSearchName = pFace->maName;
616 break;
617 }
618
619 delete pTestFontList;
620
621 return bFound;
622 }
623
624 // =======================================================================
625
626 struct ImplEnumInfo
627 {
628 HDC mhDC;
629 ImplDevFontList* mpList;
630 String* mpName;
631 LOGFONTA* mpLogFontA;
632 LOGFONTW* mpLogFontW;
633 UINT mnPreferedCharSet;
634 bool mbCourier;
635 bool mbImplSalCourierScalable;
636 bool mbImplSalCourierNew;
637 bool mbPrinter;
638 int mnFontCount;
639 };
640
641 // =======================================================================
642
ImplCharSetToSal(BYTE nCharSet)643 static CharSet ImplCharSetToSal( BYTE nCharSet )
644 {
645 rtl_TextEncoding eTextEncoding;
646
647 if ( nCharSet == OEM_CHARSET )
648 {
649 UINT nCP = (sal_uInt16)GetOEMCP();
650 switch ( nCP )
651 {
652 // It is unclear why these two (undefined?) code page numbers are
653 // handled specially here:
654 case 1004: eTextEncoding = RTL_TEXTENCODING_MS_1252; break;
655 case 65400: eTextEncoding = RTL_TEXTENCODING_SYMBOL; break;
656 default:
657 eTextEncoding = rtl_getTextEncodingFromWindowsCodePage(nCP);
658 break;
659 };
660 }
661 else
662 {
663 if( nCharSet )
664 eTextEncoding = rtl_getTextEncodingFromWindowsCharset( nCharSet );
665 else
666 eTextEncoding = RTL_TEXTENCODING_UNICODE;
667 }
668
669 return eTextEncoding;
670 }
671
672 // -----------------------------------------------------------------------
673
ImplFamilyToSal(BYTE nFamily)674 static FontFamily ImplFamilyToSal( BYTE nFamily )
675 {
676 switch ( nFamily & 0xF0 )
677 {
678 case FF_DECORATIVE:
679 return FAMILY_DECORATIVE;
680
681 case FF_MODERN:
682 return FAMILY_MODERN;
683
684 case FF_ROMAN:
685 return FAMILY_ROMAN;
686
687 case FF_SCRIPT:
688 return FAMILY_SCRIPT;
689
690 case FF_SWISS:
691 return FAMILY_SWISS;
692
693 default:
694 break;
695 }
696
697 return FAMILY_DONTKNOW;
698 }
699
700 // -----------------------------------------------------------------------
701
ImplFamilyToWin(FontFamily eFamily)702 static BYTE ImplFamilyToWin( FontFamily eFamily )
703 {
704 switch ( eFamily )
705 {
706 case FAMILY_DECORATIVE:
707 return FF_DECORATIVE;
708
709 case FAMILY_MODERN:
710 return FF_MODERN;
711
712 case FAMILY_ROMAN:
713 return FF_ROMAN;
714
715 case FAMILY_SCRIPT:
716 return FF_SCRIPT;
717
718 case FAMILY_SWISS:
719 return FF_SWISS;
720
721 case FAMILY_SYSTEM:
722 return FF_SWISS;
723
724 default:
725 break;
726 }
727
728 return FF_DONTCARE;
729 }
730
731 // -----------------------------------------------------------------------
732
ImplWeightToSal(int nWeight)733 static FontWeight ImplWeightToSal( int nWeight )
734 {
735 if ( nWeight <= FW_THIN )
736 return WEIGHT_THIN;
737 else if ( nWeight <= FW_ULTRALIGHT )
738 return WEIGHT_ULTRALIGHT;
739 else if ( nWeight <= FW_LIGHT )
740 return WEIGHT_LIGHT;
741 else if ( nWeight < FW_MEDIUM )
742 return WEIGHT_NORMAL;
743 else if ( nWeight == FW_MEDIUM )
744 return WEIGHT_MEDIUM;
745 else if ( nWeight <= FW_SEMIBOLD )
746 return WEIGHT_SEMIBOLD;
747 else if ( nWeight <= FW_BOLD )
748 return WEIGHT_BOLD;
749 else if ( nWeight <= FW_ULTRABOLD )
750 return WEIGHT_ULTRABOLD;
751 else
752 return WEIGHT_BLACK;
753 }
754
755 // -----------------------------------------------------------------------
756
ImplWeightToWin(FontWeight eWeight)757 static int ImplWeightToWin( FontWeight eWeight )
758 {
759 switch ( eWeight )
760 {
761 case WEIGHT_THIN:
762 return FW_THIN;
763
764 case WEIGHT_ULTRALIGHT:
765 return FW_ULTRALIGHT;
766
767 case WEIGHT_LIGHT:
768 return FW_LIGHT;
769
770 case WEIGHT_SEMILIGHT:
771 case WEIGHT_NORMAL:
772 return FW_NORMAL;
773
774 case WEIGHT_MEDIUM:
775 return FW_MEDIUM;
776
777 case WEIGHT_SEMIBOLD:
778 return FW_SEMIBOLD;
779
780 case WEIGHT_BOLD:
781 return FW_BOLD;
782
783 case WEIGHT_ULTRABOLD:
784 return FW_ULTRABOLD;
785
786 case WEIGHT_BLACK:
787 return FW_BLACK;
788
789 default:
790 break;
791 }
792
793 return 0;
794 }
795
796 // -----------------------------------------------------------------------
797
ImplLogPitchToSal(BYTE nPitch)798 inline FontPitch ImplLogPitchToSal( BYTE nPitch )
799 {
800 if ( nPitch & FIXED_PITCH )
801 return PITCH_FIXED;
802 else
803 return PITCH_VARIABLE;
804 }
805
806 // -----------------------------------------------------------------------
807
ImplMetricPitchToSal(BYTE nPitch)808 inline FontPitch ImplMetricPitchToSal( BYTE nPitch )
809 {
810 // Sausaecke bei MS !! siehe NT Hilfe
811 if ( !(nPitch & TMPF_FIXED_PITCH) )
812 return PITCH_FIXED;
813 else
814 return PITCH_VARIABLE;
815 }
816
817 // -----------------------------------------------------------------------
818
ImplPitchToWin(FontPitch ePitch)819 inline BYTE ImplPitchToWin( FontPitch ePitch )
820 {
821 if ( ePitch == PITCH_FIXED )
822 return FIXED_PITCH;
823 else if ( ePitch == PITCH_VARIABLE )
824 return VARIABLE_PITCH;
825 else
826 return DEFAULT_PITCH;
827 }
828
829 // -----------------------------------------------------------------------
830
WinFont2DevFontAttributes(const ENUMLOGFONTEXA & rEnumFont,const NEWTEXTMETRICA & rMetric,DWORD nFontType)831 static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXA& rEnumFont,
832 const NEWTEXTMETRICA& rMetric, DWORD nFontType )
833 {
834 ImplDevFontAttributes aDFA;
835
836 const LOGFONTA rLogFont = rEnumFont.elfLogFont;
837
838 // get font face attributes
839 aDFA.meFamily = ImplFamilyToSal( rLogFont.lfPitchAndFamily );
840 aDFA.meWidthType = WIDTH_DONTKNOW;
841 aDFA.meWeight = ImplWeightToSal( rLogFont.lfWeight );
842 aDFA.meItalic = (rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE;
843 aDFA.mePitch = ImplLogPitchToSal( rLogFont.lfPitchAndFamily );
844 aDFA.mbSymbolFlag = (rLogFont.lfCharSet == SYMBOL_CHARSET);
845
846 // get the font face name
847 aDFA.maName = ImplSalGetUniString( rLogFont.lfFaceName );
848
849 // use the face's style name only if it looks reasonable
850 const char* pStyleName = (const char*)rEnumFont.elfStyle;
851 const char* pEnd = pStyleName + sizeof( rEnumFont.elfStyle );
852 const char* p = pStyleName;
853 for(; *p && (p < pEnd); ++p )
854 if( (0x00 < *p) && (*p < 0x20) )
855 break;
856 if( p < pEnd )
857 aDFA.maStyleName = ImplSalGetUniString( pStyleName );
858
859 // get device specific font attributes
860 aDFA.mbOrientation = (nFontType & RASTER_FONTTYPE) == 0;
861 aDFA.mbDevice = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
862
863 aDFA.mbEmbeddable = false;
864 aDFA.mbSubsettable = false;
865 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
866 || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
867 aDFA.mbSubsettable = true;
868 else if( 0 != (rMetric.ntmFlags & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
869 aDFA.mbEmbeddable = true;
870
871 // heuristics for font quality
872 // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
873 // - subsetting > embedding > none
874 aDFA.mnQuality = 0;
875 if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
876 aDFA.mnQuality += 50;
877 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
878 aDFA.mnQuality += 10;
879 if( aDFA.mbSubsettable )
880 aDFA.mnQuality += 200;
881 else if( aDFA.mbEmbeddable )
882 aDFA.mnQuality += 100;
883
884 // #i38665# prefer Type1 versions of the standard postscript fonts
885 if( aDFA.mbEmbeddable )
886 {
887 if( aDFA.maName.EqualsAscii( "AvantGarde" )
888 || aDFA.maName.EqualsAscii( "Bookman" )
889 || aDFA.maName.EqualsAscii( "Courier" )
890 || aDFA.maName.EqualsAscii( "Helvetica" )
891 || aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
892 || aDFA.maName.EqualsAscii( "Palatino" )
893 || aDFA.maName.EqualsAscii( "Symbol" )
894 || aDFA.maName.EqualsAscii( "Times" )
895 || aDFA.maName.EqualsAscii( "ZapfChancery" )
896 || aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
897 aDFA.mnQuality += 500;
898 }
899
900 // TODO: add alias names
901 return aDFA;
902 }
903
904 // -----------------------------------------------------------------------
905
WinFont2DevFontAttributes(const ENUMLOGFONTEXW & rEnumFont,const NEWTEXTMETRICW & rMetric,DWORD nFontType)906 static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXW& rEnumFont,
907 const NEWTEXTMETRICW& rMetric, DWORD nFontType )
908 {
909 ImplDevFontAttributes aDFA;
910
911 const LOGFONTW rLogFont = rEnumFont.elfLogFont;
912
913 // get font face attributes
914 aDFA.meFamily = ImplFamilyToSal( rLogFont.lfPitchAndFamily );
915 aDFA.meWidthType = WIDTH_DONTKNOW;
916 aDFA.meWeight = ImplWeightToSal( rLogFont.lfWeight );
917 aDFA.meItalic = (rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE;
918 aDFA.mePitch = ImplLogPitchToSal( rLogFont.lfPitchAndFamily );
919 aDFA.mbSymbolFlag = (rLogFont.lfCharSet == SYMBOL_CHARSET);
920
921 // get the font face name
922 aDFA.maName = reinterpret_cast<const sal_Unicode*>(rLogFont.lfFaceName);
923
924 // use the face's style name only if it looks reasonable
925 const wchar_t* pStyleName = rEnumFont.elfStyle;
926 const wchar_t* pEnd = pStyleName + sizeof(rEnumFont.elfStyle)/sizeof(*rEnumFont.elfStyle);
927 const wchar_t* p = pStyleName;
928 for(; *p && (p < pEnd); ++p )
929 if( *p < 0x0020 )
930 break;
931 if( p < pEnd )
932 aDFA.maStyleName = reinterpret_cast<const sal_Unicode*>(pStyleName);
933
934 // get device specific font attributes
935 aDFA.mbOrientation = (nFontType & RASTER_FONTTYPE) == 0;
936 aDFA.mbDevice = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
937
938 aDFA.mbEmbeddable = false;
939 aDFA.mbSubsettable = false;
940 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
941 || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
942 aDFA.mbSubsettable = true;
943 else if( 0 != (rMetric.ntmFlags & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
944 aDFA.mbEmbeddable = true;
945
946 // heuristics for font quality
947 // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
948 // - subsetting > embedding > none
949 aDFA.mnQuality = 0;
950 if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
951 aDFA.mnQuality += 50;
952 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
953 aDFA.mnQuality += 10;
954 if( aDFA.mbSubsettable )
955 aDFA.mnQuality += 200;
956 else if( aDFA.mbEmbeddable )
957 aDFA.mnQuality += 100;
958
959 // #i38665# prefer Type1 versions of the standard postscript fonts
960 if( aDFA.mbEmbeddable )
961 {
962 if( aDFA.maName.EqualsAscii( "AvantGarde" )
963 || aDFA.maName.EqualsAscii( "Bookman" )
964 || aDFA.maName.EqualsAscii( "Courier" )
965 || aDFA.maName.EqualsAscii( "Helvetica" )
966 || aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
967 || aDFA.maName.EqualsAscii( "Palatino" )
968 || aDFA.maName.EqualsAscii( "Symbol" )
969 || aDFA.maName.EqualsAscii( "Times" )
970 || aDFA.maName.EqualsAscii( "ZapfChancery" )
971 || aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
972 aDFA.mnQuality += 500;
973 }
974
975 // TODO: add alias names
976 return aDFA;
977 }
978
979 // -----------------------------------------------------------------------
980
ImplLogMetricToDevFontDataA(const ENUMLOGFONTEXA * pLogFont,const NEWTEXTMETRICA * pMetric,DWORD nFontType)981 static ImplWinFontData* ImplLogMetricToDevFontDataA( const ENUMLOGFONTEXA* pLogFont,
982 const NEWTEXTMETRICA* pMetric,
983 DWORD nFontType )
984 {
985 int nHeight = 0;
986 if ( nFontType & RASTER_FONTTYPE )
987 nHeight = pMetric->tmHeight - pMetric->tmInternalLeading;
988
989 ImplWinFontData* pData = new ImplWinFontData(
990 WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType),
991 nHeight,
992 pLogFont->elfLogFont.lfCharSet,
993 pMetric->tmPitchAndFamily );
994
995 return pData;
996 }
997
998 // -----------------------------------------------------------------------
999
ImplLogMetricToDevFontDataW(const ENUMLOGFONTEXW * pLogFont,const NEWTEXTMETRICW * pMetric,DWORD nFontType)1000 static ImplWinFontData* ImplLogMetricToDevFontDataW( const ENUMLOGFONTEXW* pLogFont,
1001 const NEWTEXTMETRICW* pMetric,
1002 DWORD nFontType )
1003 {
1004 int nHeight = 0;
1005 if ( nFontType & RASTER_FONTTYPE )
1006 nHeight = pMetric->tmHeight - pMetric->tmInternalLeading;
1007
1008 ImplWinFontData* pData = new ImplWinFontData(
1009 WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType),
1010 nHeight,
1011 pLogFont->elfLogFont.lfCharSet,
1012 pMetric->tmPitchAndFamily );
1013
1014 return pData;
1015 }
1016
1017 // -----------------------------------------------------------------------
1018
ImplSalLogFontToFontA(HDC hDC,const LOGFONTA & rLogFont,Font & rFont)1019 void ImplSalLogFontToFontA( HDC hDC, const LOGFONTA& rLogFont, Font& rFont )
1020 {
1021 String aFontName( ImplSalGetUniString( rLogFont.lfFaceName ) );
1022 if ( aFontName.Len() )
1023 {
1024 rFont.SetName( aFontName );
1025 rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) );
1026 rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) );
1027 rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) );
1028 rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) );
1029
1030 long nFontHeight = rLogFont.lfHeight;
1031 if ( nFontHeight < 0 )
1032 nFontHeight = -nFontHeight;
1033 long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
1034 if( !nDPIY )
1035 nDPIY = 600;
1036 nFontHeight *= 72;
1037 nFontHeight += nDPIY/2;
1038 nFontHeight /= nDPIY;
1039 rFont.SetSize( Size( 0, nFontHeight ) );
1040 rFont.SetOrientation( (short)rLogFont.lfEscapement );
1041 if ( rLogFont.lfItalic )
1042 rFont.SetItalic( ITALIC_NORMAL );
1043 else
1044 rFont.SetItalic( ITALIC_NONE );
1045 if ( rLogFont.lfUnderline )
1046 rFont.SetUnderline( UNDERLINE_SINGLE );
1047 else
1048 rFont.SetUnderline( UNDERLINE_NONE );
1049 if ( rLogFont.lfStrikeOut )
1050 rFont.SetStrikeout( STRIKEOUT_SINGLE );
1051 else
1052 rFont.SetStrikeout( STRIKEOUT_NONE );
1053 }
1054 }
1055
1056 // -----------------------------------------------------------------------
1057
ImplSalLogFontToFontW(HDC hDC,const LOGFONTW & rLogFont,Font & rFont)1058 void ImplSalLogFontToFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont )
1059 {
1060 XubString aFontName( reinterpret_cast<const xub_Unicode*>(rLogFont.lfFaceName) );
1061 if ( aFontName.Len() )
1062 {
1063 rFont.SetName( aFontName );
1064 rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) );
1065 rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) );
1066 rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) );
1067 rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) );
1068
1069 long nFontHeight = rLogFont.lfHeight;
1070 if ( nFontHeight < 0 )
1071 nFontHeight = -nFontHeight;
1072 long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
1073 if( !nDPIY )
1074 nDPIY = 600;
1075 nFontHeight *= 72;
1076 nFontHeight += nDPIY/2;
1077 nFontHeight /= nDPIY;
1078 rFont.SetSize( Size( 0, nFontHeight ) );
1079 rFont.SetOrientation( (short)rLogFont.lfEscapement );
1080 if ( rLogFont.lfItalic )
1081 rFont.SetItalic( ITALIC_NORMAL );
1082 else
1083 rFont.SetItalic( ITALIC_NONE );
1084 if ( rLogFont.lfUnderline )
1085 rFont.SetUnderline( UNDERLINE_SINGLE );
1086 else
1087 rFont.SetUnderline( UNDERLINE_NONE );
1088 if ( rLogFont.lfStrikeOut )
1089 rFont.SetStrikeout( STRIKEOUT_SINGLE );
1090 else
1091 rFont.SetStrikeout( STRIKEOUT_NONE );
1092 }
1093 }
1094
1095 // =======================================================================
1096
ImplWinFontData(const ImplDevFontAttributes & rDFS,int nHeight,BYTE eWinCharSet,BYTE nPitchAndFamily)1097 ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes& rDFS,
1098 int nHeight, BYTE eWinCharSet, BYTE nPitchAndFamily )
1099 : ImplFontData( rDFS, 0 ),
1100 meWinCharSet( eWinCharSet ),
1101 mnPitchAndFamily( nPitchAndFamily ),
1102 mpFontCharSets( NULL ),
1103 mpUnicodeMap( NULL ),
1104 mbGsubRead( false ),
1105 mbDisableGlyphApi( false ),
1106 mbHasKoreanRange( false ),
1107 mbHasCJKSupport( false ),
1108 #ifdef ENABLE_GRAPHITE
1109 mbHasGraphiteSupport( false ),
1110 #endif
1111 mbHasArabicSupport ( false ),
1112 mbAliasSymbolsLow( false ),
1113 mbAliasSymbolsHigh( false ),
1114 mnId( 0 ),
1115 mpEncodingVector( NULL )
1116 {
1117 SetBitmapSize( 0, nHeight );
1118
1119 if( eWinCharSet == SYMBOL_CHARSET )
1120 {
1121 if( (nPitchAndFamily & TMPF_TRUETYPE) != 0 )
1122 {
1123 // truetype fonts need their symbols as U+F0xx
1124 mbAliasSymbolsHigh = true;
1125 }
1126 else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_DEVICE))
1127 == (TMPF_VECTOR|TMPF_DEVICE) )
1128 {
1129 // scalable device fonts (e.g. builtin printer fonts)
1130 // need their symbols as U+00xx
1131 mbAliasSymbolsLow = true;
1132 }
1133 else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) == 0 )
1134 {
1135 // bitmap fonts need their symbols as U+F0xx
1136 mbAliasSymbolsHigh = true;
1137 }
1138 }
1139 }
1140
1141 // -----------------------------------------------------------------------
1142
~ImplWinFontData()1143 ImplWinFontData::~ImplWinFontData()
1144 {
1145 delete[] mpFontCharSets;
1146
1147 if( mpUnicodeMap )
1148 mpUnicodeMap->DeReference();
1149 delete mpEncodingVector;
1150 }
1151
1152 // -----------------------------------------------------------------------
1153
GetFontId() const1154 sal_IntPtr ImplWinFontData::GetFontId() const
1155 {
1156 return mnId;
1157 }
1158
1159 // -----------------------------------------------------------------------
1160
UpdateFromHDC(HDC hDC) const1161 void ImplWinFontData::UpdateFromHDC( HDC hDC ) const
1162 {
1163 // short circuit if already initialized
1164 if( mpUnicodeMap != NULL )
1165 return;
1166
1167 ReadCmapTable( hDC );
1168 ReadOs2Table( hDC );
1169 #ifdef ENABLE_GRAPHITE
1170 static const char* pDisableGraphiteText = getenv( "SAL_DISABLE_GRAPHITE" );
1171 if( !pDisableGraphiteText || (pDisableGraphiteText[0] == '0') )
1172 {
1173 mbHasGraphiteSupport = gr::WinFont::FontHasGraphiteTables(hDC);
1174 }
1175 #endif
1176
1177 // even if the font works some fonts have problems with the glyph API
1178 // => the heuristic below tries to figure out which fonts have the problem
1179 TEXTMETRICA aTextMetric;
1180 if( ::GetTextMetricsA( hDC, &aTextMetric ) )
1181 if( !(aTextMetric.tmPitchAndFamily & TMPF_TRUETYPE)
1182 || (aTextMetric.tmPitchAndFamily & TMPF_DEVICE) )
1183 mbDisableGlyphApi = true;
1184
1185 #if 0
1186 // #110548# more important than #107885# => TODO: better solution
1187 DWORD nFLI = GetFontLanguageInfo( hDC );
1188 if( 0 == (nFLI & GCP_GLYPHSHAPE) )
1189 mbDisableGlyphApi = true;
1190 #endif
1191 }
1192
1193 // -----------------------------------------------------------------------
1194
HasGSUBstitutions(HDC hDC) const1195 bool ImplWinFontData::HasGSUBstitutions( HDC hDC ) const
1196 {
1197 if( !mbGsubRead )
1198 ReadGsubTable( hDC );
1199 return !maGsubTable.empty();
1200 }
1201
1202 // -----------------------------------------------------------------------
1203
IsGSUBstituted(sal_UCS4 cChar) const1204 bool ImplWinFontData::IsGSUBstituted( sal_UCS4 cChar ) const
1205 {
1206 return( maGsubTable.find( cChar ) != maGsubTable.end() );
1207 }
1208
1209 // -----------------------------------------------------------------------
1210
GetImplFontCharMap() const1211 const ImplFontCharMap* ImplWinFontData::GetImplFontCharMap() const
1212 {
1213 if( !mpUnicodeMap )
1214 return NULL;
1215 return mpUnicodeMap;
1216 }
1217
1218 // -----------------------------------------------------------------------
1219
GetUInt(const unsigned char * p)1220 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
GetUShort(const unsigned char * p)1221 static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
1222 //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
CalcTag(const char p[4])1223 static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); }
1224
ReadOs2Table(HDC hDC) const1225 void ImplWinFontData::ReadOs2Table( HDC hDC ) const
1226 {
1227 const DWORD Os2Tag = CalcTag( "OS/2" );
1228 DWORD nLength = ::GetFontData( hDC, Os2Tag, 0, NULL, 0 );
1229 if( (nLength == GDI_ERROR) || !nLength )
1230 return;
1231 std::vector<unsigned char> aOS2map( nLength );
1232 unsigned char* pOS2map = &aOS2map[0];
1233 ::GetFontData( hDC, Os2Tag, 0, pOS2map, nLength );
1234 sal_uInt32 nVersion = GetUShort( pOS2map );
1235 if ( nVersion >= 0x0001 && nLength >= 58 )
1236 {
1237 // We need at least version 0x0001 (TrueType rev 1.66)
1238 // to have access to the needed struct members.
1239 sal_uInt32 ulUnicodeRange1 = GetUInt( pOS2map + 42 );
1240 sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
1241 #if 0
1242 sal_uInt32 ulUnicodeRange3 = GetUInt( pOS2map + 50 );
1243 sal_uInt32 ulUnicodeRange4 = GetUInt( pOS2map + 54 );
1244 #endif
1245
1246 // Check for CJK capabilities of the current font
1247 mbHasCJKSupport = (ulUnicodeRange2 & 0x2DF00000);
1248 mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000)
1249 | (ulUnicodeRange2 & 0x01100000);
1250 mbHasArabicSupport = (ulUnicodeRange1 & 0x00002000);
1251 }
1252 }
1253
1254 // -----------------------------------------------------------------------
1255
ReadGsubTable(HDC hDC) const1256 void ImplWinFontData::ReadGsubTable( HDC hDC ) const
1257 {
1258 mbGsubRead = true;
1259
1260 // check the existence of a GSUB table
1261 const DWORD GsubTag = CalcTag( "GSUB" );
1262 DWORD nRC = ::GetFontData( hDC, GsubTag, 0, NULL, 0 );
1263 if( (nRC == GDI_ERROR) || !nRC )
1264 return;
1265
1266 // parse the GSUB table through sft
1267 // TODO: parse it directly
1268
1269 // sft needs the full font file data => get it
1270 const RawFontData aRawFontData( hDC );
1271 if( !aRawFontData.get() )
1272 return;
1273
1274 // open font file
1275 sal_uInt32 nFaceNum = 0;
1276 if( !*aRawFontData.get() ) // TTC candidate
1277 nFaceNum = ~0U; // indicate "TTC font extracts only"
1278
1279 TrueTypeFont* pTTFont = NULL;
1280 ::OpenTTFontBuffer( (void*)aRawFontData.get(), aRawFontData.size(), nFaceNum, &pTTFont );
1281 if( !pTTFont )
1282 return;
1283
1284 // add vertically substituted characters to list
1285 static const sal_Unicode aGSUBCandidates[] = {
1286 0x0020, 0x0080, // ASCII
1287 0x2000, 0x2600, // misc
1288 0x3000, 0x3100, // CJK punctutation
1289 0x3300, 0x3400, // squared words
1290 0xFF00, 0xFFF0, // halfwidth|fullwidth forms
1291 0 };
1292
1293 for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
1294 for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
1295 if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
1296 maGsubTable.insert( cChar ); // insert GSUBbed unicodes
1297
1298 CloseTTFont( pTTFont );
1299 }
1300
1301 // -----------------------------------------------------------------------
1302
ReadCmapTable(HDC hDC) const1303 void ImplWinFontData::ReadCmapTable( HDC hDC ) const
1304 {
1305 if( mpUnicodeMap != NULL )
1306 return;
1307
1308 bool bIsSymbolFont = (meWinCharSet == SYMBOL_CHARSET);
1309 // get the CMAP table from the font which is selected into the DC
1310 const DWORD nCmapTag = CalcTag( "cmap" );
1311 const RawFontData aRawFontData( hDC, nCmapTag );
1312 // parse the CMAP table if available
1313 if( aRawFontData.get() ) {
1314 CmapResult aResult;
1315 ParseCMAP( aRawFontData.get(), aRawFontData.size(), aResult );
1316 mbDisableGlyphApi |= aResult.mbRecoded;
1317 aResult.mbSymbolic = bIsSymbolFont;
1318 if( aResult.mnRangeCount > 0 )
1319 mpUnicodeMap = new ImplFontCharMap( aResult );
1320 }
1321
1322 if( !mpUnicodeMap )
1323 mpUnicodeMap = ImplFontCharMap::GetDefaultMap( bIsSymbolFont );
1324 mpUnicodeMap->AddReference();
1325 }
1326
1327 // =======================================================================
1328
SetTextColor(SalColor nSalColor)1329 void WinSalGraphics::SetTextColor( SalColor nSalColor )
1330 {
1331 COLORREF aCol = PALETTERGB( SALCOLOR_RED( nSalColor ),
1332 SALCOLOR_GREEN( nSalColor ),
1333 SALCOLOR_BLUE( nSalColor ) );
1334
1335 if( !mbPrinter &&
1336 GetSalData()->mhDitherPal &&
1337 ImplIsSysColorEntry( nSalColor ) )
1338 {
1339 aCol = PALRGB_TO_RGB( aCol );
1340 }
1341
1342 ::SetTextColor( getHDC(), aCol );
1343 }
1344
1345 // -----------------------------------------------------------------------
1346
SalEnumQueryFontProcExW(const ENUMLOGFONTEXW *,const NEWTEXTMETRICEXW *,DWORD,LPARAM lParam)1347 int CALLBACK SalEnumQueryFontProcExW( const ENUMLOGFONTEXW*,
1348 const NEWTEXTMETRICEXW*,
1349 DWORD, LPARAM lParam )
1350 {
1351 *((bool*)(void*)lParam) = true;
1352 return 0;
1353 }
1354
1355 // -----------------------------------------------------------------------
1356
SalEnumQueryFontProcExA(const ENUMLOGFONTEXA *,const NEWTEXTMETRICEXA *,DWORD,LPARAM lParam)1357 int CALLBACK SalEnumQueryFontProcExA( const ENUMLOGFONTEXA*,
1358 const NEWTEXTMETRICEXA*,
1359 DWORD, LPARAM lParam )
1360 {
1361 *((bool*)(void*)lParam) = true;
1362 return 0;
1363 }
1364
1365 // -----------------------------------------------------------------------
1366
ImplIsFontAvailable(HDC hDC,const UniString & rName)1367 bool ImplIsFontAvailable( HDC hDC, const UniString& rName )
1368 {
1369 // Test, if Font available
1370 LOGFONTW aLogFont;
1371 memset( &aLogFont, 0, sizeof( aLogFont ) );
1372 aLogFont.lfCharSet = DEFAULT_CHARSET;
1373
1374 UINT nNameLen = rName.Len();
1375 if ( nNameLen > (sizeof( aLogFont.lfFaceName )/sizeof( wchar_t ))-1 )
1376 nNameLen = (sizeof( aLogFont.lfFaceName )/sizeof( wchar_t ))-1;
1377 memcpy( aLogFont.lfFaceName, rName.GetBuffer(), nNameLen*sizeof( wchar_t ) );
1378 aLogFont.lfFaceName[nNameLen] = 0;
1379
1380 bool bAvailable = false;
1381 EnumFontFamiliesExW( hDC, &aLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW,
1382 (LPARAM)(void*)&bAvailable, 0 );
1383
1384 return bAvailable;
1385 }
1386
1387 // -----------------------------------------------------------------------
1388
ImplGetLogFontFromFontSelect(HDC hDC,const ImplFontSelectData * pFont,LOGFONTW & rLogFont,bool)1389 void ImplGetLogFontFromFontSelect( HDC hDC,
1390 const ImplFontSelectData* pFont,
1391 LOGFONTW& rLogFont,
1392 bool /*bTestVerticalAvail*/ )
1393 {
1394 UniString aName;
1395 if ( pFont->mpFontData )
1396 aName = pFont->mpFontData->maName;
1397 else
1398 aName = pFont->maName.GetToken( 0 );
1399
1400 UINT nNameLen = aName.Len();
1401 if ( nNameLen > (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1 )
1402 nNameLen = (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1;
1403 memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen*sizeof( wchar_t ) );
1404 rLogFont.lfFaceName[nNameLen] = 0;
1405
1406 if( !pFont->mpFontData )
1407 {
1408 rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET;
1409 rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->mePitch )
1410 | ImplFamilyToWin( pFont->meFamily );
1411 }
1412 else
1413 {
1414 const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData );
1415 rLogFont.lfCharSet = pWinFontData->GetCharSet();
1416 rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily();
1417 }
1418
1419 rLogFont.lfWeight = ImplWeightToWin( pFont->meWeight );
1420 rLogFont.lfHeight = (LONG)-pFont->mnHeight;
1421 rLogFont.lfWidth = (LONG)pFont->mnWidth;
1422 rLogFont.lfUnderline = 0;
1423 rLogFont.lfStrikeOut = 0;
1424 rLogFont.lfItalic = (pFont->meItalic) != ITALIC_NONE;
1425 rLogFont.lfEscapement = pFont->mnOrientation;
1426 rLogFont.lfOrientation = rLogFont.lfEscapement;
1427 rLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1428 rLogFont.lfQuality = DEFAULT_QUALITY;
1429 rLogFont.lfOutPrecision = OUT_TT_PRECIS;
1430 if ( pFont->mnOrientation )
1431 rLogFont.lfClipPrecision |= CLIP_LH_ANGLES;
1432
1433 // disable antialiasing if requested
1434 if ( pFont->mbNonAntialiased )
1435 rLogFont.lfQuality = NONANTIALIASED_QUALITY;
1436
1437 // select vertical mode if requested and available
1438 if( pFont->mbVertical && nNameLen )
1439 {
1440 // vertical fonts start with an '@'
1441 memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0],
1442 sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) );
1443 rLogFont.lfFaceName[0] = '@';
1444
1445 // check availability of vertical mode for this font
1446 bool bAvailable = false;
1447 EnumFontFamiliesExW( hDC, &rLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW,
1448 (LPARAM)&bAvailable, 0 );
1449
1450 if( !bAvailable )
1451 {
1452 // restore non-vertical name if not vertical mode isn't available
1453 memcpy( &rLogFont.lfFaceName[0], aName.GetBuffer(), nNameLen*sizeof(wchar_t) );
1454 if( nNameLen < LF_FACESIZE )
1455 rLogFont.lfFaceName[nNameLen] = '\0';
1456 }
1457 }
1458 }
1459
1460 // -----------------------------------------------------------------------
1461
ImplGetLogFontFromFontSelect(HDC hDC,const ImplFontSelectData * pFont,LOGFONTA & rLogFont,bool)1462 static void ImplGetLogFontFromFontSelect( HDC hDC,
1463 const ImplFontSelectData* pFont,
1464 LOGFONTA& rLogFont,
1465 bool /*bTestVerticalAvail*/ )
1466 {
1467 ByteString aName;
1468 if( pFont->mpFontData )
1469 aName = ImplSalGetWinAnsiString( pFont->mpFontData->maName );
1470 else
1471 aName = ImplSalGetWinAnsiString( pFont->maName.GetToken( 0 ) );
1472
1473 int nNameLen = aName.Len();
1474 if( nNameLen > LF_FACESIZE )
1475 nNameLen = LF_FACESIZE;
1476 memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen );
1477 if( nNameLen < LF_FACESIZE )
1478 rLogFont.lfFaceName[nNameLen] = '\0';
1479
1480 if( !pFont->mpFontData )
1481 {
1482 rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET;
1483 rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->mePitch )
1484 | ImplFamilyToWin( pFont->meFamily );
1485 }
1486 else
1487 {
1488 const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData );
1489 rLogFont.lfCharSet = pWinFontData->GetCharSet();
1490 rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily();
1491 }
1492
1493 rLogFont.lfWeight = ImplWeightToWin( pFont->meWeight );
1494 rLogFont.lfHeight = (LONG)-pFont->mnHeight;
1495 rLogFont.lfWidth = (LONG)pFont->mnWidth;
1496 rLogFont.lfUnderline = 0;
1497 rLogFont.lfStrikeOut = 0;
1498 rLogFont.lfItalic = (pFont->meItalic) != ITALIC_NONE;
1499 rLogFont.lfEscapement = pFont->mnOrientation;
1500 rLogFont.lfOrientation = rLogFont.lfEscapement; // ignored by W98
1501 rLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1502 rLogFont.lfQuality = DEFAULT_QUALITY;
1503 rLogFont.lfOutPrecision = OUT_TT_PRECIS;
1504 if( pFont->mnOrientation )
1505 rLogFont.lfClipPrecision |= CLIP_LH_ANGLES;
1506
1507 // disable antialiasing if requested
1508 if( pFont->mbNonAntialiased )
1509 rLogFont.lfQuality = NONANTIALIASED_QUALITY;
1510
1511 // select vertical mode if requested and available
1512 if( pFont->mbVertical && nNameLen )
1513 {
1514 // vertical fonts start with an '@'
1515 memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0],
1516 sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) );
1517 rLogFont.lfFaceName[0] = '@';
1518
1519 // check availability of vertical mode for this font
1520 bool bAvailable = false;
1521 EnumFontFamiliesExA( hDC, &rLogFont, (FONTENUMPROCA)SalEnumQueryFontProcExA,
1522 (LPARAM)&bAvailable, 0 );
1523
1524 if( !bAvailable )
1525 {
1526 // restore non-vertical name if vertical mode is not supported
1527 memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen );
1528 if( nNameLen < LF_FACESIZE )
1529 rLogFont.lfFaceName[nNameLen] = '\0';
1530 }
1531 }
1532 }
1533
1534 // -----------------------------------------------------------------------
1535
ImplDoSetFont(ImplFontSelectData * i_pFont,float & o_rFontScale,HFONT & o_rOldFont)1536 HFONT WinSalGraphics::ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, HFONT& o_rOldFont )
1537 {
1538 HFONT hNewFont = 0;
1539
1540 HDC hdcScreen = 0;
1541 if( mbVirDev )
1542 // only required for virtual devices, see below for details
1543 hdcScreen = GetDC(0);
1544
1545 if( true/*aSalShlData.mbWNT*/ )
1546 {
1547 LOGFONTW aLogFont;
1548 ImplGetLogFontFromFontSelect( getHDC(), i_pFont, aLogFont, true );
1549
1550 // on the display we prefer Courier New when Courier is a
1551 // bitmap only font and we need to stretch or rotate it
1552 if( mbScreen
1553 && (i_pFont->mnWidth != 0
1554 || i_pFont->mnOrientation != 0
1555 || i_pFont->mpFontData == NULL
1556 || (i_pFont->mpFontData->GetHeight() != i_pFont->mnHeight))
1557 && !bImplSalCourierScalable
1558 && bImplSalCourierNew
1559 && (ImplSalWICompareAscii( aLogFont.lfFaceName, "Courier" ) == 0) )
1560 lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 );
1561
1562 // #i47675# limit font requests to MAXFONTHEIGHT
1563 // TODO: share MAXFONTHEIGHT font instance
1564 if( (-aLogFont.lfHeight <= MAXFONTHEIGHT)
1565 && (+aLogFont.lfWidth <= MAXFONTHEIGHT) )
1566 {
1567 o_rFontScale = 1.0;
1568 }
1569 else if( -aLogFont.lfHeight >= +aLogFont.lfWidth )
1570 {
1571 o_rFontScale = -aLogFont.lfHeight / (float)MAXFONTHEIGHT;
1572 aLogFont.lfHeight = -MAXFONTHEIGHT;
1573 aLogFont.lfWidth = FRound( aLogFont.lfWidth / o_rFontScale );
1574 }
1575 else // #i95867# also limit font widths
1576 {
1577 o_rFontScale = +aLogFont.lfWidth / (float)MAXFONTHEIGHT;
1578 aLogFont.lfWidth = +MAXFONTHEIGHT;
1579 aLogFont.lfHeight = FRound( aLogFont.lfHeight / o_rFontScale );
1580 }
1581
1582 hNewFont = ::CreateFontIndirectW( &aLogFont );
1583 if( hdcScreen )
1584 {
1585 // select font into screen hdc first to get an antialiased font
1586 // see knowledge base article 305290:
1587 // "PRB: Fonts Not Drawn Antialiased on Device Context for DirectDraw Surface"
1588 SelectFont( hdcScreen, SelectFont( hdcScreen , hNewFont ) );
1589 }
1590 o_rOldFont = ::SelectFont( getHDC(), hNewFont );
1591
1592 TEXTMETRICW aTextMetricW;
1593 if( !::GetTextMetricsW( getHDC(), &aTextMetricW ) )
1594 {
1595 // the selected font doesn't work => try a replacement
1596 // TODO: use its font fallback instead
1597 lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 );
1598 aLogFont.lfPitchAndFamily = FIXED_PITCH;
1599 HFONT hNewFont2 = CreateFontIndirectW( &aLogFont );
1600 SelectFont( getHDC(), hNewFont2 );
1601 DeleteFont( hNewFont );
1602 hNewFont = hNewFont2;
1603 }
1604 }
1605
1606 if( hdcScreen )
1607 ::ReleaseDC( NULL, hdcScreen );
1608
1609 return hNewFont;
1610 }
1611
SetFont(ImplFontSelectData * pFont,int nFallbackLevel)1612 sal_uInt16 WinSalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel )
1613 {
1614 // return early if there is no new font
1615 if( !pFont )
1616 {
1617 // deselect still active font
1618 if( mhDefFont )
1619 ::SelectFont( getHDC(), mhDefFont );
1620 // release no longer referenced font handles
1621 for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
1622 {
1623 if( mhFonts[i] )
1624 ::DeleteFont( mhFonts[i] );
1625 mhFonts[ i ] = 0;
1626 }
1627 mhDefFont = 0;
1628 return 0;
1629 }
1630
1631 DBG_ASSERT( pFont->mpFontData, "WinSalGraphics mpFontData==NULL");
1632 mpWinFontEntry[ nFallbackLevel ] = reinterpret_cast<ImplWinFontEntry*>( pFont->mpFontEntry );
1633 mpWinFontData[ nFallbackLevel ] = static_cast<const ImplWinFontData*>( pFont->mpFontData );
1634
1635 HFONT hOldFont = 0;
1636 HFONT hNewFont = ImplDoSetFont( pFont, mfFontScale, hOldFont );
1637
1638 if( !mhDefFont )
1639 {
1640 // keep default font
1641 mhDefFont = hOldFont;
1642 }
1643 else
1644 {
1645 // release no longer referenced font handles
1646 for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
1647 {
1648 if( mhFonts[i] )
1649 {
1650 ::DeleteFont( mhFonts[i] );
1651 mhFonts[i] = 0;
1652 }
1653 }
1654 }
1655
1656 // store new font in correct layer
1657 mhFonts[ nFallbackLevel ] = hNewFont;
1658 // now the font is live => update font face
1659 if( mpWinFontData[ nFallbackLevel ] )
1660 mpWinFontData[ nFallbackLevel ]->UpdateFromHDC( getHDC() );
1661
1662 if( !nFallbackLevel )
1663 {
1664 mbFontKernInit = TRUE;
1665 if ( mpFontKernPairs )
1666 {
1667 delete[] mpFontKernPairs;
1668 mpFontKernPairs = NULL;
1669 }
1670 mnFontKernPairCount = 0;
1671 }
1672
1673 mnFontCharSetCount = 0;
1674
1675 // some printers have higher internal resolution, so their
1676 // text output would be different from what we calculated
1677 // => suggest DrawTextArray to workaround this problem
1678 if ( mbPrinter )
1679 return SAL_SETFONT_USEDRAWTEXTARRAY;
1680 else
1681 return 0;
1682 }
1683
1684 // -----------------------------------------------------------------------
1685
GetFontMetric(ImplFontMetricData * pMetric,int nFallbackLevel)1686 void WinSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel )
1687 {
1688 // temporarily change the HDC to the font in the fallback level
1689 HFONT hOldFont = SelectFont( getHDC(), mhFonts[nFallbackLevel] );
1690
1691 wchar_t aFaceName[LF_FACESIZE+60];
1692 if( ::GetTextFaceW( getHDC(), sizeof(aFaceName)/sizeof(wchar_t), aFaceName ) )
1693 pMetric->maName = reinterpret_cast<const sal_Unicode*>(aFaceName);
1694
1695 // get the font metric
1696 TEXTMETRICA aWinMetric;
1697 const bool bOK = GetTextMetricsA( getHDC(), &aWinMetric );
1698 // restore the HDC to the font in the base level
1699 SelectFont( getHDC(), hOldFont );
1700 if( !bOK )
1701 return;
1702
1703 // device independent font attributes
1704 pMetric->meFamily = ImplFamilyToSal( aWinMetric.tmPitchAndFamily );;
1705 pMetric->mbSymbolFlag = (aWinMetric.tmCharSet == SYMBOL_CHARSET);
1706 pMetric->meWeight = ImplWeightToSal( aWinMetric.tmWeight );
1707 pMetric->mePitch = ImplMetricPitchToSal( aWinMetric.tmPitchAndFamily );
1708 pMetric->meItalic = aWinMetric.tmItalic ? ITALIC_NORMAL : ITALIC_NONE;
1709 pMetric->mnSlant = 0;
1710
1711 // device dependend font attributes
1712 pMetric->mbDevice = (aWinMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
1713 pMetric->mbScalableFont = (aWinMetric.tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) != 0;
1714 if( pMetric->mbScalableFont )
1715 {
1716 // check if there are kern pairs
1717 // TODO: does this work with GPOS kerning?
1718 DWORD nKernPairs = ::GetKerningPairsA( getHDC(), 0, NULL );
1719 pMetric->mbKernableFont = (nKernPairs > 0);
1720 }
1721 else
1722 {
1723 // bitmap fonts cannot be rotated directly
1724 pMetric->mnOrientation = 0;
1725 // bitmap fonts have no kerning
1726 pMetric->mbKernableFont = false;
1727 }
1728
1729 // transformation dependend font metrics
1730 pMetric->mnWidth = static_cast<int>( mfFontScale * aWinMetric.tmAveCharWidth );
1731 pMetric->mnIntLeading = static_cast<int>( mfFontScale * aWinMetric.tmInternalLeading );
1732 pMetric->mnExtLeading = static_cast<int>( mfFontScale * aWinMetric.tmExternalLeading );
1733 pMetric->mnAscent = static_cast<int>( mfFontScale * aWinMetric.tmAscent );
1734 pMetric->mnDescent = static_cast<int>( mfFontScale * aWinMetric.tmDescent );
1735
1736 // #107888# improved metric compatibility for Asian fonts...
1737 // TODO: assess workaround below for CWS >= extleading
1738 // TODO: evaluate use of aWinMetric.sTypo* members for CJK
1739 if( mpWinFontData[nFallbackLevel] && mpWinFontData[nFallbackLevel]->SupportsCJK() )
1740 {
1741 pMetric->mnIntLeading += pMetric->mnExtLeading;
1742
1743 // #109280# The line height for Asian fonts is too small.
1744 // Therefore we add half of the external leading to the
1745 // ascent, the other half is added to the descent.
1746 const long nHalfTmpExtLeading = pMetric->mnExtLeading / 2;
1747 const long nOtherHalfTmpExtLeading = pMetric->mnExtLeading - nHalfTmpExtLeading;
1748
1749 // #110641# external leading for Asian fonts.
1750 // The factor 0.3 has been confirmed with experiments.
1751 long nCJKExtLeading = static_cast<long>(0.30 * (pMetric->mnAscent + pMetric->mnDescent));
1752 nCJKExtLeading -= pMetric->mnExtLeading;
1753 pMetric->mnExtLeading = (nCJKExtLeading > 0) ? nCJKExtLeading : 0;
1754
1755 pMetric->mnAscent += nHalfTmpExtLeading;
1756 pMetric->mnDescent += nOtherHalfTmpExtLeading;
1757 }
1758
1759 pMetric->mnMinKashida = GetMinKashidaWidth();
1760 }
1761
1762 // -----------------------------------------------------------------------
1763
SalEnumCharSetsProcExA(const ENUMLOGFONTEXA * pLogFont,const NEWTEXTMETRICEXA *,DWORD,LPARAM lParam)1764 int CALLBACK SalEnumCharSetsProcExA( const ENUMLOGFONTEXA* pLogFont,
1765 const NEWTEXTMETRICEXA* /*pMetric*/,
1766 DWORD /*nFontType*/, LPARAM lParam )
1767 {
1768 WinSalGraphics* pData = (WinSalGraphics*)lParam;
1769 // Charset already in the list?
1770 for ( BYTE i = 0; i < pData->mnFontCharSetCount; i++ )
1771 {
1772 if ( pData->mpFontCharSets[i] == pLogFont->elfLogFont.lfCharSet )
1773 return 1;
1774 }
1775 pData->mpFontCharSets[pData->mnFontCharSetCount] = pLogFont->elfLogFont.lfCharSet;
1776 pData->mnFontCharSetCount++;
1777 return 1;
1778 }
1779
1780 // -----------------------------------------------------------------------
1781
ImplGetAllFontCharSets(WinSalGraphics * pData)1782 static void ImplGetAllFontCharSets( WinSalGraphics* pData )
1783 {
1784 if ( !pData->mpFontCharSets )
1785 pData->mpFontCharSets = new BYTE[256];
1786
1787 LOGFONTA aLogFont;
1788 memset( &aLogFont, 0, sizeof( aLogFont ) );
1789 aLogFont.lfCharSet = DEFAULT_CHARSET;
1790 GetTextFaceA( pData->getHDC(), sizeof( aLogFont.lfFaceName ), aLogFont.lfFaceName );
1791 EnumFontFamiliesExA( pData->getHDC(), &aLogFont, (FONTENUMPROCA)SalEnumCharSetsProcExA,
1792 (LPARAM)(void*)pData, 0 );
1793 }
1794
1795 // -----------------------------------------------------------------------
1796
ImplAddKerningPairs(WinSalGraphics * pData)1797 static void ImplAddKerningPairs( WinSalGraphics* pData )
1798 {
1799 sal_uLong nPairs = ::GetKerningPairsA( pData->getHDC(), 0, NULL );
1800 if ( !nPairs )
1801 return;
1802
1803 CHARSETINFO aInfo;
1804 if ( !TranslateCharsetInfo( (DWORD*)(sal_uLong)GetTextCharset( pData->getHDC() ), &aInfo, TCI_SRCCHARSET ) )
1805 return;
1806
1807 if ( !pData->mpFontKernPairs )
1808 pData->mpFontKernPairs = new KERNINGPAIR[nPairs];
1809 else
1810 {
1811 KERNINGPAIR* pOldPairs = pData->mpFontKernPairs;
1812 pData->mpFontKernPairs = new KERNINGPAIR[nPairs+pData->mnFontKernPairCount];
1813 memcpy( pData->mpFontKernPairs, pOldPairs,
1814 pData->mnFontKernPairCount*sizeof( KERNINGPAIR ) );
1815 delete[] pOldPairs;
1816 }
1817
1818 UINT nCP = aInfo.ciACP;
1819 sal_uLong nOldPairs = pData->mnFontKernPairCount;
1820 KERNINGPAIR* pTempPair = pData->mpFontKernPairs+pData->mnFontKernPairCount;
1821 nPairs = ::GetKerningPairsA( pData->getHDC(), nPairs, pTempPair );
1822 for ( sal_uLong i = 0; i < nPairs; i++ )
1823 {
1824 unsigned char aBuf[2];
1825 wchar_t nChar;
1826 int nLen;
1827 sal_Bool bAdd = TRUE;
1828
1829 // None-ASCII?, then we must convert the char
1830 if ( (pTempPair->wFirst > 125) || (pTempPair->wFirst == 92) )
1831 {
1832 if ( pTempPair->wFirst < 256 )
1833 {
1834 aBuf[0] = (unsigned char)pTempPair->wFirst;
1835 nLen = 1;
1836 }
1837 else
1838 {
1839 aBuf[0] = (unsigned char)(pTempPair->wFirst >> 8);
1840 aBuf[1] = (unsigned char)(pTempPair->wFirst & 0xFF);
1841 nLen = 2;
1842 }
1843 if ( MultiByteToWideChar( nCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
1844 (const char*)aBuf, nLen, &nChar, 1 ) )
1845 pTempPair->wFirst = nChar;
1846 else
1847 bAdd = FALSE;
1848 }
1849 if ( (pTempPair->wSecond > 125) || (pTempPair->wSecond == 92) )
1850 {
1851 if ( pTempPair->wSecond < 256 )
1852 {
1853 aBuf[0] = (unsigned char)pTempPair->wSecond;
1854 nLen = 1;
1855 }
1856 else
1857 {
1858 aBuf[0] = (unsigned char)(pTempPair->wSecond >> 8);
1859 aBuf[1] = (unsigned char)(pTempPair->wSecond & 0xFF);
1860 nLen = 2;
1861 }
1862 if ( MultiByteToWideChar( nCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
1863 (const char*)aBuf, nLen, &nChar, 1 ) )
1864 pTempPair->wSecond = nChar;
1865 else
1866 bAdd = FALSE;
1867 }
1868
1869 // TODO: get rid of linear search!
1870 KERNINGPAIR* pTempPair2 = pData->mpFontKernPairs;
1871 for ( sal_uLong j = 0; j < nOldPairs; j++ )
1872 {
1873 if ( (pTempPair2->wFirst == pTempPair->wFirst) &&
1874 (pTempPair2->wSecond == pTempPair->wSecond) )
1875 {
1876 bAdd = FALSE;
1877 break;
1878 }
1879 pTempPair2++;
1880 }
1881
1882 if ( bAdd )
1883 {
1884 KERNINGPAIR* pDestPair = pData->mpFontKernPairs+pData->mnFontKernPairCount;
1885 if ( pDestPair != pTempPair )
1886 memcpy( pDestPair, pTempPair, sizeof( KERNINGPAIR ) );
1887 pData->mnFontKernPairCount++;
1888 }
1889
1890 pTempPair++;
1891 }
1892 }
1893
1894 // -----------------------------------------------------------------------
1895
GetKernPairs(sal_uLong nPairs,ImplKernPairData * pKernPairs)1896 sal_uLong WinSalGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData* pKernPairs )
1897 {
1898 DBG_ASSERT( sizeof( KERNINGPAIR ) == sizeof( ImplKernPairData ),
1899 "WinSalGraphics::GetKernPairs(): KERNINGPAIR != ImplKernPairData" );
1900
1901 if ( mbFontKernInit )
1902 {
1903 if( mpFontKernPairs )
1904 {
1905 delete[] mpFontKernPairs;
1906 mpFontKernPairs = NULL;
1907 }
1908 mnFontKernPairCount = 0;
1909
1910 KERNINGPAIR* pPairs = NULL;
1911 int nCount = ::GetKerningPairsW( getHDC(), 0, NULL );
1912 if( nCount )
1913 {
1914 #ifdef GCP_KERN_HACK
1915 pPairs = new KERNINGPAIR[ nCount+1 ];
1916 mpFontKernPairs = pPairs;
1917 mnFontKernPairCount = nCount;
1918 ::GetKerningPairsW( getHDC(), nCount, pPairs );
1919 #else // GCP_KERN_HACK
1920 pPairs = pKernPairs;
1921 nCount = (nCount < nPairs) : nCount : nPairs;
1922 ::GetKerningPairsW( getHDC(), nCount, pPairs );
1923 return nCount;
1924 #endif // GCP_KERN_HACK
1925 }
1926
1927 mbFontKernInit = FALSE;
1928
1929 std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData );
1930 }
1931
1932 if( !pKernPairs )
1933 return mnFontKernPairCount;
1934 else if( mpFontKernPairs )
1935 {
1936 if ( nPairs < mnFontKernPairCount )
1937 nPairs = mnFontKernPairCount;
1938 memcpy( pKernPairs, mpFontKernPairs,
1939 nPairs*sizeof( ImplKernPairData ) );
1940 return nPairs;
1941 }
1942
1943 return 0;
1944 }
1945
1946 // -----------------------------------------------------------------------
1947
GetImplFontCharMap() const1948 const ImplFontCharMap* WinSalGraphics::GetImplFontCharMap() const
1949 {
1950 if( !mpWinFontData[0] )
1951 return ImplFontCharMap::GetDefaultMap();
1952 return mpWinFontData[0]->GetImplFontCharMap();
1953 }
1954
1955 // -----------------------------------------------------------------------
1956
SalEnumFontsProcExA(const ENUMLOGFONTEXA * pLogFont,const NEWTEXTMETRICEXA * pMetric,DWORD nFontType,LPARAM lParam)1957 int CALLBACK SalEnumFontsProcExA( const ENUMLOGFONTEXA* pLogFont,
1958 const NEWTEXTMETRICEXA* pMetric,
1959 DWORD nFontType, LPARAM lParam )
1960 {
1961 ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam;
1962 if ( !pInfo->mpName )
1963 {
1964 // Ignore vertical fonts
1965 if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
1966 {
1967 if ( !pInfo->mbImplSalCourierNew )
1968 pInfo->mbImplSalCourierNew = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0;
1969 if ( !pInfo->mbImplSalCourierScalable )
1970 pInfo->mbCourier = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0;
1971 else
1972 pInfo->mbCourier = FALSE;
1973 String aName( ImplSalGetUniString( pLogFont->elfLogFont.lfFaceName ) );
1974 pInfo->mpName = &aName;
1975 strncpy( pInfo->mpLogFontA->lfFaceName, pLogFont->elfLogFont.lfFaceName, LF_FACESIZE );
1976 pInfo->mpLogFontA->lfCharSet = pLogFont->elfLogFont.lfCharSet;
1977 EnumFontFamiliesExA( pInfo->mhDC, pInfo->mpLogFontA, (FONTENUMPROCA)SalEnumFontsProcExA,
1978 (LPARAM)(void*)pInfo, 0 );
1979 pInfo->mpLogFontA->lfFaceName[0] = '\0';
1980 pInfo->mpLogFontA->lfCharSet = DEFAULT_CHARSET;
1981 pInfo->mpName = NULL;
1982 pInfo->mbCourier = FALSE;
1983 }
1984 }
1985 else
1986 {
1987 // ignore non-scalable non-device font on printer
1988 if( pInfo->mbPrinter )
1989 if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) )
1990 return 1;
1991
1992 ImplWinFontData* pData = ImplLogMetricToDevFontDataA( pLogFont, &(pMetric->ntmTm), nFontType );
1993 pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
1994
1995 // prefer the system character set, so that we get as much as
1996 // possible important characters. In the other case we could only
1997 // display a limited set of characters (#87309#)
1998 if ( pInfo->mnPreferedCharSet == pLogFont->elfLogFont.lfCharSet )
1999 pData->mnQuality += 100;
2000
2001 // knowing Courier to be scalable is nice
2002 if( pInfo->mbCourier )
2003 pInfo->mbImplSalCourierScalable |= pData->IsScalable();
2004
2005 pInfo->mpList->Add( pData );
2006 }
2007
2008 return 1;
2009 }
2010
2011 // -----------------------------------------------------------------------
2012
SalEnumFontsProcExW(const ENUMLOGFONTEXW * pLogFont,const NEWTEXTMETRICEXW * pMetric,DWORD nFontType,LPARAM lParam)2013 int CALLBACK SalEnumFontsProcExW( const ENUMLOGFONTEXW* pLogFont,
2014 const NEWTEXTMETRICEXW* pMetric,
2015 DWORD nFontType, LPARAM lParam )
2016 {
2017 ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam;
2018 if ( !pInfo->mpName )
2019 {
2020 // Ignore vertical fonts
2021 if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
2022 {
2023 if ( !pInfo->mbImplSalCourierNew )
2024 pInfo->mbImplSalCourierNew = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0;
2025 if ( !pInfo->mbImplSalCourierScalable )
2026 pInfo->mbCourier = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0;
2027 else
2028 pInfo->mbCourier = FALSE;
2029 String aName( reinterpret_cast<const sal_Unicode*>(pLogFont->elfLogFont.lfFaceName) );
2030 pInfo->mpName = &aName;
2031 memcpy( pInfo->mpLogFontW->lfFaceName, pLogFont->elfLogFont.lfFaceName, (aName.Len()+1)*sizeof( wchar_t ) );
2032 pInfo->mpLogFontW->lfCharSet = pLogFont->elfLogFont.lfCharSet;
2033 EnumFontFamiliesExW( pInfo->mhDC, pInfo->mpLogFontW, (FONTENUMPROCW)SalEnumFontsProcExW,
2034 (LPARAM)(void*)pInfo, 0 );
2035 pInfo->mpLogFontW->lfFaceName[0] = '\0';
2036 pInfo->mpLogFontW->lfCharSet = DEFAULT_CHARSET;
2037 pInfo->mpName = NULL;
2038 pInfo->mbCourier = FALSE;
2039 }
2040 }
2041 else
2042 {
2043 // ignore non-scalable non-device font on printer
2044 if( pInfo->mbPrinter )
2045 if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) )
2046 return 1;
2047
2048 ImplWinFontData* pData = ImplLogMetricToDevFontDataW( pLogFont, &(pMetric->ntmTm), nFontType );
2049 pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
2050
2051 // knowing Courier to be scalable is nice
2052 if( pInfo->mbCourier )
2053 pInfo->mbImplSalCourierScalable |= pData->IsScalable();
2054
2055 pInfo->mpList->Add( pData );
2056 }
2057
2058 return 1;
2059 }
2060
2061 // -----------------------------------------------------------------------
2062
2063 struct TempFontItem
2064 {
2065 ::rtl::OUString maFontFilePath;
2066 ::rtl::OString maResourcePath;
2067 TempFontItem* mpNextItem;
2068 };
2069
2070 #ifdef FR_PRIVATE
__AddFontResourceExW(LPCWSTR lpszfileName,DWORD fl,PVOID pdv)2071 static int WINAPI __AddFontResourceExW( LPCWSTR lpszfileName, DWORD fl, PVOID pdv )
2072 {
2073 typedef int (WINAPI *AddFontResourceExW_FUNC)(LPCWSTR, DWORD, PVOID );
2074
2075 static AddFontResourceExW_FUNC pFunc = NULL;
2076 static HMODULE hmGDI = NULL;
2077
2078 if ( !pFunc && !hmGDI )
2079 {
2080 hmGDI = GetModuleHandleA( "GDI32" );
2081 if ( hmGDI )
2082 pFunc = reinterpret_cast<AddFontResourceExW_FUNC>( GetProcAddress( hmGDI, "AddFontResourceExW" ) );
2083 }
2084
2085 if ( pFunc )
2086 return pFunc( lpszfileName, fl, pdv );
2087 else
2088 {
2089 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
2090 return 0;
2091 }
2092 }
2093 #endif
2094
ImplAddTempFont(SalData & rSalData,const String & rFontFileURL)2095 bool ImplAddTempFont( SalData& rSalData, const String& rFontFileURL )
2096 {
2097 int nRet = 0;
2098 ::rtl::OUString aUSytemPath;
2099 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
2100
2101 #ifdef FR_PRIVATE
2102 nRet = __AddFontResourceExW( reinterpret_cast<LPCWSTR>(aUSytemPath.getStr()), FR_PRIVATE, NULL );
2103 #endif
2104
2105 if ( !nRet )
2106 {
2107 static int nCounter = 0;
2108 char aFileName[] = "soAA.fot";
2109 aFileName[2] = sal::static_int_cast<char>('A' + (15 & (nCounter>>4)));
2110 aFileName[3] = sal::static_int_cast<char>('A' + (15 & nCounter));
2111 char aResourceName[512];
2112 int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16;
2113 int nLen = ::GetTempPathA( nMaxLen, aResourceName );
2114 ::strncpy( aResourceName + nLen, aFileName, sizeof( aResourceName )- nLen );
2115 // security: end buffer in any case
2116 aResourceName[ (sizeof(aResourceName)/sizeof(*aResourceName))-1 ] = 0;
2117 ::DeleteFileA( aResourceName );
2118
2119 rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
2120 ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
2121 // TODO: font should be private => need to investigate why it doesn't work then
2122 if( !::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL ) )
2123 return false;
2124 ++nCounter;
2125
2126 nRet = ::AddFontResourceA( aResourceName );
2127 if( nRet > 0 )
2128 {
2129 TempFontItem* pNewItem = new TempFontItem;
2130 pNewItem->maResourcePath = rtl::OString( aResourceName );
2131 pNewItem->maFontFilePath = aUSytemPath.getStr();
2132 pNewItem->mpNextItem = rSalData.mpTempFontItem;
2133 rSalData.mpTempFontItem = pNewItem;
2134 }
2135 }
2136
2137 return (nRet > 0);
2138 }
2139
2140 // -----------------------------------------------------------------------
2141
ImplReleaseTempFonts(SalData & rSalData)2142 void ImplReleaseTempFonts( SalData& rSalData )
2143 {
2144 int nCount = 0;
2145 while( TempFontItem* p = rSalData.mpTempFontItem )
2146 {
2147 ++nCount;
2148 if( p->maResourcePath.getLength() )
2149 {
2150 const char* pResourcePath = p->maResourcePath.getStr();
2151 ::RemoveFontResourceA( pResourcePath );
2152 ::DeleteFileA( pResourcePath );
2153 }
2154 else
2155 {
2156 ::RemoveFontResourceW( reinterpret_cast<LPCWSTR>(p->maFontFilePath.getStr()) );
2157 }
2158
2159 rSalData.mpTempFontItem = p->mpNextItem;
2160 delete p;
2161 }
2162
2163 #ifndef FR_PRIVATE
2164 // notify every other application
2165 // unless the temp fonts were installed as private fonts
2166 if( nCount > 0 )
2167 ::PostMessage( HWND_BROADCAST, WM_FONTCHANGE, 0, NULL );
2168 #endif // FR_PRIVATE
2169 }
2170
2171 // -----------------------------------------------------------------------
2172
ImplGetFontAttrFromFile(const String & rFontFileURL,ImplDevFontAttributes & rDFA)2173 static bool ImplGetFontAttrFromFile( const String& rFontFileURL,
2174 ImplDevFontAttributes& rDFA )
2175 {
2176 ::rtl::OUString aUSytemPath;
2177 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
2178
2179 // get FontAttributes from a *fot file
2180 // TODO: use GetTTGlobalFontInfo() to access the font directly
2181 rDFA.mnQuality = 1000;
2182 rDFA.mbDevice = true;
2183 rDFA.meFamily = FAMILY_DONTKNOW;
2184 rDFA.meWidthType = WIDTH_DONTKNOW;
2185 rDFA.meWeight = WEIGHT_DONTKNOW;
2186 rDFA.meItalic = ITALIC_DONTKNOW;
2187 rDFA.mePitch = PITCH_DONTKNOW;;
2188 rDFA.mbSubsettable= true;
2189 rDFA.mbEmbeddable = false;
2190
2191 // Create temporary file name
2192 char aFileName[] = "soAAT.fot";
2193 char aResourceName[512];
2194 int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16;
2195 int nLen = ::GetTempPathA( nMaxLen, aResourceName );
2196 ::strncpy( aResourceName + nLen, aFileName, Max( 0, nMaxLen - nLen ));
2197 ::DeleteFileA( aResourceName );
2198
2199 // Create font resource file (typically with a .fot file name extension).
2200 rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
2201 ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
2202 ::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL );
2203
2204 // Open and read the font resource file
2205 rtl::OUString aFotFileName = rtl::OStringToOUString( aResourceName, osl_getThreadTextEncoding() );
2206 osl::FileBase::getFileURLFromSystemPath( aFotFileName, aFotFileName );
2207 osl::File aFotFile( aFotFileName );
2208 osl::FileBase::RC aError = aFotFile.open( osl_File_OpenFlag_Read );
2209 if( aError != osl::FileBase::E_None )
2210 return false;
2211
2212 sal_uInt64 nBytesRead = 0;
2213 char aBuffer[4096];
2214 aFotFile.read( aBuffer, sizeof( aBuffer ), nBytesRead );
2215 // clean up temporary resource file
2216 aFotFile.close();
2217 ::DeleteFileA( aResourceName );
2218
2219 // retrieve font family name from byte offset 0x4F6
2220 int i = 0x4F6;
2221 int nNameOfs = i;
2222 while( (i < nBytesRead) && (aBuffer[i++] != 0) );
2223 // skip full name
2224 while( (i < nBytesRead) && (aBuffer[i++] != 0) );
2225 // retrieve font style name
2226 int nStyleOfs = i;
2227 while( (i < nBytesRead) && (aBuffer[i++] != 0) );
2228 if( i >= nBytesRead )
2229 return false;
2230
2231 // convert byte strings to unicode
2232 rDFA.maName = String( aBuffer + nNameOfs, osl_getThreadTextEncoding() );
2233 rDFA.maStyleName = String( aBuffer + nStyleOfs, osl_getThreadTextEncoding() );
2234
2235 // byte offset 0x4C7: OS2_fsSelection
2236 const char nFSS = aBuffer[ 0x4C7 ];
2237 if( nFSS & 0x01 ) // italic
2238 rDFA.meItalic = ITALIC_NORMAL;
2239 //if( nFSS & 0x20 ) // bold
2240 // rDFA.meWeight = WEIGHT_BOLD;
2241 if( nFSS & 0x40 ) // regular
2242 {
2243 rDFA.meWeight = WEIGHT_NORMAL;
2244 rDFA.meItalic = ITALIC_NONE;
2245 }
2246
2247 // byte offsets 0x4D7/0x4D8: wingdi's FW_WEIGHT
2248 int nWinWeight = (aBuffer[0x4D7] & 0xFF) + ((aBuffer[0x4D8] & 0xFF) << 8);
2249 rDFA.meWeight = ImplWeightToSal( nWinWeight );
2250
2251 rDFA.mbSymbolFlag = false; // TODO
2252 rDFA.mePitch = PITCH_DONTKNOW; // TODO
2253
2254 // byte offset 0x4DE: pitch&family
2255 rDFA.meFamily = ImplFamilyToSal( aBuffer[0x4DE] );
2256
2257 // byte offsets 0x4C8/0x4C9: emunits
2258 // byte offsets 0x4CE/0x4CF: winascent
2259 // byte offsets 0x4D0/0x4D1: winascent+windescent-emunits
2260 // byte offsets 0x4DF/0x4E0: avgwidth
2261 //...
2262
2263 return true;
2264 }
2265
2266 // -----------------------------------------------------------------------
2267
AddTempDevFont(ImplDevFontList * pFontList,const String & rFontFileURL,const String & rFontName)2268 bool WinSalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
2269 const String& rFontFileURL, const String& rFontName )
2270 {
2271 RTL_LOGFILE_TRACE1( "WinSalGraphics::AddTempDevFont(): %s", rtl::OUStringToOString( rFontFileURL, RTL_TEXTENCODING_UTF8 ).getStr() );
2272
2273 ImplDevFontAttributes aDFA;
2274 aDFA.maName = rFontName;
2275 aDFA.mnQuality = 1000;
2276 aDFA.mbDevice = true;
2277
2278 // Search Font Name in Cache
2279 if( !rFontName.Len() && mpFontAttrCache )
2280 aDFA = mpFontAttrCache->GetFontAttr( rFontFileURL );
2281
2282 // Retrieve font name from font resource
2283 if( !aDFA.maName.Len() )
2284 {
2285 ImplGetFontAttrFromFile( rFontFileURL, aDFA );
2286 if( mpFontAttrCache && aDFA.maName.Len() )
2287 mpFontAttrCache->AddFontAttr( rFontFileURL, aDFA );
2288 }
2289
2290 if ( !aDFA.maName.Len() )
2291 return false;
2292
2293 // remember temp font for cleanup later
2294 if( !ImplAddTempFont( *GetSalData(), rFontFileURL ) )
2295 return false;
2296
2297 UINT nPreferedCharSet = DEFAULT_CHARSET;
2298
2299 // create matching FontData struct
2300 aDFA.mbSymbolFlag = false; // TODO: how to know it without accessing the font?
2301 aDFA.meFamily = FAMILY_DONTKNOW;
2302 aDFA.meWidthType = WIDTH_DONTKNOW;
2303 aDFA.meWeight = WEIGHT_DONTKNOW;
2304 aDFA.meItalic = ITALIC_DONTKNOW;
2305 aDFA.mePitch = PITCH_DONTKNOW;;
2306 aDFA.mbSubsettable= true;
2307 aDFA.mbEmbeddable = false;
2308
2309 /*
2310 // TODO: improve ImplDevFontAttributes using the "font resource file"
2311 aDFS.maName = // using "FONTRES:" from file
2312 if( rFontName != aDFS.maName )
2313 aDFS.maMapName = aFontName;
2314 */
2315
2316 ImplWinFontData* pFontData = new ImplWinFontData( aDFA, 0,
2317 sal::static_int_cast<BYTE>(nPreferedCharSet),
2318 sal::static_int_cast<BYTE>(TMPF_VECTOR|TMPF_TRUETYPE) );
2319 pFontData->SetFontId( reinterpret_cast<sal_IntPtr>(pFontData) );
2320 pFontList->Add( pFontData );
2321 return true;
2322 }
2323
2324 // -----------------------------------------------------------------------
2325
GetDevFontList(ImplDevFontList * pFontList)2326 void WinSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
2327 {
2328 // make sure all fonts are registered at least temporarily
2329 static bool bOnce = true;
2330 if( bOnce )
2331 {
2332 bOnce = false;
2333
2334 // determine font path
2335 // since we are only interested in fonts that could not be
2336 // registered before because of missing administration rights
2337 // only the font path of the user installation is needed
2338 ::rtl::OUString aPath;
2339 osl_getExecutableFile( &aPath.pData );
2340 ::rtl::OUString aExecutableFile( aPath );
2341 aPath = aPath.copy( 0, aPath.lastIndexOf('/') );
2342 String aFontDirUrl = aPath.copy( 0, aPath.lastIndexOf('/') );
2343 aFontDirUrl += String( RTL_CONSTASCII_USTRINGPARAM("/share/fonts/truetype") );
2344
2345 // collect fonts in font path that could not be registered
2346 osl::Directory aFontDir( aFontDirUrl );
2347 osl::FileBase::RC rcOSL = aFontDir.open();
2348 if( rcOSL == osl::FileBase::E_None )
2349 {
2350 osl::DirectoryItem aDirItem;
2351 String aEmptyString;
2352
2353 ::rtl::OUString aBootStrap;
2354 rtl::Bootstrap::get( String( RTL_CONSTASCII_USTRINGPARAM( "OOO_BASE_DIR" ) ), aBootStrap );
2355 aBootStrap += String( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
2356 rtl::Bootstrap aBootstrap( aBootStrap );
2357 ::rtl::OUString aUserPath;
2358 aBootstrap.getFrom( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserInstallation" ) ), aUserPath );
2359 aUserPath += String( RTL_CONSTASCII_USTRINGPARAM("/user/config/fontnames.dat") );
2360 String aBaseURL = aPath.copy( 0, aPath.lastIndexOf('/')+1 );
2361 mpFontAttrCache = new ImplFontAttrCache( aUserPath, aBaseURL );
2362
2363 while( aFontDir.getNextItem( aDirItem, 10 ) == osl::FileBase::E_None )
2364 {
2365 osl::FileStatus aFileStatus( FileStatusMask_FileURL );
2366 rcOSL = aDirItem.getFileStatus( aFileStatus );
2367 if ( rcOSL == osl::FileBase::E_None )
2368 AddTempDevFont( pFontList, aFileStatus.getFileURL(), aEmptyString );
2369 }
2370
2371 delete mpFontAttrCache; // destructor rewrites the cache file if needed
2372 mpFontAttrCache = NULL;
2373 }
2374 }
2375
2376 ImplEnumInfo aInfo;
2377 aInfo.mhDC = getHDC();
2378 aInfo.mpList = pFontList;
2379 aInfo.mpName = NULL;
2380 aInfo.mpLogFontA = NULL;
2381 aInfo.mpLogFontW = NULL;
2382 aInfo.mbCourier = false;
2383 aInfo.mbPrinter = mbPrinter;
2384 aInfo.mnFontCount = 0;
2385 if ( !mbPrinter )
2386 {
2387 aInfo.mbImplSalCourierScalable = false;
2388 aInfo.mbImplSalCourierNew = false;
2389 }
2390 else
2391 {
2392 aInfo.mbImplSalCourierScalable = true;
2393 aInfo.mbImplSalCourierNew = true;
2394 }
2395
2396 aInfo.mnPreferedCharSet = DEFAULT_CHARSET;
2397 DWORD nCP = GetACP();
2398 CHARSETINFO aCharSetInfo;
2399 if ( TranslateCharsetInfo( (DWORD*)nCP, &aCharSetInfo, TCI_SRCCODEPAGE ) )
2400 aInfo.mnPreferedCharSet = aCharSetInfo.ciCharset;
2401
2402 LOGFONTW aLogFont;
2403 memset( &aLogFont, 0, sizeof( aLogFont ) );
2404 aLogFont.lfCharSet = DEFAULT_CHARSET;
2405 aInfo.mpLogFontW = &aLogFont;
2406 EnumFontFamiliesExW( getHDC(), &aLogFont,
2407 (FONTENUMPROCW)SalEnumFontsProcExW, (LPARAM)(void*)&aInfo, 0 );
2408
2409 // Feststellen, was es fuer Courier-Schriften auf dem Bildschirm gibt,
2410 // um in SetFont() evt. Courier auf Courier New zu mappen
2411 if ( !mbPrinter )
2412 {
2413 bImplSalCourierScalable = aInfo.mbImplSalCourierScalable;
2414 bImplSalCourierNew = aInfo.mbImplSalCourierNew;
2415 }
2416
2417 // set glyph fallback hook
2418 static WinGlyphFallbackSubstititution aSubstFallback( getHDC() );
2419 pFontList->SetFallbackHook( &aSubstFallback );
2420 }
2421
2422 // ----------------------------------------------------------------------------
2423
GetDevFontSubstList(OutputDevice *)2424 void WinSalGraphics::GetDevFontSubstList( OutputDevice* )
2425 {}
2426
2427 // -----------------------------------------------------------------------
2428
GetGlyphBoundRect(sal_GlyphId aGlyphId,Rectangle & rRect)2429 bool WinSalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect )
2430 {
2431 HDC hDC = getHDC();
2432
2433 // use unity matrix
2434 MAT2 aMat;
2435 aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
2436 aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
2437
2438 UINT nGGOFlags = GGO_METRICS;
2439 if( !(aGlyphId & GF_ISCHAR) )
2440 nGGOFlags |= GGO_GLYPH_INDEX;
2441 aGlyphId &= GF_IDXMASK;
2442
2443 GLYPHMETRICS aGM;
2444 aGM.gmptGlyphOrigin.x = aGM.gmptGlyphOrigin.y = 0;
2445 aGM.gmBlackBoxX = aGM.gmBlackBoxY = 0;
2446 DWORD nSize = ::GetGlyphOutlineW( hDC, aGlyphId, nGGOFlags, &aGM, 0, NULL, &aMat );
2447 if( nSize == GDI_ERROR )
2448 return false;
2449
2450 rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
2451 Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
2452 rRect.Left() = static_cast<int>( mfFontScale * rRect.Left() );
2453 rRect.Right() = static_cast<int>( mfFontScale * rRect.Right() );
2454 rRect.Top() = static_cast<int>( mfFontScale * rRect.Top() );
2455 rRect.Bottom() = static_cast<int>( mfFontScale * rRect.Bottom() );
2456 return true;
2457 }
2458
2459 // -----------------------------------------------------------------------
2460
GetGlyphOutline(sal_GlyphId aGlyphId,::basegfx::B2DPolyPolygon & rB2DPolyPoly)2461 bool WinSalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId,
2462 ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
2463 {
2464 rB2DPolyPoly.clear();
2465
2466 HDC hDC = getHDC();
2467
2468 // use unity matrix
2469 MAT2 aMat;
2470 aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
2471 aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
2472
2473 UINT nGGOFlags = GGO_NATIVE;
2474 if( !(aGlyphId & GF_ISCHAR) )
2475 nGGOFlags |= GGO_GLYPH_INDEX;
2476 aGlyphId &= GF_IDXMASK;
2477
2478 GLYPHMETRICS aGlyphMetrics;
2479 const DWORD nSize1 = ::GetGlyphOutlineW( hDC, aGlyphId, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
2480 if( !nSize1 ) // blank glyphs are ok
2481 return true;
2482 else if( nSize1 == GDI_ERROR )
2483 return false;
2484
2485 BYTE* pData = new BYTE[ nSize1 ];
2486 const DWORD nSize2 = ::GetGlyphOutlineW( hDC, aGlyphId, nGGOFlags,
2487 &aGlyphMetrics, nSize1, pData, &aMat );
2488
2489 if( nSize1 != nSize2 )
2490 return false;
2491
2492 // TODO: avoid tools polygon by creating B2DPolygon directly
2493 int nPtSize = 512;
2494 Point* pPoints = new Point[ nPtSize ];
2495 BYTE* pFlags = new BYTE[ nPtSize ];
2496
2497 TTPOLYGONHEADER* pHeader = (TTPOLYGONHEADER*)pData;
2498 while( (BYTE*)pHeader < pData+nSize2 )
2499 {
2500 // only outline data is interesting
2501 if( pHeader->dwType != TT_POLYGON_TYPE )
2502 break;
2503
2504 // get start point; next start points are end points
2505 // of previous segment
2506 USHORT nPnt = 0;
2507
2508 long nX = IntTimes256FromFixed( pHeader->pfxStart.x );
2509 long nY = IntTimes256FromFixed( pHeader->pfxStart.y );
2510 pPoints[ nPnt ] = Point( nX, nY );
2511 pFlags[ nPnt++ ] = POLY_NORMAL;
2512
2513 bool bHasOfflinePoints = false;
2514 TTPOLYCURVE* pCurve = (TTPOLYCURVE*)( pHeader + 1 );
2515 pHeader = (TTPOLYGONHEADER*)( (BYTE*)pHeader + pHeader->cb );
2516 while( (BYTE*)pCurve < (BYTE*)pHeader )
2517 {
2518 int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx;
2519 if( nPtSize < nNeededSize )
2520 {
2521 Point* pOldPoints = pPoints;
2522 BYTE* pOldFlags = pFlags;
2523 nPtSize = 2 * nNeededSize;
2524 pPoints = new Point[ nPtSize ];
2525 pFlags = new BYTE[ nPtSize ];
2526 for( USHORT i = 0; i < nPnt; ++i )
2527 {
2528 pPoints[ i ] = pOldPoints[ i ];
2529 pFlags[ i ] = pOldFlags[ i ];
2530 }
2531 delete[] pOldPoints;
2532 delete[] pOldFlags;
2533 }
2534
2535 int i = 0;
2536 if( TT_PRIM_LINE == pCurve->wType )
2537 {
2538 while( i < pCurve->cpfx )
2539 {
2540 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2541 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2542 ++i;
2543 pPoints[ nPnt ] = Point( nX, nY );
2544 pFlags[ nPnt ] = POLY_NORMAL;
2545 ++nPnt;
2546 }
2547 }
2548 else if( TT_PRIM_QSPLINE == pCurve->wType )
2549 {
2550 bHasOfflinePoints = true;
2551 while( i < pCurve->cpfx )
2552 {
2553 // get control point of quadratic bezier spline
2554 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2555 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2556 ++i;
2557 Point aControlP( nX, nY );
2558
2559 // calculate first cubic control point
2560 // P0 = 1/3 * (PBeg + 2 * PQControl)
2561 nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X();
2562 nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y();
2563 pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
2564 pFlags[ nPnt+0 ] = POLY_CONTROL;
2565
2566 // calculate endpoint of segment
2567 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2568 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2569
2570 if ( i+1 >= pCurve->cpfx )
2571 {
2572 // endpoint is either last point in segment => advance
2573 ++i;
2574 }
2575 else
2576 {
2577 // or endpoint is the middle of two control points
2578 nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x );
2579 nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y );
2580 nX = (nX + 1) / 2;
2581 nY = (nY + 1) / 2;
2582 // no need to advance, because the current point
2583 // is the control point in next bezier spline
2584 }
2585
2586 pPoints[ nPnt+2 ] = Point( nX, nY );
2587 pFlags[ nPnt+2 ] = POLY_NORMAL;
2588
2589 // calculate second cubic control point
2590 // P1 = 1/3 * (PEnd + 2 * PQControl)
2591 nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X();
2592 nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y();
2593 pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
2594 pFlags[ nPnt+1 ] = POLY_CONTROL;
2595
2596 nPnt += 3;
2597 }
2598 }
2599
2600 // next curve segment
2601 pCurve = (TTPOLYCURVE*)&pCurve->apfx[ i ];
2602 }
2603
2604 // end point is start point for closed contour
2605 // disabled, because Polygon class closes the contour itself
2606 // pPoints[nPnt++] = pPoints[0];
2607 // #i35928#
2608 // Added again, but add only when not yet closed
2609 if(pPoints[nPnt - 1] != pPoints[0])
2610 {
2611 if( bHasOfflinePoints )
2612 pFlags[nPnt] = pFlags[0];
2613
2614 pPoints[nPnt++] = pPoints[0];
2615 }
2616
2617 // convert y-coordinates W32 -> VCL
2618 for( int i = 0; i < nPnt; ++i )
2619 pPoints[i].Y() = -pPoints[i].Y();
2620
2621 // insert into polypolygon
2622 Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : NULL) );
2623 // convert to B2DPolyPolygon
2624 // TODO: get rid of the intermediate PolyPolygon
2625 rB2DPolyPoly.append( aPoly.getB2DPolygon() );
2626 }
2627
2628 delete[] pPoints;
2629 delete[] pFlags;
2630
2631 delete[] pData;
2632
2633 // rescaling needed for the PolyPolygon conversion
2634 if( rB2DPolyPoly.count() )
2635 {
2636 const double fFactor(mfFontScale/256);
2637 rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fFactor, fFactor));
2638 }
2639
2640 return true;
2641 }
2642
2643 // -----------------------------------------------------------------------
2644
2645 class ScopedFont
2646 {
2647 public:
2648 explicit ScopedFont(WinSalGraphics & rData);
2649
2650 ~ScopedFont();
2651
2652 private:
2653 WinSalGraphics & m_rData;
2654 HFONT m_hOrigFont;
2655 };
2656
ScopedFont(WinSalGraphics & rData)2657 ScopedFont::ScopedFont(WinSalGraphics & rData): m_rData(rData)
2658 {
2659 m_hOrigFont = m_rData.mhFonts[0];
2660 m_rData.mhFonts[0] = 0; // avoid deletion of current font
2661 }
2662
~ScopedFont()2663 ScopedFont::~ScopedFont()
2664 {
2665 if( m_hOrigFont )
2666 {
2667 // restore original font, destroy temporary font
2668 HFONT hTempFont = m_rData.mhFonts[0];
2669 m_rData.mhFonts[0] = m_hOrigFont;
2670 SelectObject( m_rData.getHDC(), m_hOrigFont );
2671 DeleteObject( hTempFont );
2672 }
2673 }
2674
2675 class ScopedTrueTypeFont
2676 {
2677 public:
ScopedTrueTypeFont()2678 inline ScopedTrueTypeFont(): m_pFont(0) {}
2679
2680 ~ScopedTrueTypeFont();
2681
2682 int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum);
2683
get() const2684 inline TrueTypeFont * get() const { return m_pFont; }
2685
2686 private:
2687 TrueTypeFont * m_pFont;
2688 };
2689
~ScopedTrueTypeFont()2690 ScopedTrueTypeFont::~ScopedTrueTypeFont()
2691 {
2692 if (m_pFont != 0)
2693 CloseTTFont(m_pFont);
2694 }
2695
open(void * pBuffer,sal_uInt32 nLen,sal_uInt32 nFaceNum)2696 int ScopedTrueTypeFont::open(void * pBuffer, sal_uInt32 nLen,
2697 sal_uInt32 nFaceNum)
2698 {
2699 OSL_ENSURE(m_pFont == 0, "already open");
2700 return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont);
2701 }
2702
CreateFontSubset(const rtl::OUString & rToFile,const ImplFontData * pFont,sal_GlyphId * pGlyphIds,sal_uInt8 * pEncoding,sal_Int32 * pGlyphWidths,int nGlyphCount,FontSubsetInfo & rInfo)2703 sal_Bool WinSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
2704 const ImplFontData* pFont, sal_GlyphId* pGlyphIds, sal_uInt8* pEncoding,
2705 sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
2706 {
2707 // TODO: use more of the central font-subsetting code, move stuff there if needed
2708
2709 // create matching ImplFontSelectData
2710 // we need just enough to get to the font file data
2711 // use height=1000 for easier debugging (to match psprint's font units)
2712 ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2713
2714 // TODO: much better solution: move SetFont and restoration of old font to caller
2715 ScopedFont aOldFont(*this);
2716 float fScale = 1.0;
2717 HFONT hOldFont = 0;
2718 ImplDoSetFont( &aIFSD, fScale, hOldFont );
2719
2720 ImplWinFontData* pWinFontData = (ImplWinFontData*)aIFSD.mpFontData;
2721
2722 #if OSL_DEBUG_LEVEL > 1
2723 // get font metrics
2724 TEXTMETRICA aWinMetric;
2725 if( !::GetTextMetricsA( getHDC(), &aWinMetric ) )
2726 return FALSE;
2727
2728 DBG_ASSERT( !(aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "cannot subset device font" );
2729 DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" );
2730 #endif
2731
2732 rtl::OUString aSysPath;
2733 if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
2734 return FALSE;
2735 const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
2736 const ByteString aToFile( aSysPath.getStr(), (xub_StrLen)aSysPath.getLength(), aThreadEncoding );
2737
2738 // check if the font has a CFF-table
2739 const DWORD nCffTag = CalcTag( "CFF " );
2740 const RawFontData aRawCffData( getHDC(), nCffTag );
2741 if( aRawCffData.get() )
2742 {
2743 pWinFontData->UpdateFromHDC( getHDC() );
2744 const ImplFontCharMap* pCharMap = pWinFontData->GetImplFontCharMap();
2745 pCharMap->AddReference();
2746
2747 sal_GlyphId aRealGlyphIds[ 256 ];
2748 for( int i = 0; i < nGlyphCount; ++i )
2749 {
2750 // TODO: remap notdef glyph if needed
2751 // TODO: use GDI's GetGlyphIndices instead? Does it handle GSUB properly?
2752 sal_GlyphId aGlyphId = pGlyphIds[i] & GF_IDXMASK;
2753 if( pGlyphIds[i] & GF_ISCHAR ) // remaining pseudo-glyphs need to be translated
2754 aGlyphId = pCharMap->GetGlyphIndex( aGlyphId );
2755 if( (pGlyphIds[i] & (GF_ROTMASK|GF_GSUB)) != 0) // TODO: vertical substitution
2756 {/*####*/}
2757
2758 aRealGlyphIds[i] = aGlyphId;
2759 }
2760
2761 pCharMap->DeReference(); // TODO: and and use a RAII object
2762
2763 // provide a font subset from the CFF-table
2764 FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
2765 rInfo.LoadFont( FontSubsetInfo::CFF_FONT, aRawCffData.get(), aRawCffData.size() );
2766 bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL,
2767 aRealGlyphIds, pEncoding, nGlyphCount, pGlyphWidths );
2768 fclose( pOutFile );
2769 return bRC;
2770 }
2771
2772 // get raw font file data
2773 const RawFontData xRawFontData( getHDC(), NULL );
2774 if( !xRawFontData.get() )
2775 return FALSE;
2776
2777 // open font file
2778 sal_uInt32 nFaceNum = 0;
2779 if( !*xRawFontData.get() ) // TTC candidate
2780 nFaceNum = ~0U; // indicate "TTC font extracts only"
2781
2782 ScopedTrueTypeFont aSftTTF;
2783 int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
2784 if( nRC != SF_OK )
2785 return FALSE;
2786
2787 TTGlobalFontInfo aTTInfo;
2788 ::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
2789 rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF;
2790 rInfo.m_aPSName = ImplSalGetUniString( aTTInfo.psname );
2791 rInfo.m_nAscent = aTTInfo.winAscent;
2792 rInfo.m_nDescent = aTTInfo.winDescent;
2793 rInfo.m_aFontBBox = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
2794 Point( aTTInfo.xMax, aTTInfo.yMax ) );
2795 rInfo.m_nCapHeight = aTTInfo.yMax; // Well ...
2796
2797 // subset TTF-glyphs and get their properties
2798 // take care that subset fonts require the NotDef glyph in pos 0
2799 int nOrigCount = nGlyphCount;
2800 sal_uInt16 aShortIDs[ 256 ];
2801 sal_uInt8 aTempEncs[ 256 ];
2802
2803 int nNotDef=-1, i;
2804 for( i = 0; i < nGlyphCount; ++i )
2805 {
2806 aTempEncs[i] = pEncoding[i];
2807 sal_GlyphId aGlyphId = pGlyphIds[i] & GF_IDXMASK;
2808 if( pGlyphIds[i] & GF_ISCHAR )
2809 {
2810 sal_Unicode cChar = static_cast<sal_Unicode>(aGlyphId); // TODO: sal_UCS4
2811 const bool bVertical = ((pGlyphIds[i] & (GF_ROTMASK|GF_GSUB)) != 0);
2812 aGlyphId = ::MapChar( aSftTTF.get(), cChar, bVertical );
2813 if( (aGlyphId == 0) && pFont->IsSymbolFont() )
2814 {
2815 // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
2816 cChar = (cChar & 0xF000) ? (cChar & 0x00FF) : (cChar | 0xF000);
2817 aGlyphId = ::MapChar( aSftTTF.get(), cChar, bVertical );
2818 }
2819 }
2820 aShortIDs[i] = static_cast<sal_uInt16>( aGlyphId );
2821 if( !aGlyphId )
2822 if( nNotDef < 0 )
2823 nNotDef = i; // first NotDef glyph found
2824 }
2825
2826 if( nNotDef != 0 )
2827 {
2828 // add fake NotDef glyph if needed
2829 if( nNotDef < 0 )
2830 nNotDef = nGlyphCount++;
2831
2832 // NotDef glyph must be in pos 0 => swap glyphids
2833 aShortIDs[ nNotDef ] = aShortIDs[0];
2834 aTempEncs[ nNotDef ] = aTempEncs[0];
2835 aShortIDs[0] = 0;
2836 aTempEncs[0] = 0;
2837 }
2838 DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
2839
2840 // fill pWidth array
2841 TTSimpleGlyphMetrics* pMetrics =
2842 ::GetTTSimpleGlyphMetrics( aSftTTF.get(), aShortIDs, nGlyphCount, aIFSD.mbVertical );
2843 if( !pMetrics )
2844 return FALSE;
2845 sal_uInt16 nNotDefAdv = pMetrics[0].adv;
2846 pMetrics[0].adv = pMetrics[nNotDef].adv;
2847 pMetrics[nNotDef].adv = nNotDefAdv;
2848 for( i = 0; i < nOrigCount; ++i )
2849 pGlyphWidths[i] = pMetrics[i].adv;
2850 free( pMetrics );
2851
2852 // write subset into destination file
2853 nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.GetBuffer(), aShortIDs,
2854 aTempEncs, nGlyphCount, 0, NULL, 0 );
2855 return (nRC == SF_OK);
2856 }
2857
2858 //--------------------------------------------------------------------------
2859
GetEmbedFontData(const ImplFontData * pFont,const sal_Unicode * pUnicodes,sal_Int32 * pCharWidths,FontSubsetInfo & rInfo,long * pDataLen)2860 const void* WinSalGraphics::GetEmbedFontData( const ImplFontData* pFont,
2861 const sal_Unicode* pUnicodes, sal_Int32* pCharWidths,
2862 FontSubsetInfo& rInfo, long* pDataLen )
2863 {
2864 // create matching ImplFontSelectData
2865 // we need just enough to get to the font file data
2866 ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2867
2868 // TODO: much better solution: move SetFont and restoration of old font to caller
2869 ScopedFont aOldFont(*this);
2870 SetFont( &aIFSD, 0 );
2871
2872 // get the raw font file data
2873 RawFontData aRawFontData( getHDC() );
2874 *pDataLen = aRawFontData.size();
2875 if( !aRawFontData.get() )
2876 return NULL;
2877
2878 // get important font properties
2879 TEXTMETRICA aTm;
2880 if( !::GetTextMetricsA( getHDC(), &aTm ) )
2881 *pDataLen = 0;
2882 const bool bPFA = (*aRawFontData.get() < 0x80);
2883 rInfo.m_nFontType = bPFA ? FontSubsetInfo::TYPE1_PFA : FontSubsetInfo::TYPE1_PFB;
2884 WCHAR aFaceName[64];
2885 int nFNLen = ::GetTextFaceW( getHDC(), 64, aFaceName );
2886 // #i59854# strip eventual null byte
2887 while( nFNLen > 0 && aFaceName[nFNLen-1] == 0 )
2888 nFNLen--;
2889 if( nFNLen == 0 )
2890 *pDataLen = 0;
2891 rInfo.m_aPSName = String( reinterpret_cast<const sal_Unicode*>(aFaceName), sal::static_int_cast<sal_uInt16>(nFNLen) );
2892 rInfo.m_nAscent = +aTm.tmAscent;
2893 rInfo.m_nDescent = -aTm.tmDescent;
2894 rInfo.m_aFontBBox = Rectangle( Point( -aTm.tmOverhang, -aTm.tmDescent ),
2895 Point( aTm.tmMaxCharWidth, aTm.tmAscent+aTm.tmExternalLeading ) );
2896 rInfo.m_nCapHeight = aTm.tmAscent; // Well ...
2897
2898 // get individual character widths
2899 for( int i = 0; i < 256; ++i )
2900 {
2901 int nCharWidth = 0;
2902 const sal_Unicode cChar = pUnicodes[i];
2903 if( !::GetCharWidth32W( getHDC(), cChar, cChar, &nCharWidth ) )
2904 *pDataLen = 0;
2905 pCharWidths[i] = nCharWidth;
2906 }
2907
2908 if( !*pDataLen )
2909 return NULL;
2910
2911 const unsigned char* pData = aRawFontData.steal();
2912 return (void*)pData;
2913 }
2914
2915 //--------------------------------------------------------------------------
2916
FreeEmbedFontData(const void * pData,long)2917 void WinSalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ )
2918 {
2919 delete[] reinterpret_cast<char*>(const_cast<void*>(pData));
2920 }
2921
2922 //--------------------------------------------------------------------------
2923
GetFontEncodingVector(const ImplFontData * pFont,const Ucs2OStrMap ** pNonEncoded)2924 const Ucs2SIntMap* WinSalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
2925 {
2926 // TODO: even for builtin fonts we get here... why?
2927 if( !pFont->IsEmbeddable() )
2928 return NULL;
2929
2930 // fill the encoding vector
2931 // currently no nonencoded vector
2932 if( pNonEncoded )
2933 *pNonEncoded = NULL;
2934
2935 const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>(pFont);
2936 const Ucs2SIntMap* pEncoding = pWinFontData->GetEncodingVector();
2937 if( pEncoding == NULL )
2938 {
2939 Ucs2SIntMap* pNewEncoding = new Ucs2SIntMap;
2940 #if 0
2941 // TODO: get correct encoding vector
2942 GLYPHSET aGlyphSet;
2943 aGlyphSet.cbThis = sizeof(aGlyphSet);
2944 DWORD aW = ::GetFontUnicodeRanges( getHDC(), &aGlyphSet);
2945 #else
2946 for( sal_Unicode i = 32; i < 256; ++i )
2947 (*pNewEncoding)[i] = i;
2948 #endif
2949 pWinFontData->SetEncodingVector( pNewEncoding );
2950 pEncoding = pNewEncoding;
2951 }
2952
2953 return pEncoding;
2954 }
2955
2956 //--------------------------------------------------------------------------
2957
GetGlyphWidths(const ImplFontData * pFont,bool bVertical,Int32Vector & rWidths,Ucs2UIntMap & rUnicodeEnc)2958 void WinSalGraphics::GetGlyphWidths( const ImplFontData* pFont,
2959 bool bVertical,
2960 Int32Vector& rWidths,
2961 Ucs2UIntMap& rUnicodeEnc )
2962 {
2963 // create matching ImplFontSelectData
2964 // we need just enough to get to the font file data
2965 ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2966
2967 // TODO: much better solution: move SetFont and restoration of old font to caller
2968 ScopedFont aOldFont(*this);
2969
2970 float fScale = 0.0;
2971 HFONT hOldFont = 0;
2972 ImplDoSetFont( &aIFSD, fScale, hOldFont );
2973
2974 if( pFont->IsSubsettable() )
2975 {
2976 // get raw font file data
2977 const RawFontData xRawFontData( getHDC() );
2978 if( !xRawFontData.get() )
2979 return;
2980
2981 // open font file
2982 sal_uInt32 nFaceNum = 0;
2983 if( !*xRawFontData.get() ) // TTC candidate
2984 nFaceNum = ~0U; // indicate "TTC font extracts only"
2985
2986 ScopedTrueTypeFont aSftTTF;
2987 int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
2988 if( nRC != SF_OK )
2989 return;
2990
2991 int nGlyphs = GetTTGlyphCount( aSftTTF.get() );
2992 if( nGlyphs > 0 )
2993 {
2994 rWidths.resize(nGlyphs);
2995 std::vector<sal_uInt16> aGlyphIds(nGlyphs);
2996 for( int i = 0; i < nGlyphs; i++ )
2997 aGlyphIds[i] = sal_uInt16(i);
2998 TTSimpleGlyphMetrics* pMetrics = ::GetTTSimpleGlyphMetrics( aSftTTF.get(),
2999 &aGlyphIds[0],
3000 nGlyphs,
3001 bVertical ? 1 : 0 );
3002 if( pMetrics )
3003 {
3004 for( int i = 0; i< nGlyphs; i++ )
3005 rWidths[i] = pMetrics[i].adv;
3006 free( pMetrics );
3007 rUnicodeEnc.clear();
3008 }
3009 const ImplWinFontData* pWinFont = static_cast<const ImplWinFontData*>(pFont);
3010 const ImplFontCharMap* pMap = pWinFont->GetImplFontCharMap();
3011 DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" );
3012 pMap->AddReference();
3013
3014 int nCharCount = pMap->GetCharCount();
3015 sal_uInt32 nChar = pMap->GetFirstChar();
3016 for( int i = 0; i < nCharCount; i++ )
3017 {
3018 if( nChar < 0x00010000 )
3019 {
3020 sal_uInt16 nGlyph = ::MapChar( aSftTTF.get(),
3021 static_cast<sal_Ucs>(nChar),
3022 bVertical ? 1 : 0 );
3023 if( nGlyph )
3024 rUnicodeEnc[ static_cast<sal_Unicode>(nChar) ] = nGlyph;
3025 }
3026 nChar = pMap->GetNextChar( nChar );
3027 }
3028
3029 pMap->DeReference(); // TODO: and and use a RAII object
3030 }
3031 }
3032 else if( pFont->IsEmbeddable() )
3033 {
3034 // get individual character widths
3035 rWidths.clear();
3036 rUnicodeEnc.clear();
3037 rWidths.reserve( 224 );
3038 for( sal_Unicode i = 32; i < 256; ++i )
3039 {
3040 int nCharWidth = 0;
3041 if( ::GetCharWidth32W( getHDC(), i, i, &nCharWidth ) )
3042 {
3043 rUnicodeEnc[ i ] = rWidths.size();
3044 rWidths.push_back( nCharWidth );
3045 }
3046 }
3047 }
3048 }
3049
3050 //--------------------------------------------------------------------------
3051
DrawServerFontLayout(const ServerFontLayout &)3052 void WinSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
3053 {}
3054
3055 //--------------------------------------------------------------------------
3056
GetSysFontData(int nFallbacklevel) const3057 SystemFontData WinSalGraphics::GetSysFontData( int nFallbacklevel ) const
3058 {
3059 SystemFontData aSysFontData;
3060
3061 if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
3062 if (nFallbacklevel < 0 ) nFallbacklevel = 0;
3063
3064 aSysFontData.nSize = sizeof( SystemFontData );
3065 aSysFontData.hFont = mhFonts[nFallbacklevel];
3066 aSysFontData.bFakeBold = false;
3067 aSysFontData.bFakeItalic = false;
3068 aSysFontData.bAntialias = true;
3069 aSysFontData.bVerticalCharacterType = false;
3070
3071 OSL_TRACE("\r\n:WinSalGraphics::GetSysFontData(): FontID: %p, Fallback level: %d",
3072 aSysFontData.hFont,
3073 nFallbacklevel);
3074
3075 return aSysFontData;
3076 }
3077
3078 //--------------------------------------------------------------------------
3079
3080