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 93 inline FIXED FixedFromDouble( double d ) 94 { 95 const long l = (long) ( d * 65536. ); 96 return *(FIXED*) &l; 97 } 98 99 // ----------------------------------------------------------------------- 100 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 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 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 220 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 229 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 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 ); 257 ~RawFontData() { delete[] mpRawBytes; } 258 const unsigned char* get() const { return mpRawBytes; } 259 const unsigned char* steal() { unsigned char* p = mpRawBytes; mpRawBytes = NULL; return p; } 260 const int size() const { return mnByteCount; } 261 262 private: 263 unsigned char* mpRawBytes; 264 int mnByteCount; 265 }; 266 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 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 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? 499 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? 551 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1143 ImplWinFontData::~ImplWinFontData() 1144 { 1145 delete[] mpFontCharSets; 1146 1147 if( mpUnicodeMap ) 1148 mpUnicodeMap->DeReference(); 1149 delete mpEncodingVector; 1150 } 1151 1152 // ----------------------------------------------------------------------- 1153 1154 sal_IntPtr ImplWinFontData::GetFontId() const 1155 { 1156 return mnId; 1157 } 1158 1159 // ----------------------------------------------------------------------- 1160 1161 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 1195 bool ImplWinFontData::HasGSUBstitutions( HDC hDC ) const 1196 { 1197 if( !mbGsubRead ) 1198 ReadGsubTable( hDC ); 1199 return !maGsubTable.empty(); 1200 } 1201 1202 // ----------------------------------------------------------------------- 1203 1204 bool ImplWinFontData::IsGSUBstituted( sal_UCS4 cChar ) const 1205 { 1206 return( maGsubTable.find( cChar ) != maGsubTable.end() ); 1207 } 1208 1209 // ----------------------------------------------------------------------- 1210 1211 const ImplFontCharMap* ImplWinFontData::GetImplFontCharMap() const 1212 { 1213 if( !mpUnicodeMap ) 1214 return NULL; 1215 return mpUnicodeMap; 1216 } 1217 1218 // ----------------------------------------------------------------------- 1219 1220 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);} 1221 static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);} 1222 //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));} 1223 static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); } 1224 1225 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 1256 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 1303 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1948 const ImplFontCharMap* WinSalGraphics::GetImplFontCharMap() const 1949 { 1950 if( !mpWinFontData[0] ) 1951 return ImplFontCharMap::GetDefaultMap(); 1952 return mpWinFontData[0]->GetImplFontCharMap(); 1953 } 1954 1955 // ----------------------------------------------------------------------- 1956 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 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 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 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 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 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 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 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("/Basis/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( "BRAND_BASE_DIR" ) ), aBootStrap ); 2355 aBootStrap += String( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) ); 2356 rtl::Bootstrap aBootstrap( aBootStrap ); 2357 ::rtl::OUString aUserPath; 2358 aBootstrap.getFrom( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserInstallation" ) ), aUserPath ); 2359 aUserPath += String( RTL_CONSTASCII_USTRINGPARAM("/user/config/fontnames.dat") ); 2360 String aBaseURL = aPath.copy( 0, aPath.lastIndexOf('/')+1 ); 2361 mpFontAttrCache = new ImplFontAttrCache( aUserPath, aBaseURL ); 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 2424 void WinSalGraphics::GetDevFontSubstList( OutputDevice* ) 2425 {} 2426 2427 // ----------------------------------------------------------------------- 2428 2429 sal_Bool WinSalGraphics::GetGlyphBoundRect( long nIndex, 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( !(nIndex & GF_ISCHAR) ) 2440 nGGOFlags |= GGO_GLYPH_INDEX; 2441 nIndex &= 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, nIndex, 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 2461 sal_Bool WinSalGraphics::GetGlyphOutline( long nIndex, 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( !(nIndex & GF_ISCHAR) ) 2475 nGGOFlags |= GGO_GLYPH_INDEX; 2476 nIndex &= GF_IDXMASK; 2477 2478 GLYPHMETRICS aGlyphMetrics; 2479 const DWORD nSize1 = ::GetGlyphOutlineW( hDC, nIndex, 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, nIndex, 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 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 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: 2678 inline ScopedTrueTypeFont(): m_pFont(0) {} 2679 2680 ~ScopedTrueTypeFont(); 2681 2682 int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum); 2683 2684 inline TrueTypeFont * get() const { return m_pFont; } 2685 2686 private: 2687 TrueTypeFont * m_pFont; 2688 }; 2689 2690 ScopedTrueTypeFont::~ScopedTrueTypeFont() 2691 { 2692 if (m_pFont != 0) 2693 CloseTTFont(m_pFont); 2694 } 2695 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 2703 sal_Bool WinSalGraphics::CreateFontSubset( const rtl::OUString& rToFile, 2704 const ImplFontData* pFont, long* pGlyphIDs, sal_uInt8* pEncoding, 2705 sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo ) 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 long nRealGlyphIds[ 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_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK; 2753 if( pGlyphIDs[i] & GF_ISCHAR ) // remaining pseudo-glyphs need to be translated 2754 nGlyphIdx = pCharMap->GetGlyphIndex( nGlyphIdx ); 2755 if( (pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0) // TODO: vertical substitution 2756 {/*####*/} 2757 2758 nRealGlyphIds[i] = nGlyphIdx; 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 nRealGlyphIds, 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_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK; 2808 if( pGlyphIDs[i] & GF_ISCHAR ) 2809 { 2810 sal_Unicode cChar = static_cast<sal_Unicode>(nGlyphIdx); // TODO: sal_UCS4 2811 const bool bVertical = ((pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0); 2812 nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical ); 2813 if( (nGlyphIdx == 0) && pFont->IsSymbolFont() ) 2814 { 2815 // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX 2816 cChar = (cChar & 0xF000) ? (cChar & 0x00FF) : (cChar | 0xF000); 2817 nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical ); 2818 } 2819 } 2820 aShortIDs[i] = static_cast<sal_uInt16>( nGlyphIdx ); 2821 if( !nGlyphIdx ) 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 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 2917 void WinSalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ ) 2918 { 2919 delete[] reinterpret_cast<char*>(const_cast<void*>(pData)); 2920 } 2921 2922 //-------------------------------------------------------------------------- 2923 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 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 3052 void WinSalGraphics::DrawServerFontLayout( const ServerFontLayout& ) 3053 {} 3054 3055 //-------------------------------------------------------------------------- 3056 3057 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