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 for( int i = 0; i < nTestFontCount; ++i ) 609 { 610 const ImplFontData* pFace = pTestFontList->Get( i ); 611 if( !HasMissingChars( pFace, rMissingChars ) ) 612 continue; 613 rFontSelData.maSearchName = pFace->maName; 614 return true; 615 } 616 617 return false; 618 } 619 620 // ======================================================================= 621 622 struct ImplEnumInfo 623 { 624 HDC mhDC; 625 ImplDevFontList* mpList; 626 String* mpName; 627 LOGFONTA* mpLogFontA; 628 LOGFONTW* mpLogFontW; 629 UINT mnPreferedCharSet; 630 bool mbCourier; 631 bool mbImplSalCourierScalable; 632 bool mbImplSalCourierNew; 633 bool mbPrinter; 634 int mnFontCount; 635 }; 636 637 // ======================================================================= 638 639 static CharSet ImplCharSetToSal( BYTE nCharSet ) 640 { 641 rtl_TextEncoding eTextEncoding; 642 643 if ( nCharSet == OEM_CHARSET ) 644 { 645 UINT nCP = (sal_uInt16)GetOEMCP(); 646 switch ( nCP ) 647 { 648 // It is unclear why these two (undefined?) code page numbers are 649 // handled specially here: 650 case 1004: eTextEncoding = RTL_TEXTENCODING_MS_1252; break; 651 case 65400: eTextEncoding = RTL_TEXTENCODING_SYMBOL; break; 652 default: 653 eTextEncoding = rtl_getTextEncodingFromWindowsCodePage(nCP); 654 break; 655 }; 656 } 657 else 658 { 659 if( nCharSet ) 660 eTextEncoding = rtl_getTextEncodingFromWindowsCharset( nCharSet ); 661 else 662 eTextEncoding = RTL_TEXTENCODING_UNICODE; 663 } 664 665 return eTextEncoding; 666 } 667 668 // ----------------------------------------------------------------------- 669 670 static FontFamily ImplFamilyToSal( BYTE nFamily ) 671 { 672 switch ( nFamily & 0xF0 ) 673 { 674 case FF_DECORATIVE: 675 return FAMILY_DECORATIVE; 676 677 case FF_MODERN: 678 return FAMILY_MODERN; 679 680 case FF_ROMAN: 681 return FAMILY_ROMAN; 682 683 case FF_SCRIPT: 684 return FAMILY_SCRIPT; 685 686 case FF_SWISS: 687 return FAMILY_SWISS; 688 689 default: 690 break; 691 } 692 693 return FAMILY_DONTKNOW; 694 } 695 696 // ----------------------------------------------------------------------- 697 698 static BYTE ImplFamilyToWin( FontFamily eFamily ) 699 { 700 switch ( eFamily ) 701 { 702 case FAMILY_DECORATIVE: 703 return FF_DECORATIVE; 704 705 case FAMILY_MODERN: 706 return FF_MODERN; 707 708 case FAMILY_ROMAN: 709 return FF_ROMAN; 710 711 case FAMILY_SCRIPT: 712 return FF_SCRIPT; 713 714 case FAMILY_SWISS: 715 return FF_SWISS; 716 717 case FAMILY_SYSTEM: 718 return FF_SWISS; 719 720 default: 721 break; 722 } 723 724 return FF_DONTCARE; 725 } 726 727 // ----------------------------------------------------------------------- 728 729 static FontWeight ImplWeightToSal( int nWeight ) 730 { 731 if ( nWeight <= FW_THIN ) 732 return WEIGHT_THIN; 733 else if ( nWeight <= FW_ULTRALIGHT ) 734 return WEIGHT_ULTRALIGHT; 735 else if ( nWeight <= FW_LIGHT ) 736 return WEIGHT_LIGHT; 737 else if ( nWeight < FW_MEDIUM ) 738 return WEIGHT_NORMAL; 739 else if ( nWeight == FW_MEDIUM ) 740 return WEIGHT_MEDIUM; 741 else if ( nWeight <= FW_SEMIBOLD ) 742 return WEIGHT_SEMIBOLD; 743 else if ( nWeight <= FW_BOLD ) 744 return WEIGHT_BOLD; 745 else if ( nWeight <= FW_ULTRABOLD ) 746 return WEIGHT_ULTRABOLD; 747 else 748 return WEIGHT_BLACK; 749 } 750 751 // ----------------------------------------------------------------------- 752 753 static int ImplWeightToWin( FontWeight eWeight ) 754 { 755 switch ( eWeight ) 756 { 757 case WEIGHT_THIN: 758 return FW_THIN; 759 760 case WEIGHT_ULTRALIGHT: 761 return FW_ULTRALIGHT; 762 763 case WEIGHT_LIGHT: 764 return FW_LIGHT; 765 766 case WEIGHT_SEMILIGHT: 767 case WEIGHT_NORMAL: 768 return FW_NORMAL; 769 770 case WEIGHT_MEDIUM: 771 return FW_MEDIUM; 772 773 case WEIGHT_SEMIBOLD: 774 return FW_SEMIBOLD; 775 776 case WEIGHT_BOLD: 777 return FW_BOLD; 778 779 case WEIGHT_ULTRABOLD: 780 return FW_ULTRABOLD; 781 782 case WEIGHT_BLACK: 783 return FW_BLACK; 784 785 default: 786 break; 787 } 788 789 return 0; 790 } 791 792 // ----------------------------------------------------------------------- 793 794 inline FontPitch ImplLogPitchToSal( BYTE nPitch ) 795 { 796 if ( nPitch & FIXED_PITCH ) 797 return PITCH_FIXED; 798 else 799 return PITCH_VARIABLE; 800 } 801 802 // ----------------------------------------------------------------------- 803 804 inline FontPitch ImplMetricPitchToSal( BYTE nPitch ) 805 { 806 // Sausaecke bei MS !! siehe NT Hilfe 807 if ( !(nPitch & TMPF_FIXED_PITCH) ) 808 return PITCH_FIXED; 809 else 810 return PITCH_VARIABLE; 811 } 812 813 // ----------------------------------------------------------------------- 814 815 inline BYTE ImplPitchToWin( FontPitch ePitch ) 816 { 817 if ( ePitch == PITCH_FIXED ) 818 return FIXED_PITCH; 819 else if ( ePitch == PITCH_VARIABLE ) 820 return VARIABLE_PITCH; 821 else 822 return DEFAULT_PITCH; 823 } 824 825 // ----------------------------------------------------------------------- 826 827 static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXA& rEnumFont, 828 const NEWTEXTMETRICA& rMetric, DWORD nFontType ) 829 { 830 ImplDevFontAttributes aDFA; 831 832 const LOGFONTA rLogFont = rEnumFont.elfLogFont; 833 834 // get font face attributes 835 aDFA.meFamily = ImplFamilyToSal( rLogFont.lfPitchAndFamily ); 836 aDFA.meWidthType = WIDTH_DONTKNOW; 837 aDFA.meWeight = ImplWeightToSal( rLogFont.lfWeight ); 838 aDFA.meItalic = (rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE; 839 aDFA.mePitch = ImplLogPitchToSal( rLogFont.lfPitchAndFamily ); 840 aDFA.mbSymbolFlag = (rLogFont.lfCharSet == SYMBOL_CHARSET); 841 842 // get the font face name 843 aDFA.maName = ImplSalGetUniString( rLogFont.lfFaceName ); 844 845 // use the face's style name only if it looks reasonable 846 const char* pStyleName = (const char*)rEnumFont.elfStyle; 847 const char* pEnd = pStyleName + sizeof( rEnumFont.elfStyle ); 848 const char* p = pStyleName; 849 for(; *p && (p < pEnd); ++p ) 850 if( (0x00 < *p) && (*p < 0x20) ) 851 break; 852 if( p < pEnd ) 853 aDFA.maStyleName = ImplSalGetUniString( pStyleName ); 854 855 // get device specific font attributes 856 aDFA.mbOrientation = (nFontType & RASTER_FONTTYPE) == 0; 857 aDFA.mbDevice = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0; 858 859 aDFA.mbEmbeddable = false; 860 aDFA.mbSubsettable = false; 861 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) 862 || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE)) 863 aDFA.mbSubsettable = true; 864 else if( 0 != (rMetric.ntmFlags & NTM_TYPE1) ) // TODO: implement subsetting for type1 too 865 aDFA.mbEmbeddable = true; 866 867 // heuristics for font quality 868 // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster 869 // - subsetting > embedding > none 870 aDFA.mnQuality = 0; 871 if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE ) 872 aDFA.mnQuality += 50; 873 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) ) 874 aDFA.mnQuality += 10; 875 if( aDFA.mbSubsettable ) 876 aDFA.mnQuality += 200; 877 else if( aDFA.mbEmbeddable ) 878 aDFA.mnQuality += 100; 879 880 // #i38665# prefer Type1 versions of the standard postscript fonts 881 if( aDFA.mbEmbeddable ) 882 { 883 if( aDFA.maName.EqualsAscii( "AvantGarde" ) 884 || aDFA.maName.EqualsAscii( "Bookman" ) 885 || aDFA.maName.EqualsAscii( "Courier" ) 886 || aDFA.maName.EqualsAscii( "Helvetica" ) 887 || aDFA.maName.EqualsAscii( "NewCenturySchlbk" ) 888 || aDFA.maName.EqualsAscii( "Palatino" ) 889 || aDFA.maName.EqualsAscii( "Symbol" ) 890 || aDFA.maName.EqualsAscii( "Times" ) 891 || aDFA.maName.EqualsAscii( "ZapfChancery" ) 892 || aDFA.maName.EqualsAscii( "ZapfDingbats" ) ) 893 aDFA.mnQuality += 500; 894 } 895 896 // TODO: add alias names 897 return aDFA; 898 } 899 900 // ----------------------------------------------------------------------- 901 902 static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXW& rEnumFont, 903 const NEWTEXTMETRICW& rMetric, DWORD nFontType ) 904 { 905 ImplDevFontAttributes aDFA; 906 907 const LOGFONTW rLogFont = rEnumFont.elfLogFont; 908 909 // get font face attributes 910 aDFA.meFamily = ImplFamilyToSal( rLogFont.lfPitchAndFamily ); 911 aDFA.meWidthType = WIDTH_DONTKNOW; 912 aDFA.meWeight = ImplWeightToSal( rLogFont.lfWeight ); 913 aDFA.meItalic = (rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE; 914 aDFA.mePitch = ImplLogPitchToSal( rLogFont.lfPitchAndFamily ); 915 aDFA.mbSymbolFlag = (rLogFont.lfCharSet == SYMBOL_CHARSET); 916 917 // get the font face name 918 aDFA.maName = reinterpret_cast<const sal_Unicode*>(rLogFont.lfFaceName); 919 920 // use the face's style name only if it looks reasonable 921 const wchar_t* pStyleName = rEnumFont.elfStyle; 922 const wchar_t* pEnd = pStyleName + sizeof(rEnumFont.elfStyle)/sizeof(*rEnumFont.elfStyle); 923 const wchar_t* p = pStyleName; 924 for(; *p && (p < pEnd); ++p ) 925 if( *p < 0x0020 ) 926 break; 927 if( p < pEnd ) 928 aDFA.maStyleName = reinterpret_cast<const sal_Unicode*>(pStyleName); 929 930 // get device specific font attributes 931 aDFA.mbOrientation = (nFontType & RASTER_FONTTYPE) == 0; 932 aDFA.mbDevice = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0; 933 934 aDFA.mbEmbeddable = false; 935 aDFA.mbSubsettable = false; 936 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) 937 || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE)) 938 aDFA.mbSubsettable = true; 939 else if( 0 != (rMetric.ntmFlags & NTM_TYPE1) ) // TODO: implement subsetting for type1 too 940 aDFA.mbEmbeddable = true; 941 942 // heuristics for font quality 943 // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster 944 // - subsetting > embedding > none 945 aDFA.mnQuality = 0; 946 if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE ) 947 aDFA.mnQuality += 50; 948 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) ) 949 aDFA.mnQuality += 10; 950 if( aDFA.mbSubsettable ) 951 aDFA.mnQuality += 200; 952 else if( aDFA.mbEmbeddable ) 953 aDFA.mnQuality += 100; 954 955 // #i38665# prefer Type1 versions of the standard postscript fonts 956 if( aDFA.mbEmbeddable ) 957 { 958 if( aDFA.maName.EqualsAscii( "AvantGarde" ) 959 || aDFA.maName.EqualsAscii( "Bookman" ) 960 || aDFA.maName.EqualsAscii( "Courier" ) 961 || aDFA.maName.EqualsAscii( "Helvetica" ) 962 || aDFA.maName.EqualsAscii( "NewCenturySchlbk" ) 963 || aDFA.maName.EqualsAscii( "Palatino" ) 964 || aDFA.maName.EqualsAscii( "Symbol" ) 965 || aDFA.maName.EqualsAscii( "Times" ) 966 || aDFA.maName.EqualsAscii( "ZapfChancery" ) 967 || aDFA.maName.EqualsAscii( "ZapfDingbats" ) ) 968 aDFA.mnQuality += 500; 969 } 970 971 // TODO: add alias names 972 return aDFA; 973 } 974 975 // ----------------------------------------------------------------------- 976 977 static ImplWinFontData* ImplLogMetricToDevFontDataA( const ENUMLOGFONTEXA* pLogFont, 978 const NEWTEXTMETRICA* pMetric, 979 DWORD nFontType ) 980 { 981 int nHeight = 0; 982 if ( nFontType & RASTER_FONTTYPE ) 983 nHeight = pMetric->tmHeight - pMetric->tmInternalLeading; 984 985 ImplWinFontData* pData = new ImplWinFontData( 986 WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType), 987 nHeight, 988 pLogFont->elfLogFont.lfCharSet, 989 pMetric->tmPitchAndFamily ); 990 991 return pData; 992 } 993 994 // ----------------------------------------------------------------------- 995 996 static ImplWinFontData* ImplLogMetricToDevFontDataW( const ENUMLOGFONTEXW* pLogFont, 997 const NEWTEXTMETRICW* pMetric, 998 DWORD nFontType ) 999 { 1000 int nHeight = 0; 1001 if ( nFontType & RASTER_FONTTYPE ) 1002 nHeight = pMetric->tmHeight - pMetric->tmInternalLeading; 1003 1004 ImplWinFontData* pData = new ImplWinFontData( 1005 WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType), 1006 nHeight, 1007 pLogFont->elfLogFont.lfCharSet, 1008 pMetric->tmPitchAndFamily ); 1009 1010 return pData; 1011 } 1012 1013 // ----------------------------------------------------------------------- 1014 1015 void ImplSalLogFontToFontA( HDC hDC, const LOGFONTA& rLogFont, Font& rFont ) 1016 { 1017 String aFontName( ImplSalGetUniString( rLogFont.lfFaceName ) ); 1018 if ( aFontName.Len() ) 1019 { 1020 rFont.SetName( aFontName ); 1021 rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) ); 1022 rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) ); 1023 rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) ); 1024 rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) ); 1025 1026 long nFontHeight = rLogFont.lfHeight; 1027 if ( nFontHeight < 0 ) 1028 nFontHeight = -nFontHeight; 1029 long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY ); 1030 if( !nDPIY ) 1031 nDPIY = 600; 1032 nFontHeight *= 72; 1033 nFontHeight += nDPIY/2; 1034 nFontHeight /= nDPIY; 1035 rFont.SetSize( Size( 0, nFontHeight ) ); 1036 rFont.SetOrientation( (short)rLogFont.lfEscapement ); 1037 if ( rLogFont.lfItalic ) 1038 rFont.SetItalic( ITALIC_NORMAL ); 1039 else 1040 rFont.SetItalic( ITALIC_NONE ); 1041 if ( rLogFont.lfUnderline ) 1042 rFont.SetUnderline( UNDERLINE_SINGLE ); 1043 else 1044 rFont.SetUnderline( UNDERLINE_NONE ); 1045 if ( rLogFont.lfStrikeOut ) 1046 rFont.SetStrikeout( STRIKEOUT_SINGLE ); 1047 else 1048 rFont.SetStrikeout( STRIKEOUT_NONE ); 1049 } 1050 } 1051 1052 // ----------------------------------------------------------------------- 1053 1054 void ImplSalLogFontToFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont ) 1055 { 1056 XubString aFontName( reinterpret_cast<const xub_Unicode*>(rLogFont.lfFaceName) ); 1057 if ( aFontName.Len() ) 1058 { 1059 rFont.SetName( aFontName ); 1060 rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) ); 1061 rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) ); 1062 rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) ); 1063 rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) ); 1064 1065 long nFontHeight = rLogFont.lfHeight; 1066 if ( nFontHeight < 0 ) 1067 nFontHeight = -nFontHeight; 1068 long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY ); 1069 if( !nDPIY ) 1070 nDPIY = 600; 1071 nFontHeight *= 72; 1072 nFontHeight += nDPIY/2; 1073 nFontHeight /= nDPIY; 1074 rFont.SetSize( Size( 0, nFontHeight ) ); 1075 rFont.SetOrientation( (short)rLogFont.lfEscapement ); 1076 if ( rLogFont.lfItalic ) 1077 rFont.SetItalic( ITALIC_NORMAL ); 1078 else 1079 rFont.SetItalic( ITALIC_NONE ); 1080 if ( rLogFont.lfUnderline ) 1081 rFont.SetUnderline( UNDERLINE_SINGLE ); 1082 else 1083 rFont.SetUnderline( UNDERLINE_NONE ); 1084 if ( rLogFont.lfStrikeOut ) 1085 rFont.SetStrikeout( STRIKEOUT_SINGLE ); 1086 else 1087 rFont.SetStrikeout( STRIKEOUT_NONE ); 1088 } 1089 } 1090 1091 // ======================================================================= 1092 1093 ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes& rDFS, 1094 int nHeight, BYTE eWinCharSet, BYTE nPitchAndFamily ) 1095 : ImplFontData( rDFS, 0 ), 1096 meWinCharSet( eWinCharSet ), 1097 mnPitchAndFamily( nPitchAndFamily ), 1098 mpFontCharSets( NULL ), 1099 mpUnicodeMap( NULL ), 1100 mbGsubRead( false ), 1101 mbDisableGlyphApi( false ), 1102 mbHasKoreanRange( false ), 1103 mbHasCJKSupport( false ), 1104 #ifdef ENABLE_GRAPHITE 1105 mbHasGraphiteSupport( false ), 1106 #endif 1107 mbHasArabicSupport ( false ), 1108 mbAliasSymbolsLow( false ), 1109 mbAliasSymbolsHigh( false ), 1110 mnId( 0 ), 1111 mpEncodingVector( NULL ) 1112 { 1113 SetBitmapSize( 0, nHeight ); 1114 1115 if( eWinCharSet == SYMBOL_CHARSET ) 1116 { 1117 if( (nPitchAndFamily & TMPF_TRUETYPE) != 0 ) 1118 { 1119 // truetype fonts need their symbols as U+F0xx 1120 mbAliasSymbolsHigh = true; 1121 } 1122 else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_DEVICE)) 1123 == (TMPF_VECTOR|TMPF_DEVICE) ) 1124 { 1125 // scalable device fonts (e.g. builtin printer fonts) 1126 // need their symbols as U+00xx 1127 mbAliasSymbolsLow = true; 1128 } 1129 else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) == 0 ) 1130 { 1131 // bitmap fonts need their symbols as U+F0xx 1132 mbAliasSymbolsHigh = true; 1133 } 1134 } 1135 } 1136 1137 // ----------------------------------------------------------------------- 1138 1139 ImplWinFontData::~ImplWinFontData() 1140 { 1141 delete[] mpFontCharSets; 1142 1143 if( mpUnicodeMap ) 1144 mpUnicodeMap->DeReference(); 1145 delete mpEncodingVector; 1146 } 1147 1148 // ----------------------------------------------------------------------- 1149 1150 sal_IntPtr ImplWinFontData::GetFontId() const 1151 { 1152 return mnId; 1153 } 1154 1155 // ----------------------------------------------------------------------- 1156 1157 void ImplWinFontData::UpdateFromHDC( HDC hDC ) const 1158 { 1159 // short circuit if already initialized 1160 if( mpUnicodeMap != NULL ) 1161 return; 1162 1163 ReadCmapTable( hDC ); 1164 ReadOs2Table( hDC ); 1165 #ifdef ENABLE_GRAPHITE 1166 static const char* pDisableGraphiteText = getenv( "SAL_DISABLE_GRAPHITE" ); 1167 if( !pDisableGraphiteText || (pDisableGraphiteText[0] == '0') ) 1168 { 1169 mbHasGraphiteSupport = gr::WinFont::FontHasGraphiteTables(hDC); 1170 } 1171 #endif 1172 1173 // even if the font works some fonts have problems with the glyph API 1174 // => the heuristic below tries to figure out which fonts have the problem 1175 TEXTMETRICA aTextMetric; 1176 if( ::GetTextMetricsA( hDC, &aTextMetric ) ) 1177 if( !(aTextMetric.tmPitchAndFamily & TMPF_TRUETYPE) 1178 || (aTextMetric.tmPitchAndFamily & TMPF_DEVICE) ) 1179 mbDisableGlyphApi = true; 1180 1181 #if 0 1182 // #110548# more important than #107885# => TODO: better solution 1183 DWORD nFLI = GetFontLanguageInfo( hDC ); 1184 if( 0 == (nFLI & GCP_GLYPHSHAPE) ) 1185 mbDisableGlyphApi = true; 1186 #endif 1187 } 1188 1189 // ----------------------------------------------------------------------- 1190 1191 bool ImplWinFontData::HasGSUBstitutions( HDC hDC ) const 1192 { 1193 if( !mbGsubRead ) 1194 ReadGsubTable( hDC ); 1195 return !maGsubTable.empty(); 1196 } 1197 1198 // ----------------------------------------------------------------------- 1199 1200 bool ImplWinFontData::IsGSUBstituted( sal_UCS4 cChar ) const 1201 { 1202 return( maGsubTable.find( cChar ) != maGsubTable.end() ); 1203 } 1204 1205 // ----------------------------------------------------------------------- 1206 1207 const ImplFontCharMap* ImplWinFontData::GetImplFontCharMap() const 1208 { 1209 if( !mpUnicodeMap ) 1210 return NULL; 1211 return mpUnicodeMap; 1212 } 1213 1214 // ----------------------------------------------------------------------- 1215 1216 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);} 1217 static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);} 1218 //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));} 1219 static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); } 1220 1221 void ImplWinFontData::ReadOs2Table( HDC hDC ) const 1222 { 1223 const DWORD Os2Tag = CalcTag( "OS/2" ); 1224 DWORD nLength = ::GetFontData( hDC, Os2Tag, 0, NULL, 0 ); 1225 if( (nLength == GDI_ERROR) || !nLength ) 1226 return; 1227 std::vector<unsigned char> aOS2map( nLength ); 1228 unsigned char* pOS2map = &aOS2map[0]; 1229 ::GetFontData( hDC, Os2Tag, 0, pOS2map, nLength ); 1230 sal_uInt32 nVersion = GetUShort( pOS2map ); 1231 if ( nVersion >= 0x0001 && nLength >= 58 ) 1232 { 1233 // We need at least version 0x0001 (TrueType rev 1.66) 1234 // to have access to the needed struct members. 1235 sal_uInt32 ulUnicodeRange1 = GetUInt( pOS2map + 42 ); 1236 sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 ); 1237 #if 0 1238 sal_uInt32 ulUnicodeRange3 = GetUInt( pOS2map + 50 ); 1239 sal_uInt32 ulUnicodeRange4 = GetUInt( pOS2map + 54 ); 1240 #endif 1241 1242 // Check for CJK capabilities of the current font 1243 mbHasCJKSupport = (ulUnicodeRange2 & 0x2DF00000); 1244 mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000) 1245 | (ulUnicodeRange2 & 0x01100000); 1246 mbHasArabicSupport = (ulUnicodeRange1 & 0x00002000); 1247 } 1248 } 1249 1250 // ----------------------------------------------------------------------- 1251 1252 void ImplWinFontData::ReadGsubTable( HDC hDC ) const 1253 { 1254 mbGsubRead = true; 1255 1256 // check the existence of a GSUB table 1257 const DWORD GsubTag = CalcTag( "GSUB" ); 1258 DWORD nRC = ::GetFontData( hDC, GsubTag, 0, NULL, 0 ); 1259 if( (nRC == GDI_ERROR) || !nRC ) 1260 return; 1261 1262 // parse the GSUB table through sft 1263 // TODO: parse it directly 1264 1265 // sft needs the full font file data => get it 1266 const RawFontData aRawFontData( hDC ); 1267 if( !aRawFontData.get() ) 1268 return; 1269 1270 // open font file 1271 sal_uInt32 nFaceNum = 0; 1272 if( !*aRawFontData.get() ) // TTC candidate 1273 nFaceNum = ~0U; // indicate "TTC font extracts only" 1274 1275 TrueTypeFont* pTTFont = NULL; 1276 ::OpenTTFontBuffer( (void*)aRawFontData.get(), aRawFontData.size(), nFaceNum, &pTTFont ); 1277 if( !pTTFont ) 1278 return; 1279 1280 // add vertically substituted characters to list 1281 static const sal_Unicode aGSUBCandidates[] = { 1282 0x0020, 0x0080, // ASCII 1283 0x2000, 0x2600, // misc 1284 0x3000, 0x3100, // CJK punctutation 1285 0x3300, 0x3400, // squared words 1286 0xFF00, 0xFFF0, // halfwidth|fullwidth forms 1287 0 }; 1288 1289 for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 ) 1290 for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar ) 1291 if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) ) 1292 maGsubTable.insert( cChar ); // insert GSUBbed unicodes 1293 1294 CloseTTFont( pTTFont ); 1295 } 1296 1297 // ----------------------------------------------------------------------- 1298 1299 void ImplWinFontData::ReadCmapTable( HDC hDC ) const 1300 { 1301 if( mpUnicodeMap != NULL ) 1302 return; 1303 1304 bool bIsSymbolFont = (meWinCharSet == SYMBOL_CHARSET); 1305 // get the CMAP table from the font which is selected into the DC 1306 const DWORD nCmapTag = CalcTag( "cmap" ); 1307 const RawFontData aRawFontData( hDC, nCmapTag ); 1308 // parse the CMAP table if available 1309 if( aRawFontData.get() ) { 1310 CmapResult aResult; 1311 ParseCMAP( aRawFontData.get(), aRawFontData.size(), aResult ); 1312 mbDisableGlyphApi |= aResult.mbRecoded; 1313 aResult.mbSymbolic = bIsSymbolFont; 1314 if( aResult.mnRangeCount > 0 ) 1315 mpUnicodeMap = new ImplFontCharMap( aResult ); 1316 } 1317 1318 if( !mpUnicodeMap ) 1319 mpUnicodeMap = ImplFontCharMap::GetDefaultMap( bIsSymbolFont ); 1320 mpUnicodeMap->AddReference(); 1321 } 1322 1323 // ======================================================================= 1324 1325 void WinSalGraphics::SetTextColor( SalColor nSalColor ) 1326 { 1327 COLORREF aCol = PALETTERGB( SALCOLOR_RED( nSalColor ), 1328 SALCOLOR_GREEN( nSalColor ), 1329 SALCOLOR_BLUE( nSalColor ) ); 1330 1331 if( !mbPrinter && 1332 GetSalData()->mhDitherPal && 1333 ImplIsSysColorEntry( nSalColor ) ) 1334 { 1335 aCol = PALRGB_TO_RGB( aCol ); 1336 } 1337 1338 ::SetTextColor( mhDC, aCol ); 1339 } 1340 1341 // ----------------------------------------------------------------------- 1342 1343 int CALLBACK SalEnumQueryFontProcExW( const ENUMLOGFONTEXW*, 1344 const NEWTEXTMETRICEXW*, 1345 DWORD, LPARAM lParam ) 1346 { 1347 *((bool*)(void*)lParam) = true; 1348 return 0; 1349 } 1350 1351 // ----------------------------------------------------------------------- 1352 1353 int CALLBACK SalEnumQueryFontProcExA( const ENUMLOGFONTEXA*, 1354 const NEWTEXTMETRICEXA*, 1355 DWORD, LPARAM lParam ) 1356 { 1357 *((bool*)(void*)lParam) = true; 1358 return 0; 1359 } 1360 1361 // ----------------------------------------------------------------------- 1362 1363 bool ImplIsFontAvailable( HDC hDC, const UniString& rName ) 1364 { 1365 // Test, if Font available 1366 LOGFONTW aLogFont; 1367 memset( &aLogFont, 0, sizeof( aLogFont ) ); 1368 aLogFont.lfCharSet = DEFAULT_CHARSET; 1369 1370 UINT nNameLen = rName.Len(); 1371 if ( nNameLen > (sizeof( aLogFont.lfFaceName )/sizeof( wchar_t ))-1 ) 1372 nNameLen = (sizeof( aLogFont.lfFaceName )/sizeof( wchar_t ))-1; 1373 memcpy( aLogFont.lfFaceName, rName.GetBuffer(), nNameLen*sizeof( wchar_t ) ); 1374 aLogFont.lfFaceName[nNameLen] = 0; 1375 1376 bool bAvailable = false; 1377 EnumFontFamiliesExW( hDC, &aLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW, 1378 (LPARAM)(void*)&bAvailable, 0 ); 1379 1380 return bAvailable; 1381 } 1382 1383 // ----------------------------------------------------------------------- 1384 1385 void ImplGetLogFontFromFontSelect( HDC hDC, 1386 const ImplFontSelectData* pFont, 1387 LOGFONTW& rLogFont, 1388 bool /*bTestVerticalAvail*/ ) 1389 { 1390 UniString aName; 1391 if ( pFont->mpFontData ) 1392 aName = pFont->mpFontData->maName; 1393 else 1394 aName = pFont->maName.GetToken( 0 ); 1395 1396 UINT nNameLen = aName.Len(); 1397 if ( nNameLen > (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1 ) 1398 nNameLen = (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1; 1399 memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen*sizeof( wchar_t ) ); 1400 rLogFont.lfFaceName[nNameLen] = 0; 1401 1402 if( !pFont->mpFontData ) 1403 { 1404 rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET; 1405 rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->mePitch ) 1406 | ImplFamilyToWin( pFont->meFamily ); 1407 } 1408 else 1409 { 1410 const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData ); 1411 rLogFont.lfCharSet = pWinFontData->GetCharSet(); 1412 rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily(); 1413 } 1414 1415 rLogFont.lfWeight = ImplWeightToWin( pFont->meWeight ); 1416 rLogFont.lfHeight = (LONG)-pFont->mnHeight; 1417 rLogFont.lfWidth = (LONG)pFont->mnWidth; 1418 rLogFont.lfUnderline = 0; 1419 rLogFont.lfStrikeOut = 0; 1420 rLogFont.lfItalic = (pFont->meItalic) != ITALIC_NONE; 1421 rLogFont.lfEscapement = pFont->mnOrientation; 1422 rLogFont.lfOrientation = rLogFont.lfEscapement; 1423 rLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; 1424 rLogFont.lfQuality = DEFAULT_QUALITY; 1425 rLogFont.lfOutPrecision = OUT_TT_PRECIS; 1426 if ( pFont->mnOrientation ) 1427 rLogFont.lfClipPrecision |= CLIP_LH_ANGLES; 1428 1429 // disable antialiasing if requested 1430 if ( pFont->mbNonAntialiased ) 1431 rLogFont.lfQuality = NONANTIALIASED_QUALITY; 1432 1433 // select vertical mode if requested and available 1434 if( pFont->mbVertical && nNameLen ) 1435 { 1436 // vertical fonts start with an '@' 1437 memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0], 1438 sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) ); 1439 rLogFont.lfFaceName[0] = '@'; 1440 1441 // check availability of vertical mode for this font 1442 bool bAvailable = false; 1443 EnumFontFamiliesExW( hDC, &rLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW, 1444 (LPARAM)&bAvailable, 0 ); 1445 1446 if( !bAvailable ) 1447 { 1448 // restore non-vertical name if not vertical mode isn't available 1449 memcpy( &rLogFont.lfFaceName[0], aName.GetBuffer(), nNameLen*sizeof(wchar_t) ); 1450 if( nNameLen < LF_FACESIZE ) 1451 rLogFont.lfFaceName[nNameLen] = '\0'; 1452 } 1453 } 1454 } 1455 1456 // ----------------------------------------------------------------------- 1457 1458 static void ImplGetLogFontFromFontSelect( HDC hDC, 1459 const ImplFontSelectData* pFont, 1460 LOGFONTA& rLogFont, 1461 bool /*bTestVerticalAvail*/ ) 1462 { 1463 ByteString aName; 1464 if( pFont->mpFontData ) 1465 aName = ImplSalGetWinAnsiString( pFont->mpFontData->maName ); 1466 else 1467 aName = ImplSalGetWinAnsiString( pFont->maName.GetToken( 0 ) ); 1468 1469 int nNameLen = aName.Len(); 1470 if( nNameLen > LF_FACESIZE ) 1471 nNameLen = LF_FACESIZE; 1472 memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen ); 1473 if( nNameLen < LF_FACESIZE ) 1474 rLogFont.lfFaceName[nNameLen] = '\0'; 1475 1476 if( !pFont->mpFontData ) 1477 { 1478 rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET; 1479 rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->mePitch ) 1480 | ImplFamilyToWin( pFont->meFamily ); 1481 } 1482 else 1483 { 1484 const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData ); 1485 rLogFont.lfCharSet = pWinFontData->GetCharSet(); 1486 rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily(); 1487 } 1488 1489 rLogFont.lfWeight = ImplWeightToWin( pFont->meWeight ); 1490 rLogFont.lfHeight = (LONG)-pFont->mnHeight; 1491 rLogFont.lfWidth = (LONG)pFont->mnWidth; 1492 rLogFont.lfUnderline = 0; 1493 rLogFont.lfStrikeOut = 0; 1494 rLogFont.lfItalic = (pFont->meItalic) != ITALIC_NONE; 1495 rLogFont.lfEscapement = pFont->mnOrientation; 1496 rLogFont.lfOrientation = rLogFont.lfEscapement; // ignored by W98 1497 rLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; 1498 rLogFont.lfQuality = DEFAULT_QUALITY; 1499 rLogFont.lfOutPrecision = OUT_TT_PRECIS; 1500 if( pFont->mnOrientation ) 1501 rLogFont.lfClipPrecision |= CLIP_LH_ANGLES; 1502 1503 // disable antialiasing if requested 1504 if( pFont->mbNonAntialiased ) 1505 rLogFont.lfQuality = NONANTIALIASED_QUALITY; 1506 1507 // select vertical mode if requested and available 1508 if( pFont->mbVertical && nNameLen ) 1509 { 1510 // vertical fonts start with an '@' 1511 memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0], 1512 sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) ); 1513 rLogFont.lfFaceName[0] = '@'; 1514 1515 // check availability of vertical mode for this font 1516 bool bAvailable = false; 1517 EnumFontFamiliesExA( hDC, &rLogFont, (FONTENUMPROCA)SalEnumQueryFontProcExA, 1518 (LPARAM)&bAvailable, 0 ); 1519 1520 if( !bAvailable ) 1521 { 1522 // restore non-vertical name if vertical mode is not supported 1523 memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen ); 1524 if( nNameLen < LF_FACESIZE ) 1525 rLogFont.lfFaceName[nNameLen] = '\0'; 1526 } 1527 } 1528 } 1529 1530 // ----------------------------------------------------------------------- 1531 1532 HFONT WinSalGraphics::ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, HFONT& o_rOldFont ) 1533 { 1534 HFONT hNewFont = 0; 1535 1536 HDC hdcScreen = 0; 1537 if( mbVirDev ) 1538 // only required for virtual devices, see below for details 1539 hdcScreen = GetDC(0); 1540 1541 if( true/*aSalShlData.mbWNT*/ ) 1542 { 1543 LOGFONTW aLogFont; 1544 ImplGetLogFontFromFontSelect( mhDC, i_pFont, aLogFont, true ); 1545 1546 // on the display we prefer Courier New when Courier is a 1547 // bitmap only font and we need to stretch or rotate it 1548 if( mbScreen 1549 && (i_pFont->mnWidth != 0 1550 || i_pFont->mnOrientation != 0 1551 || i_pFont->mpFontData == NULL 1552 || (i_pFont->mpFontData->GetHeight() != i_pFont->mnHeight)) 1553 && !bImplSalCourierScalable 1554 && bImplSalCourierNew 1555 && (ImplSalWICompareAscii( aLogFont.lfFaceName, "Courier" ) == 0) ) 1556 lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 ); 1557 1558 // #i47675# limit font requests to MAXFONTHEIGHT 1559 // TODO: share MAXFONTHEIGHT font instance 1560 if( (-aLogFont.lfHeight <= MAXFONTHEIGHT) 1561 && (+aLogFont.lfWidth <= MAXFONTHEIGHT) ) 1562 { 1563 o_rFontScale = 1.0; 1564 } 1565 else if( -aLogFont.lfHeight >= +aLogFont.lfWidth ) 1566 { 1567 o_rFontScale = -aLogFont.lfHeight / (float)MAXFONTHEIGHT; 1568 aLogFont.lfHeight = -MAXFONTHEIGHT; 1569 aLogFont.lfWidth = FRound( aLogFont.lfWidth / o_rFontScale ); 1570 } 1571 else // #i95867# also limit font widths 1572 { 1573 o_rFontScale = +aLogFont.lfWidth / (float)MAXFONTHEIGHT; 1574 aLogFont.lfWidth = +MAXFONTHEIGHT; 1575 aLogFont.lfHeight = FRound( aLogFont.lfHeight / o_rFontScale ); 1576 } 1577 1578 hNewFont = ::CreateFontIndirectW( &aLogFont ); 1579 if( hdcScreen ) 1580 { 1581 // select font into screen hdc first to get an antialiased font 1582 // see knowledge base article 305290: 1583 // "PRB: Fonts Not Drawn Antialiased on Device Context for DirectDraw Surface" 1584 SelectFont( hdcScreen, SelectFont( hdcScreen , hNewFont ) ); 1585 } 1586 o_rOldFont = ::SelectFont( mhDC, hNewFont ); 1587 1588 TEXTMETRICW aTextMetricW; 1589 if( !::GetTextMetricsW( mhDC, &aTextMetricW ) ) 1590 { 1591 // the selected font doesn't work => try a replacement 1592 // TODO: use its font fallback instead 1593 lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 ); 1594 aLogFont.lfPitchAndFamily = FIXED_PITCH; 1595 HFONT hNewFont2 = CreateFontIndirectW( &aLogFont ); 1596 SelectFont( mhDC, hNewFont2 ); 1597 DeleteFont( hNewFont ); 1598 hNewFont = hNewFont2; 1599 } 1600 } 1601 1602 if( hdcScreen ) 1603 ::ReleaseDC( NULL, hdcScreen ); 1604 1605 return hNewFont; 1606 } 1607 1608 sal_uInt16 WinSalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel ) 1609 { 1610 // return early if there is no new font 1611 if( !pFont ) 1612 { 1613 // deselect still active font 1614 if( mhDefFont ) 1615 ::SelectFont( mhDC, mhDefFont ); 1616 // release no longer referenced font handles 1617 for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i ) 1618 { 1619 if( mhFonts[i] ) 1620 ::DeleteFont( mhFonts[i] ); 1621 mhFonts[ i ] = 0; 1622 } 1623 mhDefFont = 0; 1624 return 0; 1625 } 1626 1627 DBG_ASSERT( pFont->mpFontData, "WinSalGraphics mpFontData==NULL"); 1628 mpWinFontEntry[ nFallbackLevel ] = reinterpret_cast<ImplWinFontEntry*>( pFont->mpFontEntry ); 1629 mpWinFontData[ nFallbackLevel ] = static_cast<const ImplWinFontData*>( pFont->mpFontData ); 1630 1631 HFONT hOldFont = 0; 1632 HFONT hNewFont = ImplDoSetFont( pFont, mfFontScale, hOldFont ); 1633 1634 if( !mhDefFont ) 1635 { 1636 // keep default font 1637 mhDefFont = hOldFont; 1638 } 1639 else 1640 { 1641 // release no longer referenced font handles 1642 for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i ) 1643 { 1644 if( mhFonts[i] ) 1645 { 1646 ::DeleteFont( mhFonts[i] ); 1647 mhFonts[i] = 0; 1648 } 1649 } 1650 } 1651 1652 // store new font in correct layer 1653 mhFonts[ nFallbackLevel ] = hNewFont; 1654 // now the font is live => update font face 1655 if( mpWinFontData[ nFallbackLevel ] ) 1656 mpWinFontData[ nFallbackLevel ]->UpdateFromHDC( mhDC ); 1657 1658 if( !nFallbackLevel ) 1659 { 1660 mbFontKernInit = TRUE; 1661 if ( mpFontKernPairs ) 1662 { 1663 delete[] mpFontKernPairs; 1664 mpFontKernPairs = NULL; 1665 } 1666 mnFontKernPairCount = 0; 1667 } 1668 1669 mnFontCharSetCount = 0; 1670 1671 // some printers have higher internal resolution, so their 1672 // text output would be different from what we calculated 1673 // => suggest DrawTextArray to workaround this problem 1674 if ( mbPrinter ) 1675 return SAL_SETFONT_USEDRAWTEXTARRAY; 1676 else 1677 return 0; 1678 } 1679 1680 // ----------------------------------------------------------------------- 1681 1682 void WinSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel ) 1683 { 1684 // temporarily change the HDC to the font in the fallback level 1685 HFONT hOldFont = SelectFont( mhDC, mhFonts[nFallbackLevel] ); 1686 1687 wchar_t aFaceName[LF_FACESIZE+60]; 1688 if( ::GetTextFaceW( mhDC, sizeof(aFaceName)/sizeof(wchar_t), aFaceName ) ) 1689 pMetric->maName = reinterpret_cast<const sal_Unicode*>(aFaceName); 1690 1691 // get the font metric 1692 TEXTMETRICA aWinMetric; 1693 const bool bOK = GetTextMetricsA( mhDC, &aWinMetric ); 1694 // restore the HDC to the font in the base level 1695 SelectFont( mhDC, hOldFont ); 1696 if( !bOK ) 1697 return; 1698 1699 // device independent font attributes 1700 pMetric->meFamily = ImplFamilyToSal( aWinMetric.tmPitchAndFamily );; 1701 pMetric->mbSymbolFlag = (aWinMetric.tmCharSet == SYMBOL_CHARSET); 1702 pMetric->meWeight = ImplWeightToSal( aWinMetric.tmWeight ); 1703 pMetric->mePitch = ImplMetricPitchToSal( aWinMetric.tmPitchAndFamily ); 1704 pMetric->meItalic = aWinMetric.tmItalic ? ITALIC_NORMAL : ITALIC_NONE; 1705 pMetric->mnSlant = 0; 1706 1707 // device dependend font attributes 1708 pMetric->mbDevice = (aWinMetric.tmPitchAndFamily & TMPF_DEVICE) != 0; 1709 pMetric->mbScalableFont = (aWinMetric.tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) != 0; 1710 if( pMetric->mbScalableFont ) 1711 { 1712 // check if there are kern pairs 1713 // TODO: does this work with GPOS kerning? 1714 DWORD nKernPairs = ::GetKerningPairsA( mhDC, 0, NULL ); 1715 pMetric->mbKernableFont = (nKernPairs > 0); 1716 } 1717 else 1718 { 1719 // bitmap fonts cannot be rotated directly 1720 pMetric->mnOrientation = 0; 1721 // bitmap fonts have no kerning 1722 pMetric->mbKernableFont = false; 1723 } 1724 1725 // transformation dependend font metrics 1726 pMetric->mnWidth = static_cast<int>( mfFontScale * aWinMetric.tmAveCharWidth ); 1727 pMetric->mnIntLeading = static_cast<int>( mfFontScale * aWinMetric.tmInternalLeading ); 1728 pMetric->mnExtLeading = static_cast<int>( mfFontScale * aWinMetric.tmExternalLeading ); 1729 pMetric->mnAscent = static_cast<int>( mfFontScale * aWinMetric.tmAscent ); 1730 pMetric->mnDescent = static_cast<int>( mfFontScale * aWinMetric.tmDescent ); 1731 1732 // #107888# improved metric compatibility for Asian fonts... 1733 // TODO: assess workaround below for CWS >= extleading 1734 // TODO: evaluate use of aWinMetric.sTypo* members for CJK 1735 if( mpWinFontData[nFallbackLevel] && mpWinFontData[nFallbackLevel]->SupportsCJK() ) 1736 { 1737 pMetric->mnIntLeading += pMetric->mnExtLeading; 1738 1739 // #109280# The line height for Asian fonts is too small. 1740 // Therefore we add half of the external leading to the 1741 // ascent, the other half is added to the descent. 1742 const long nHalfTmpExtLeading = pMetric->mnExtLeading / 2; 1743 const long nOtherHalfTmpExtLeading = pMetric->mnExtLeading - nHalfTmpExtLeading; 1744 1745 // #110641# external leading for Asian fonts. 1746 // The factor 0.3 has been confirmed with experiments. 1747 long nCJKExtLeading = static_cast<long>(0.30 * (pMetric->mnAscent + pMetric->mnDescent)); 1748 nCJKExtLeading -= pMetric->mnExtLeading; 1749 pMetric->mnExtLeading = (nCJKExtLeading > 0) ? nCJKExtLeading : 0; 1750 1751 pMetric->mnAscent += nHalfTmpExtLeading; 1752 pMetric->mnDescent += nOtherHalfTmpExtLeading; 1753 } 1754 1755 pMetric->mnMinKashida = GetMinKashidaWidth(); 1756 } 1757 1758 // ----------------------------------------------------------------------- 1759 1760 int CALLBACK SalEnumCharSetsProcExA( const ENUMLOGFONTEXA* pLogFont, 1761 const NEWTEXTMETRICEXA* /*pMetric*/, 1762 DWORD /*nFontType*/, LPARAM lParam ) 1763 { 1764 WinSalGraphics* pData = (WinSalGraphics*)lParam; 1765 // Charset already in the list? 1766 for ( BYTE i = 0; i < pData->mnFontCharSetCount; i++ ) 1767 { 1768 if ( pData->mpFontCharSets[i] == pLogFont->elfLogFont.lfCharSet ) 1769 return 1; 1770 } 1771 pData->mpFontCharSets[pData->mnFontCharSetCount] = pLogFont->elfLogFont.lfCharSet; 1772 pData->mnFontCharSetCount++; 1773 return 1; 1774 } 1775 1776 // ----------------------------------------------------------------------- 1777 1778 static void ImplGetAllFontCharSets( WinSalGraphics* pData ) 1779 { 1780 if ( !pData->mpFontCharSets ) 1781 pData->mpFontCharSets = new BYTE[256]; 1782 1783 LOGFONTA aLogFont; 1784 memset( &aLogFont, 0, sizeof( aLogFont ) ); 1785 aLogFont.lfCharSet = DEFAULT_CHARSET; 1786 GetTextFaceA( pData->mhDC, sizeof( aLogFont.lfFaceName ), aLogFont.lfFaceName ); 1787 EnumFontFamiliesExA( pData->mhDC, &aLogFont, (FONTENUMPROCA)SalEnumCharSetsProcExA, 1788 (LPARAM)(void*)pData, 0 ); 1789 } 1790 1791 // ----------------------------------------------------------------------- 1792 1793 static void ImplAddKerningPairs( WinSalGraphics* pData ) 1794 { 1795 sal_uLong nPairs = ::GetKerningPairsA( pData->mhDC, 0, NULL ); 1796 if ( !nPairs ) 1797 return; 1798 1799 CHARSETINFO aInfo; 1800 if ( !TranslateCharsetInfo( (DWORD*)(sal_uLong)GetTextCharset( pData->mhDC ), &aInfo, TCI_SRCCHARSET ) ) 1801 return; 1802 1803 if ( !pData->mpFontKernPairs ) 1804 pData->mpFontKernPairs = new KERNINGPAIR[nPairs]; 1805 else 1806 { 1807 KERNINGPAIR* pOldPairs = pData->mpFontKernPairs; 1808 pData->mpFontKernPairs = new KERNINGPAIR[nPairs+pData->mnFontKernPairCount]; 1809 memcpy( pData->mpFontKernPairs, pOldPairs, 1810 pData->mnFontKernPairCount*sizeof( KERNINGPAIR ) ); 1811 delete[] pOldPairs; 1812 } 1813 1814 UINT nCP = aInfo.ciACP; 1815 sal_uLong nOldPairs = pData->mnFontKernPairCount; 1816 KERNINGPAIR* pTempPair = pData->mpFontKernPairs+pData->mnFontKernPairCount; 1817 nPairs = ::GetKerningPairsA( pData->mhDC, nPairs, pTempPair ); 1818 for ( sal_uLong i = 0; i < nPairs; i++ ) 1819 { 1820 unsigned char aBuf[2]; 1821 wchar_t nChar; 1822 int nLen; 1823 sal_Bool bAdd = TRUE; 1824 1825 // None-ASCII?, then we must convert the char 1826 if ( (pTempPair->wFirst > 125) || (pTempPair->wFirst == 92) ) 1827 { 1828 if ( pTempPair->wFirst < 256 ) 1829 { 1830 aBuf[0] = (unsigned char)pTempPair->wFirst; 1831 nLen = 1; 1832 } 1833 else 1834 { 1835 aBuf[0] = (unsigned char)(pTempPair->wFirst >> 8); 1836 aBuf[1] = (unsigned char)(pTempPair->wFirst & 0xFF); 1837 nLen = 2; 1838 } 1839 if ( MultiByteToWideChar( nCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS, 1840 (const char*)aBuf, nLen, &nChar, 1 ) ) 1841 pTempPair->wFirst = nChar; 1842 else 1843 bAdd = FALSE; 1844 } 1845 if ( (pTempPair->wSecond > 125) || (pTempPair->wSecond == 92) ) 1846 { 1847 if ( pTempPair->wSecond < 256 ) 1848 { 1849 aBuf[0] = (unsigned char)pTempPair->wSecond; 1850 nLen = 1; 1851 } 1852 else 1853 { 1854 aBuf[0] = (unsigned char)(pTempPair->wSecond >> 8); 1855 aBuf[1] = (unsigned char)(pTempPair->wSecond & 0xFF); 1856 nLen = 2; 1857 } 1858 if ( MultiByteToWideChar( nCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS, 1859 (const char*)aBuf, nLen, &nChar, 1 ) ) 1860 pTempPair->wSecond = nChar; 1861 else 1862 bAdd = FALSE; 1863 } 1864 1865 // TODO: get rid of linear search! 1866 KERNINGPAIR* pTempPair2 = pData->mpFontKernPairs; 1867 for ( sal_uLong j = 0; j < nOldPairs; j++ ) 1868 { 1869 if ( (pTempPair2->wFirst == pTempPair->wFirst) && 1870 (pTempPair2->wSecond == pTempPair->wSecond) ) 1871 { 1872 bAdd = FALSE; 1873 break; 1874 } 1875 pTempPair2++; 1876 } 1877 1878 if ( bAdd ) 1879 { 1880 KERNINGPAIR* pDestPair = pData->mpFontKernPairs+pData->mnFontKernPairCount; 1881 if ( pDestPair != pTempPair ) 1882 memcpy( pDestPair, pTempPair, sizeof( KERNINGPAIR ) ); 1883 pData->mnFontKernPairCount++; 1884 } 1885 1886 pTempPair++; 1887 } 1888 } 1889 1890 // ----------------------------------------------------------------------- 1891 1892 sal_uLong WinSalGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData* pKernPairs ) 1893 { 1894 DBG_ASSERT( sizeof( KERNINGPAIR ) == sizeof( ImplKernPairData ), 1895 "WinSalGraphics::GetKernPairs(): KERNINGPAIR != ImplKernPairData" ); 1896 1897 if ( mbFontKernInit ) 1898 { 1899 if( mpFontKernPairs ) 1900 { 1901 delete[] mpFontKernPairs; 1902 mpFontKernPairs = NULL; 1903 } 1904 mnFontKernPairCount = 0; 1905 1906 KERNINGPAIR* pPairs = NULL; 1907 int nCount = ::GetKerningPairsW( mhDC, 0, NULL ); 1908 if( nCount ) 1909 { 1910 #ifdef GCP_KERN_HACK 1911 pPairs = new KERNINGPAIR[ nCount+1 ]; 1912 mpFontKernPairs = pPairs; 1913 mnFontKernPairCount = nCount; 1914 ::GetKerningPairsW( mhDC, nCount, pPairs ); 1915 #else // GCP_KERN_HACK 1916 pPairs = pKernPairs; 1917 nCount = (nCount < nPairs) : nCount : nPairs; 1918 ::GetKerningPairsW( mhDC, nCount, pPairs ); 1919 return nCount; 1920 #endif // GCP_KERN_HACK 1921 } 1922 1923 mbFontKernInit = FALSE; 1924 1925 std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData ); 1926 } 1927 1928 if( !pKernPairs ) 1929 return mnFontKernPairCount; 1930 else if( mpFontKernPairs ) 1931 { 1932 if ( nPairs < mnFontKernPairCount ) 1933 nPairs = mnFontKernPairCount; 1934 memcpy( pKernPairs, mpFontKernPairs, 1935 nPairs*sizeof( ImplKernPairData ) ); 1936 return nPairs; 1937 } 1938 1939 return 0; 1940 } 1941 1942 // ----------------------------------------------------------------------- 1943 1944 const ImplFontCharMap* WinSalGraphics::GetImplFontCharMap() const 1945 { 1946 if( !mpWinFontData[0] ) 1947 return ImplFontCharMap::GetDefaultMap(); 1948 return mpWinFontData[0]->GetImplFontCharMap(); 1949 } 1950 1951 // ----------------------------------------------------------------------- 1952 1953 int CALLBACK SalEnumFontsProcExA( const ENUMLOGFONTEXA* pLogFont, 1954 const NEWTEXTMETRICEXA* pMetric, 1955 DWORD nFontType, LPARAM lParam ) 1956 { 1957 ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam; 1958 if ( !pInfo->mpName ) 1959 { 1960 // Ignore vertical fonts 1961 if ( pLogFont->elfLogFont.lfFaceName[0] != '@' ) 1962 { 1963 if ( !pInfo->mbImplSalCourierNew ) 1964 pInfo->mbImplSalCourierNew = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0; 1965 if ( !pInfo->mbImplSalCourierScalable ) 1966 pInfo->mbCourier = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0; 1967 else 1968 pInfo->mbCourier = FALSE; 1969 String aName( ImplSalGetUniString( pLogFont->elfLogFont.lfFaceName ) ); 1970 pInfo->mpName = &aName; 1971 strncpy( pInfo->mpLogFontA->lfFaceName, pLogFont->elfLogFont.lfFaceName, LF_FACESIZE ); 1972 pInfo->mpLogFontA->lfCharSet = pLogFont->elfLogFont.lfCharSet; 1973 EnumFontFamiliesExA( pInfo->mhDC, pInfo->mpLogFontA, (FONTENUMPROCA)SalEnumFontsProcExA, 1974 (LPARAM)(void*)pInfo, 0 ); 1975 pInfo->mpLogFontA->lfFaceName[0] = '\0'; 1976 pInfo->mpLogFontA->lfCharSet = DEFAULT_CHARSET; 1977 pInfo->mpName = NULL; 1978 pInfo->mbCourier = FALSE; 1979 } 1980 } 1981 else 1982 { 1983 // ignore non-scalable non-device font on printer 1984 if( pInfo->mbPrinter ) 1985 if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) ) 1986 return 1; 1987 1988 ImplWinFontData* pData = ImplLogMetricToDevFontDataA( pLogFont, &(pMetric->ntmTm), nFontType ); 1989 pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) ); 1990 1991 // prefer the system character set, so that we get as much as 1992 // possible important characters. In the other case we could only 1993 // display a limited set of characters (#87309#) 1994 if ( pInfo->mnPreferedCharSet == pLogFont->elfLogFont.lfCharSet ) 1995 pData->mnQuality += 100; 1996 1997 // knowing Courier to be scalable is nice 1998 if( pInfo->mbCourier ) 1999 pInfo->mbImplSalCourierScalable |= pData->IsScalable(); 2000 2001 pInfo->mpList->Add( pData ); 2002 } 2003 2004 return 1; 2005 } 2006 2007 // ----------------------------------------------------------------------- 2008 2009 int CALLBACK SalEnumFontsProcExW( const ENUMLOGFONTEXW* pLogFont, 2010 const NEWTEXTMETRICEXW* pMetric, 2011 DWORD nFontType, LPARAM lParam ) 2012 { 2013 ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam; 2014 if ( !pInfo->mpName ) 2015 { 2016 // Ignore vertical fonts 2017 if ( pLogFont->elfLogFont.lfFaceName[0] != '@' ) 2018 { 2019 if ( !pInfo->mbImplSalCourierNew ) 2020 pInfo->mbImplSalCourierNew = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0; 2021 if ( !pInfo->mbImplSalCourierScalable ) 2022 pInfo->mbCourier = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0; 2023 else 2024 pInfo->mbCourier = FALSE; 2025 String aName( reinterpret_cast<const sal_Unicode*>(pLogFont->elfLogFont.lfFaceName) ); 2026 pInfo->mpName = &aName; 2027 memcpy( pInfo->mpLogFontW->lfFaceName, pLogFont->elfLogFont.lfFaceName, (aName.Len()+1)*sizeof( wchar_t ) ); 2028 pInfo->mpLogFontW->lfCharSet = pLogFont->elfLogFont.lfCharSet; 2029 EnumFontFamiliesExW( pInfo->mhDC, pInfo->mpLogFontW, (FONTENUMPROCW)SalEnumFontsProcExW, 2030 (LPARAM)(void*)pInfo, 0 ); 2031 pInfo->mpLogFontW->lfFaceName[0] = '\0'; 2032 pInfo->mpLogFontW->lfCharSet = DEFAULT_CHARSET; 2033 pInfo->mpName = NULL; 2034 pInfo->mbCourier = FALSE; 2035 } 2036 } 2037 else 2038 { 2039 // ignore non-scalable non-device font on printer 2040 if( pInfo->mbPrinter ) 2041 if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) ) 2042 return 1; 2043 2044 ImplWinFontData* pData = ImplLogMetricToDevFontDataW( pLogFont, &(pMetric->ntmTm), nFontType ); 2045 pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) ); 2046 2047 // knowing Courier to be scalable is nice 2048 if( pInfo->mbCourier ) 2049 pInfo->mbImplSalCourierScalable |= pData->IsScalable(); 2050 2051 pInfo->mpList->Add( pData ); 2052 } 2053 2054 return 1; 2055 } 2056 2057 // ----------------------------------------------------------------------- 2058 2059 struct TempFontItem 2060 { 2061 ::rtl::OUString maFontFilePath; 2062 ::rtl::OString maResourcePath; 2063 TempFontItem* mpNextItem; 2064 }; 2065 2066 #ifdef FR_PRIVATE 2067 static int WINAPI __AddFontResourceExW( LPCWSTR lpszfileName, DWORD fl, PVOID pdv ) 2068 { 2069 typedef int (WINAPI *AddFontResourceExW_FUNC)(LPCWSTR, DWORD, PVOID ); 2070 2071 static AddFontResourceExW_FUNC pFunc = NULL; 2072 static HMODULE hmGDI = NULL; 2073 2074 if ( !pFunc && !hmGDI ) 2075 { 2076 hmGDI = GetModuleHandleA( "GDI32" ); 2077 if ( hmGDI ) 2078 pFunc = reinterpret_cast<AddFontResourceExW_FUNC>( GetProcAddress( hmGDI, "AddFontResourceExW" ) ); 2079 } 2080 2081 if ( pFunc ) 2082 return pFunc( lpszfileName, fl, pdv ); 2083 else 2084 { 2085 SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); 2086 return 0; 2087 } 2088 } 2089 #endif 2090 2091 bool ImplAddTempFont( SalData& rSalData, const String& rFontFileURL ) 2092 { 2093 int nRet = 0; 2094 ::rtl::OUString aUSytemPath; 2095 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) ); 2096 2097 #ifdef FR_PRIVATE 2098 nRet = __AddFontResourceExW( reinterpret_cast<LPCWSTR>(aUSytemPath.getStr()), FR_PRIVATE, NULL ); 2099 #endif 2100 2101 if ( !nRet ) 2102 { 2103 static int nCounter = 0; 2104 char aFileName[] = "soAA.fot"; 2105 aFileName[2] = sal::static_int_cast<char>('A' + (15 & (nCounter>>4))); 2106 aFileName[3] = sal::static_int_cast<char>('A' + (15 & nCounter)); 2107 char aResourceName[512]; 2108 int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16; 2109 int nLen = ::GetTempPathA( nMaxLen, aResourceName ); 2110 ::strncpy( aResourceName + nLen, aFileName, sizeof( aResourceName )- nLen ); 2111 // security: end buffer in any case 2112 aResourceName[ (sizeof(aResourceName)/sizeof(*aResourceName))-1 ] = 0; 2113 ::DeleteFileA( aResourceName ); 2114 2115 rtl_TextEncoding theEncoding = osl_getThreadTextEncoding(); 2116 ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding ); 2117 // TODO: font should be private => need to investigate why it doesn't work then 2118 if( !::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL ) ) 2119 return false; 2120 ++nCounter; 2121 2122 nRet = ::AddFontResourceA( aResourceName ); 2123 if( nRet > 0 ) 2124 { 2125 TempFontItem* pNewItem = new TempFontItem; 2126 pNewItem->maResourcePath = rtl::OString( aResourceName ); 2127 pNewItem->maFontFilePath = aUSytemPath.getStr(); 2128 pNewItem->mpNextItem = rSalData.mpTempFontItem; 2129 rSalData.mpTempFontItem = pNewItem; 2130 } 2131 } 2132 2133 return (nRet > 0); 2134 } 2135 2136 // ----------------------------------------------------------------------- 2137 2138 void ImplReleaseTempFonts( SalData& rSalData ) 2139 { 2140 int nCount = 0; 2141 while( TempFontItem* p = rSalData.mpTempFontItem ) 2142 { 2143 ++nCount; 2144 if( p->maResourcePath.getLength() ) 2145 { 2146 const char* pResourcePath = p->maResourcePath.getStr(); 2147 ::RemoveFontResourceA( pResourcePath ); 2148 ::DeleteFileA( pResourcePath ); 2149 } 2150 else 2151 { 2152 ::RemoveFontResourceW( reinterpret_cast<LPCWSTR>(p->maFontFilePath.getStr()) ); 2153 } 2154 2155 rSalData.mpTempFontItem = p->mpNextItem; 2156 delete p; 2157 } 2158 2159 #ifndef FR_PRIVATE 2160 // notify every other application 2161 // unless the temp fonts were installed as private fonts 2162 if( nCount > 0 ) 2163 ::PostMessage( HWND_BROADCAST, WM_FONTCHANGE, 0, NULL ); 2164 #endif // FR_PRIVATE 2165 } 2166 2167 // ----------------------------------------------------------------------- 2168 2169 static bool ImplGetFontAttrFromFile( const String& rFontFileURL, 2170 ImplDevFontAttributes& rDFA ) 2171 { 2172 ::rtl::OUString aUSytemPath; 2173 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) ); 2174 2175 // get FontAttributes from a *fot file 2176 // TODO: use GetTTGlobalFontInfo() to access the font directly 2177 rDFA.mnQuality = 1000; 2178 rDFA.mbDevice = true; 2179 rDFA.meFamily = FAMILY_DONTKNOW; 2180 rDFA.meWidthType = WIDTH_DONTKNOW; 2181 rDFA.meWeight = WEIGHT_DONTKNOW; 2182 rDFA.meItalic = ITALIC_DONTKNOW; 2183 rDFA.mePitch = PITCH_DONTKNOW;; 2184 rDFA.mbSubsettable= true; 2185 rDFA.mbEmbeddable = false; 2186 2187 // Create temporary file name 2188 char aFileName[] = "soAAT.fot"; 2189 char aResourceName[512]; 2190 int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16; 2191 int nLen = ::GetTempPathA( nMaxLen, aResourceName ); 2192 ::strncpy( aResourceName + nLen, aFileName, Max( 0, nMaxLen - nLen )); 2193 ::DeleteFileA( aResourceName ); 2194 2195 // Create font resource file (typically with a .fot file name extension). 2196 rtl_TextEncoding theEncoding = osl_getThreadTextEncoding(); 2197 ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding ); 2198 ::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL ); 2199 2200 // Open and read the font resource file 2201 rtl::OUString aFotFileName = rtl::OStringToOUString( aResourceName, osl_getThreadTextEncoding() ); 2202 osl::FileBase::getFileURLFromSystemPath( aFotFileName, aFotFileName ); 2203 osl::File aFotFile( aFotFileName ); 2204 osl::FileBase::RC aError = aFotFile.open( osl_File_OpenFlag_Read ); 2205 if( aError != osl::FileBase::E_None ) 2206 return false; 2207 2208 sal_uInt64 nBytesRead = 0; 2209 char aBuffer[4096]; 2210 aFotFile.read( aBuffer, sizeof( aBuffer ), nBytesRead ); 2211 // clean up temporary resource file 2212 aFotFile.close(); 2213 ::DeleteFileA( aResourceName ); 2214 2215 // retrieve font family name from byte offset 0x4F6 2216 int i = 0x4F6; 2217 int nNameOfs = i; 2218 while( (i < nBytesRead) && (aBuffer[i++] != 0) ); 2219 // skip full name 2220 while( (i < nBytesRead) && (aBuffer[i++] != 0) ); 2221 // retrieve font style name 2222 int nStyleOfs = i; 2223 while( (i < nBytesRead) && (aBuffer[i++] != 0) ); 2224 if( i >= nBytesRead ) 2225 return false; 2226 2227 // convert byte strings to unicode 2228 rDFA.maName = String( aBuffer + nNameOfs, osl_getThreadTextEncoding() ); 2229 rDFA.maStyleName = String( aBuffer + nStyleOfs, osl_getThreadTextEncoding() ); 2230 2231 // byte offset 0x4C7: OS2_fsSelection 2232 const char nFSS = aBuffer[ 0x4C7 ]; 2233 if( nFSS & 0x01 ) // italic 2234 rDFA.meItalic = ITALIC_NORMAL; 2235 //if( nFSS & 0x20 ) // bold 2236 // rDFA.meWeight = WEIGHT_BOLD; 2237 if( nFSS & 0x40 ) // regular 2238 { 2239 rDFA.meWeight = WEIGHT_NORMAL; 2240 rDFA.meItalic = ITALIC_NONE; 2241 } 2242 2243 // byte offsets 0x4D7/0x4D8: wingdi's FW_WEIGHT 2244 int nWinWeight = (aBuffer[0x4D7] & 0xFF) + ((aBuffer[0x4D8] & 0xFF) << 8); 2245 rDFA.meWeight = ImplWeightToSal( nWinWeight ); 2246 2247 rDFA.mbSymbolFlag = false; // TODO 2248 rDFA.mePitch = PITCH_DONTKNOW; // TODO 2249 2250 // byte offset 0x4DE: pitch&family 2251 rDFA.meFamily = ImplFamilyToSal( aBuffer[0x4DE] ); 2252 2253 // byte offsets 0x4C8/0x4C9: emunits 2254 // byte offsets 0x4CE/0x4CF: winascent 2255 // byte offsets 0x4D0/0x4D1: winascent+windescent-emunits 2256 // byte offsets 0x4DF/0x4E0: avgwidth 2257 //... 2258 2259 return true; 2260 } 2261 2262 // ----------------------------------------------------------------------- 2263 2264 bool WinSalGraphics::AddTempDevFont( ImplDevFontList* pFontList, 2265 const String& rFontFileURL, const String& rFontName ) 2266 { 2267 RTL_LOGFILE_TRACE1( "WinSalGraphics::AddTempDevFont(): %s", rtl::OUStringToOString( rFontFileURL, RTL_TEXTENCODING_UTF8 ).getStr() ); 2268 2269 ImplDevFontAttributes aDFA; 2270 aDFA.maName = rFontName; 2271 aDFA.mnQuality = 1000; 2272 aDFA.mbDevice = true; 2273 2274 // Search Font Name in Cache 2275 if( !rFontName.Len() && mpFontAttrCache ) 2276 aDFA = mpFontAttrCache->GetFontAttr( rFontFileURL ); 2277 2278 // Retrieve font name from font resource 2279 if( !aDFA.maName.Len() ) 2280 { 2281 ImplGetFontAttrFromFile( rFontFileURL, aDFA ); 2282 if( mpFontAttrCache && aDFA.maName.Len() ) 2283 mpFontAttrCache->AddFontAttr( rFontFileURL, aDFA ); 2284 } 2285 2286 if ( !aDFA.maName.Len() ) 2287 return false; 2288 2289 // remember temp font for cleanup later 2290 if( !ImplAddTempFont( *GetSalData(), rFontFileURL ) ) 2291 return false; 2292 2293 UINT nPreferedCharSet = DEFAULT_CHARSET; 2294 2295 // create matching FontData struct 2296 aDFA.mbSymbolFlag = false; // TODO: how to know it without accessing the font? 2297 aDFA.meFamily = FAMILY_DONTKNOW; 2298 aDFA.meWidthType = WIDTH_DONTKNOW; 2299 aDFA.meWeight = WEIGHT_DONTKNOW; 2300 aDFA.meItalic = ITALIC_DONTKNOW; 2301 aDFA.mePitch = PITCH_DONTKNOW;; 2302 aDFA.mbSubsettable= true; 2303 aDFA.mbEmbeddable = false; 2304 2305 /* 2306 // TODO: improve ImplDevFontAttributes using the "font resource file" 2307 aDFS.maName = // using "FONTRES:" from file 2308 if( rFontName != aDFS.maName ) 2309 aDFS.maMapName = aFontName; 2310 */ 2311 2312 ImplWinFontData* pFontData = new ImplWinFontData( aDFA, 0, 2313 sal::static_int_cast<BYTE>(nPreferedCharSet), 2314 sal::static_int_cast<BYTE>(TMPF_VECTOR|TMPF_TRUETYPE) ); 2315 pFontData->SetFontId( reinterpret_cast<sal_IntPtr>(pFontData) ); 2316 pFontList->Add( pFontData ); 2317 return true; 2318 } 2319 2320 // ----------------------------------------------------------------------- 2321 2322 void WinSalGraphics::GetDevFontList( ImplDevFontList* pFontList ) 2323 { 2324 // make sure all fonts are registered at least temporarily 2325 static bool bOnce = true; 2326 if( bOnce ) 2327 { 2328 bOnce = false; 2329 2330 // determine font path 2331 // since we are only interested in fonts that could not be 2332 // registered before because of missing administration rights 2333 // only the font path of the user installation is needed 2334 ::rtl::OUString aPath; 2335 osl_getExecutableFile( &aPath.pData ); 2336 ::rtl::OUString aExecutableFile( aPath ); 2337 aPath = aPath.copy( 0, aPath.lastIndexOf('/') ); 2338 String aFontDirUrl = aPath.copy( 0, aPath.lastIndexOf('/') ); 2339 aFontDirUrl += String( RTL_CONSTASCII_USTRINGPARAM("/Basis/share/fonts/truetype") ); 2340 2341 // collect fonts in font path that could not be registered 2342 osl::Directory aFontDir( aFontDirUrl ); 2343 osl::FileBase::RC rcOSL = aFontDir.open(); 2344 if( rcOSL == osl::FileBase::E_None ) 2345 { 2346 osl::DirectoryItem aDirItem; 2347 String aEmptyString; 2348 2349 ::rtl::OUString aBootStrap; 2350 rtl::Bootstrap::get( String( RTL_CONSTASCII_USTRINGPARAM( "BRAND_BASE_DIR" ) ), aBootStrap ); 2351 aBootStrap += String( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) ); 2352 rtl::Bootstrap aBootstrap( aBootStrap ); 2353 ::rtl::OUString aUserPath; 2354 aBootstrap.getFrom( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserInstallation" ) ), aUserPath ); 2355 aUserPath += String( RTL_CONSTASCII_USTRINGPARAM("/user/config/fontnames.dat") ); 2356 String aBaseURL = aPath.copy( 0, aPath.lastIndexOf('/')+1 ); 2357 mpFontAttrCache = new ImplFontAttrCache( aUserPath, aBaseURL ); 2358 2359 while( aFontDir.getNextItem( aDirItem, 10 ) == osl::FileBase::E_None ) 2360 { 2361 osl::FileStatus aFileStatus( FileStatusMask_FileURL ); 2362 rcOSL = aDirItem.getFileStatus( aFileStatus ); 2363 if ( rcOSL == osl::FileBase::E_None ) 2364 AddTempDevFont( pFontList, aFileStatus.getFileURL(), aEmptyString ); 2365 } 2366 2367 delete mpFontAttrCache; // destructor rewrites the cache file if needed 2368 mpFontAttrCache = NULL; 2369 } 2370 } 2371 2372 ImplEnumInfo aInfo; 2373 aInfo.mhDC = mhDC; 2374 aInfo.mpList = pFontList; 2375 aInfo.mpName = NULL; 2376 aInfo.mpLogFontA = NULL; 2377 aInfo.mpLogFontW = NULL; 2378 aInfo.mbCourier = false; 2379 aInfo.mbPrinter = mbPrinter; 2380 aInfo.mnFontCount = 0; 2381 if ( !mbPrinter ) 2382 { 2383 aInfo.mbImplSalCourierScalable = false; 2384 aInfo.mbImplSalCourierNew = false; 2385 } 2386 else 2387 { 2388 aInfo.mbImplSalCourierScalable = true; 2389 aInfo.mbImplSalCourierNew = true; 2390 } 2391 2392 aInfo.mnPreferedCharSet = DEFAULT_CHARSET; 2393 DWORD nCP = GetACP(); 2394 CHARSETINFO aCharSetInfo; 2395 if ( TranslateCharsetInfo( (DWORD*)nCP, &aCharSetInfo, TCI_SRCCODEPAGE ) ) 2396 aInfo.mnPreferedCharSet = aCharSetInfo.ciCharset; 2397 2398 LOGFONTW aLogFont; 2399 memset( &aLogFont, 0, sizeof( aLogFont ) ); 2400 aLogFont.lfCharSet = DEFAULT_CHARSET; 2401 aInfo.mpLogFontW = &aLogFont; 2402 EnumFontFamiliesExW( mhDC, &aLogFont, 2403 (FONTENUMPROCW)SalEnumFontsProcExW, (LPARAM)(void*)&aInfo, 0 ); 2404 2405 // Feststellen, was es fuer Courier-Schriften auf dem Bildschirm gibt, 2406 // um in SetFont() evt. Courier auf Courier New zu mappen 2407 if ( !mbPrinter ) 2408 { 2409 bImplSalCourierScalable = aInfo.mbImplSalCourierScalable; 2410 bImplSalCourierNew = aInfo.mbImplSalCourierNew; 2411 } 2412 2413 // set glyph fallback hook 2414 static WinGlyphFallbackSubstititution aSubstFallback( mhDC ); 2415 pFontList->SetFallbackHook( &aSubstFallback ); 2416 } 2417 2418 // ---------------------------------------------------------------------------- 2419 2420 void WinSalGraphics::GetDevFontSubstList( OutputDevice* ) 2421 {} 2422 2423 // ----------------------------------------------------------------------- 2424 2425 sal_Bool WinSalGraphics::GetGlyphBoundRect( long nIndex, Rectangle& rRect ) 2426 { 2427 HDC hDC = mhDC; 2428 2429 // use unity matrix 2430 MAT2 aMat; 2431 aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 ); 2432 aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 ); 2433 2434 UINT nGGOFlags = GGO_METRICS; 2435 if( !(nIndex & GF_ISCHAR) ) 2436 nGGOFlags |= GGO_GLYPH_INDEX; 2437 nIndex &= GF_IDXMASK; 2438 2439 GLYPHMETRICS aGM; 2440 aGM.gmptGlyphOrigin.x = aGM.gmptGlyphOrigin.y = 0; 2441 aGM.gmBlackBoxX = aGM.gmBlackBoxY = 0; 2442 DWORD nSize = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags, &aGM, 0, NULL, &aMat ); 2443 if( nSize == GDI_ERROR ) 2444 return false; 2445 2446 rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ), 2447 Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) ); 2448 rRect.Left() = static_cast<int>( mfFontScale * rRect.Left() ); 2449 rRect.Right() = static_cast<int>( mfFontScale * rRect.Right() ); 2450 rRect.Top() = static_cast<int>( mfFontScale * rRect.Top() ); 2451 rRect.Bottom() = static_cast<int>( mfFontScale * rRect.Bottom() ); 2452 return true; 2453 } 2454 2455 // ----------------------------------------------------------------------- 2456 2457 sal_Bool WinSalGraphics::GetGlyphOutline( long nIndex, 2458 ::basegfx::B2DPolyPolygon& rB2DPolyPoly ) 2459 { 2460 rB2DPolyPoly.clear(); 2461 2462 HDC hDC = mhDC; 2463 2464 // use unity matrix 2465 MAT2 aMat; 2466 aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 ); 2467 aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 ); 2468 2469 UINT nGGOFlags = GGO_NATIVE; 2470 if( !(nIndex & GF_ISCHAR) ) 2471 nGGOFlags |= GGO_GLYPH_INDEX; 2472 nIndex &= GF_IDXMASK; 2473 2474 GLYPHMETRICS aGlyphMetrics; 2475 const DWORD nSize1 = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat ); 2476 if( !nSize1 ) // blank glyphs are ok 2477 return TRUE; 2478 else if( nSize1 == GDI_ERROR ) 2479 return FALSE; 2480 2481 BYTE* pData = new BYTE[ nSize1 ]; 2482 const DWORD nSize2 = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags, 2483 &aGlyphMetrics, nSize1, pData, &aMat ); 2484 2485 if( nSize1 != nSize2 ) 2486 return FALSE; 2487 2488 // TODO: avoid tools polygon by creating B2DPolygon directly 2489 int nPtSize = 512; 2490 Point* pPoints = new Point[ nPtSize ]; 2491 BYTE* pFlags = new BYTE[ nPtSize ]; 2492 2493 TTPOLYGONHEADER* pHeader = (TTPOLYGONHEADER*)pData; 2494 while( (BYTE*)pHeader < pData+nSize2 ) 2495 { 2496 // only outline data is interesting 2497 if( pHeader->dwType != TT_POLYGON_TYPE ) 2498 break; 2499 2500 // get start point; next start points are end points 2501 // of previous segment 2502 USHORT nPnt = 0; 2503 2504 long nX = IntTimes256FromFixed( pHeader->pfxStart.x ); 2505 long nY = IntTimes256FromFixed( pHeader->pfxStart.y ); 2506 pPoints[ nPnt ] = Point( nX, nY ); 2507 pFlags[ nPnt++ ] = POLY_NORMAL; 2508 2509 bool bHasOfflinePoints = false; 2510 TTPOLYCURVE* pCurve = (TTPOLYCURVE*)( pHeader + 1 ); 2511 pHeader = (TTPOLYGONHEADER*)( (BYTE*)pHeader + pHeader->cb ); 2512 while( (BYTE*)pCurve < (BYTE*)pHeader ) 2513 { 2514 int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx; 2515 if( nPtSize < nNeededSize ) 2516 { 2517 Point* pOldPoints = pPoints; 2518 BYTE* pOldFlags = pFlags; 2519 nPtSize = 2 * nNeededSize; 2520 pPoints = new Point[ nPtSize ]; 2521 pFlags = new BYTE[ nPtSize ]; 2522 for( USHORT i = 0; i < nPnt; ++i ) 2523 { 2524 pPoints[ i ] = pOldPoints[ i ]; 2525 pFlags[ i ] = pOldFlags[ i ]; 2526 } 2527 delete[] pOldPoints; 2528 delete[] pOldFlags; 2529 } 2530 2531 int i = 0; 2532 if( TT_PRIM_LINE == pCurve->wType ) 2533 { 2534 while( i < pCurve->cpfx ) 2535 { 2536 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x ); 2537 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y ); 2538 ++i; 2539 pPoints[ nPnt ] = Point( nX, nY ); 2540 pFlags[ nPnt ] = POLY_NORMAL; 2541 ++nPnt; 2542 } 2543 } 2544 else if( TT_PRIM_QSPLINE == pCurve->wType ) 2545 { 2546 bHasOfflinePoints = true; 2547 while( i < pCurve->cpfx ) 2548 { 2549 // get control point of quadratic bezier spline 2550 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x ); 2551 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y ); 2552 ++i; 2553 Point aControlP( nX, nY ); 2554 2555 // calculate first cubic control point 2556 // P0 = 1/3 * (PBeg + 2 * PQControl) 2557 nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X(); 2558 nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y(); 2559 pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 ); 2560 pFlags[ nPnt+0 ] = POLY_CONTROL; 2561 2562 // calculate endpoint of segment 2563 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x ); 2564 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y ); 2565 2566 if ( i+1 >= pCurve->cpfx ) 2567 { 2568 // endpoint is either last point in segment => advance 2569 ++i; 2570 } 2571 else 2572 { 2573 // or endpoint is the middle of two control points 2574 nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x ); 2575 nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y ); 2576 nX = (nX + 1) / 2; 2577 nY = (nY + 1) / 2; 2578 // no need to advance, because the current point 2579 // is the control point in next bezier spline 2580 } 2581 2582 pPoints[ nPnt+2 ] = Point( nX, nY ); 2583 pFlags[ nPnt+2 ] = POLY_NORMAL; 2584 2585 // calculate second cubic control point 2586 // P1 = 1/3 * (PEnd + 2 * PQControl) 2587 nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X(); 2588 nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y(); 2589 pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 ); 2590 pFlags[ nPnt+1 ] = POLY_CONTROL; 2591 2592 nPnt += 3; 2593 } 2594 } 2595 2596 // next curve segment 2597 pCurve = (TTPOLYCURVE*)&pCurve->apfx[ i ]; 2598 } 2599 2600 // end point is start point for closed contour 2601 // disabled, because Polygon class closes the contour itself 2602 // pPoints[nPnt++] = pPoints[0]; 2603 // #i35928# 2604 // Added again, but add only when not yet closed 2605 if(pPoints[nPnt - 1] != pPoints[0]) 2606 { 2607 if( bHasOfflinePoints ) 2608 pFlags[nPnt] = pFlags[0]; 2609 2610 pPoints[nPnt++] = pPoints[0]; 2611 } 2612 2613 // convert y-coordinates W32 -> VCL 2614 for( int i = 0; i < nPnt; ++i ) 2615 pPoints[i].Y() = -pPoints[i].Y(); 2616 2617 // insert into polypolygon 2618 Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : NULL) ); 2619 // convert to B2DPolyPolygon 2620 // TODO: get rid of the intermediate PolyPolygon 2621 rB2DPolyPoly.append( aPoly.getB2DPolygon() ); 2622 } 2623 2624 delete[] pPoints; 2625 delete[] pFlags; 2626 2627 delete[] pData; 2628 2629 // rescaling needed for the PolyPolygon conversion 2630 if( rB2DPolyPoly.count() ) 2631 { 2632 const double fFactor(mfFontScale/256); 2633 rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fFactor, fFactor)); 2634 } 2635 2636 return TRUE; 2637 } 2638 2639 // ----------------------------------------------------------------------- 2640 2641 class ScopedFont 2642 { 2643 public: 2644 explicit ScopedFont(WinSalGraphics & rData); 2645 2646 ~ScopedFont(); 2647 2648 private: 2649 WinSalGraphics & m_rData; 2650 HFONT m_hOrigFont; 2651 }; 2652 2653 ScopedFont::ScopedFont(WinSalGraphics & rData): m_rData(rData) 2654 { 2655 m_hOrigFont = m_rData.mhFonts[0]; 2656 m_rData.mhFonts[0] = 0; // avoid deletion of current font 2657 } 2658 2659 ScopedFont::~ScopedFont() 2660 { 2661 if( m_hOrigFont ) 2662 { 2663 // restore original font, destroy temporary font 2664 HFONT hTempFont = m_rData.mhFonts[0]; 2665 m_rData.mhFonts[0] = m_hOrigFont; 2666 SelectObject( m_rData.mhDC, m_hOrigFont ); 2667 DeleteObject( hTempFont ); 2668 } 2669 } 2670 2671 class ScopedTrueTypeFont 2672 { 2673 public: 2674 inline ScopedTrueTypeFont(): m_pFont(0) {} 2675 2676 ~ScopedTrueTypeFont(); 2677 2678 int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum); 2679 2680 inline TrueTypeFont * get() const { return m_pFont; } 2681 2682 private: 2683 TrueTypeFont * m_pFont; 2684 }; 2685 2686 ScopedTrueTypeFont::~ScopedTrueTypeFont() 2687 { 2688 if (m_pFont != 0) 2689 CloseTTFont(m_pFont); 2690 } 2691 2692 int ScopedTrueTypeFont::open(void * pBuffer, sal_uInt32 nLen, 2693 sal_uInt32 nFaceNum) 2694 { 2695 OSL_ENSURE(m_pFont == 0, "already open"); 2696 return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont); 2697 } 2698 2699 sal_Bool WinSalGraphics::CreateFontSubset( const rtl::OUString& rToFile, 2700 const ImplFontData* pFont, long* pGlyphIDs, sal_uInt8* pEncoding, 2701 sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo ) 2702 { 2703 // TODO: use more of the central font-subsetting code, move stuff there if needed 2704 2705 // create matching ImplFontSelectData 2706 // we need just enough to get to the font file data 2707 // use height=1000 for easier debugging (to match psprint's font units) 2708 ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false ); 2709 2710 // TODO: much better solution: move SetFont and restoration of old font to caller 2711 ScopedFont aOldFont(*this); 2712 float fScale = 1.0; 2713 HFONT hOldFont = 0; 2714 ImplDoSetFont( &aIFSD, fScale, hOldFont ); 2715 2716 ImplWinFontData* pWinFontData = (ImplWinFontData*)aIFSD.mpFontData; 2717 2718 #if OSL_DEBUG_LEVEL > 1 2719 // get font metrics 2720 TEXTMETRICA aWinMetric; 2721 if( !::GetTextMetricsA( mhDC, &aWinMetric ) ) 2722 return FALSE; 2723 2724 DBG_ASSERT( !(aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "cannot subset device font" ); 2725 DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" ); 2726 #endif 2727 2728 rtl::OUString aSysPath; 2729 if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) ) 2730 return FALSE; 2731 const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding(); 2732 const ByteString aToFile( aSysPath.getStr(), (xub_StrLen)aSysPath.getLength(), aThreadEncoding ); 2733 2734 // check if the font has a CFF-table 2735 const DWORD nCffTag = CalcTag( "CFF " ); 2736 const RawFontData aRawCffData( mhDC, nCffTag ); 2737 if( aRawCffData.get() ) 2738 { 2739 pWinFontData->UpdateFromHDC( mhDC ); 2740 const ImplFontCharMap* pCharMap = pWinFontData->GetImplFontCharMap(); 2741 pCharMap->AddReference(); 2742 2743 long nRealGlyphIds[ 256 ]; 2744 for( int i = 0; i < nGlyphCount; ++i ) 2745 { 2746 // TODO: remap notdef glyph if needed 2747 // TODO: use GDI's GetGlyphIndices instead? Does it handle GSUB properly? 2748 sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK; 2749 if( pGlyphIDs[i] & GF_ISCHAR ) // remaining pseudo-glyphs need to be translated 2750 nGlyphIdx = pCharMap->GetGlyphIndex( nGlyphIdx ); 2751 if( (pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0) // TODO: vertical substitution 2752 {/*####*/} 2753 2754 nRealGlyphIds[i] = nGlyphIdx; 2755 } 2756 2757 pCharMap->DeReference(); // TODO: and and use a RAII object 2758 2759 // provide a font subset from the CFF-table 2760 FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" ); 2761 rInfo.LoadFont( FontSubsetInfo::CFF_FONT, aRawCffData.get(), aRawCffData.size() ); 2762 bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL, 2763 nRealGlyphIds, pEncoding, nGlyphCount, pGlyphWidths ); 2764 fclose( pOutFile ); 2765 return bRC; 2766 } 2767 2768 // get raw font file data 2769 const RawFontData xRawFontData( mhDC, NULL ); 2770 if( !xRawFontData.get() ) 2771 return FALSE; 2772 2773 // open font file 2774 sal_uInt32 nFaceNum = 0; 2775 if( !*xRawFontData.get() ) // TTC candidate 2776 nFaceNum = ~0U; // indicate "TTC font extracts only" 2777 2778 ScopedTrueTypeFont aSftTTF; 2779 int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum ); 2780 if( nRC != SF_OK ) 2781 return FALSE; 2782 2783 TTGlobalFontInfo aTTInfo; 2784 ::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo ); 2785 rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; 2786 rInfo.m_aPSName = ImplSalGetUniString( aTTInfo.psname ); 2787 rInfo.m_nAscent = aTTInfo.winAscent; 2788 rInfo.m_nDescent = aTTInfo.winDescent; 2789 rInfo.m_aFontBBox = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ), 2790 Point( aTTInfo.xMax, aTTInfo.yMax ) ); 2791 rInfo.m_nCapHeight = aTTInfo.yMax; // Well ... 2792 2793 // subset TTF-glyphs and get their properties 2794 // take care that subset fonts require the NotDef glyph in pos 0 2795 int nOrigCount = nGlyphCount; 2796 sal_uInt16 aShortIDs[ 256 ]; 2797 sal_uInt8 aTempEncs[ 256 ]; 2798 2799 int nNotDef=-1, i; 2800 for( i = 0; i < nGlyphCount; ++i ) 2801 { 2802 aTempEncs[i] = pEncoding[i]; 2803 sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK; 2804 if( pGlyphIDs[i] & GF_ISCHAR ) 2805 { 2806 sal_Unicode cChar = static_cast<sal_Unicode>(nGlyphIdx); // TODO: sal_UCS4 2807 const bool bVertical = ((pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0); 2808 nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical ); 2809 if( (nGlyphIdx == 0) && pFont->IsSymbolFont() ) 2810 { 2811 // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX 2812 cChar = (cChar & 0xF000) ? (cChar & 0x00FF) : (cChar | 0xF000); 2813 nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical ); 2814 } 2815 } 2816 aShortIDs[i] = static_cast<sal_uInt16>( nGlyphIdx ); 2817 if( !nGlyphIdx ) 2818 if( nNotDef < 0 ) 2819 nNotDef = i; // first NotDef glyph found 2820 } 2821 2822 if( nNotDef != 0 ) 2823 { 2824 // add fake NotDef glyph if needed 2825 if( nNotDef < 0 ) 2826 nNotDef = nGlyphCount++; 2827 2828 // NotDef glyph must be in pos 0 => swap glyphids 2829 aShortIDs[ nNotDef ] = aShortIDs[0]; 2830 aTempEncs[ nNotDef ] = aTempEncs[0]; 2831 aShortIDs[0] = 0; 2832 aTempEncs[0] = 0; 2833 } 2834 DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" ); 2835 2836 // fill pWidth array 2837 TTSimpleGlyphMetrics* pMetrics = 2838 ::GetTTSimpleGlyphMetrics( aSftTTF.get(), aShortIDs, nGlyphCount, aIFSD.mbVertical ); 2839 if( !pMetrics ) 2840 return FALSE; 2841 sal_uInt16 nNotDefAdv = pMetrics[0].adv; 2842 pMetrics[0].adv = pMetrics[nNotDef].adv; 2843 pMetrics[nNotDef].adv = nNotDefAdv; 2844 for( i = 0; i < nOrigCount; ++i ) 2845 pGlyphWidths[i] = pMetrics[i].adv; 2846 free( pMetrics ); 2847 2848 // write subset into destination file 2849 nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.GetBuffer(), aShortIDs, 2850 aTempEncs, nGlyphCount, 0, NULL, 0 ); 2851 return (nRC == SF_OK); 2852 } 2853 2854 //-------------------------------------------------------------------------- 2855 2856 const void* WinSalGraphics::GetEmbedFontData( const ImplFontData* pFont, 2857 const sal_Unicode* pUnicodes, sal_Int32* pCharWidths, 2858 FontSubsetInfo& rInfo, long* pDataLen ) 2859 { 2860 // create matching ImplFontSelectData 2861 // we need just enough to get to the font file data 2862 ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false ); 2863 2864 // TODO: much better solution: move SetFont and restoration of old font to caller 2865 ScopedFont aOldFont(*this); 2866 SetFont( &aIFSD, 0 ); 2867 2868 // get the raw font file data 2869 RawFontData aRawFontData( mhDC ); 2870 *pDataLen = aRawFontData.size(); 2871 if( !aRawFontData.get() ) 2872 return NULL; 2873 2874 // get important font properties 2875 TEXTMETRICA aTm; 2876 if( !::GetTextMetricsA( mhDC, &aTm ) ) 2877 *pDataLen = 0; 2878 const bool bPFA = (*aRawFontData.get() < 0x80); 2879 rInfo.m_nFontType = bPFA ? FontSubsetInfo::TYPE1_PFA : FontSubsetInfo::TYPE1_PFB; 2880 WCHAR aFaceName[64]; 2881 int nFNLen = ::GetTextFaceW( mhDC, 64, aFaceName ); 2882 // #i59854# strip eventual null byte 2883 while( nFNLen > 0 && aFaceName[nFNLen-1] == 0 ) 2884 nFNLen--; 2885 if( nFNLen == 0 ) 2886 *pDataLen = 0; 2887 rInfo.m_aPSName = String( reinterpret_cast<const sal_Unicode*>(aFaceName), sal::static_int_cast<sal_uInt16>(nFNLen) ); 2888 rInfo.m_nAscent = +aTm.tmAscent; 2889 rInfo.m_nDescent = -aTm.tmDescent; 2890 rInfo.m_aFontBBox = Rectangle( Point( -aTm.tmOverhang, -aTm.tmDescent ), 2891 Point( aTm.tmMaxCharWidth, aTm.tmAscent+aTm.tmExternalLeading ) ); 2892 rInfo.m_nCapHeight = aTm.tmAscent; // Well ... 2893 2894 // get individual character widths 2895 for( int i = 0; i < 256; ++i ) 2896 { 2897 int nCharWidth = 0; 2898 const sal_Unicode cChar = pUnicodes[i]; 2899 if( !::GetCharWidth32W( mhDC, cChar, cChar, &nCharWidth ) ) 2900 *pDataLen = 0; 2901 pCharWidths[i] = nCharWidth; 2902 } 2903 2904 if( !*pDataLen ) 2905 return NULL; 2906 2907 const unsigned char* pData = aRawFontData.steal(); 2908 return (void*)pData; 2909 } 2910 2911 //-------------------------------------------------------------------------- 2912 2913 void WinSalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ ) 2914 { 2915 delete[] reinterpret_cast<char*>(const_cast<void*>(pData)); 2916 } 2917 2918 //-------------------------------------------------------------------------- 2919 2920 const Ucs2SIntMap* WinSalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded ) 2921 { 2922 // TODO: even for builtin fonts we get here... why? 2923 if( !pFont->IsEmbeddable() ) 2924 return NULL; 2925 2926 // fill the encoding vector 2927 // currently no nonencoded vector 2928 if( pNonEncoded ) 2929 *pNonEncoded = NULL; 2930 2931 const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>(pFont); 2932 const Ucs2SIntMap* pEncoding = pWinFontData->GetEncodingVector(); 2933 if( pEncoding == NULL ) 2934 { 2935 Ucs2SIntMap* pNewEncoding = new Ucs2SIntMap; 2936 #if 0 2937 // TODO: get correct encoding vector 2938 GLYPHSET aGlyphSet; 2939 aGlyphSet.cbThis = sizeof(aGlyphSet); 2940 DWORD aW = ::GetFontUnicodeRanges( mhDC, &aGlyphSet); 2941 #else 2942 for( sal_Unicode i = 32; i < 256; ++i ) 2943 (*pNewEncoding)[i] = i; 2944 #endif 2945 pWinFontData->SetEncodingVector( pNewEncoding ); 2946 pEncoding = pNewEncoding; 2947 } 2948 2949 return pEncoding; 2950 } 2951 2952 //-------------------------------------------------------------------------- 2953 2954 void WinSalGraphics::GetGlyphWidths( const ImplFontData* pFont, 2955 bool bVertical, 2956 Int32Vector& rWidths, 2957 Ucs2UIntMap& rUnicodeEnc ) 2958 { 2959 // create matching ImplFontSelectData 2960 // we need just enough to get to the font file data 2961 ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false ); 2962 2963 // TODO: much better solution: move SetFont and restoration of old font to caller 2964 ScopedFont aOldFont(*this); 2965 2966 float fScale = 0.0; 2967 HFONT hOldFont = 0; 2968 ImplDoSetFont( &aIFSD, fScale, hOldFont ); 2969 2970 if( pFont->IsSubsettable() ) 2971 { 2972 // get raw font file data 2973 const RawFontData xRawFontData( mhDC ); 2974 if( !xRawFontData.get() ) 2975 return; 2976 2977 // open font file 2978 sal_uInt32 nFaceNum = 0; 2979 if( !*xRawFontData.get() ) // TTC candidate 2980 nFaceNum = ~0U; // indicate "TTC font extracts only" 2981 2982 ScopedTrueTypeFont aSftTTF; 2983 int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum ); 2984 if( nRC != SF_OK ) 2985 return; 2986 2987 int nGlyphs = GetTTGlyphCount( aSftTTF.get() ); 2988 if( nGlyphs > 0 ) 2989 { 2990 rWidths.resize(nGlyphs); 2991 std::vector<sal_uInt16> aGlyphIds(nGlyphs); 2992 for( int i = 0; i < nGlyphs; i++ ) 2993 aGlyphIds[i] = sal_uInt16(i); 2994 TTSimpleGlyphMetrics* pMetrics = ::GetTTSimpleGlyphMetrics( aSftTTF.get(), 2995 &aGlyphIds[0], 2996 nGlyphs, 2997 bVertical ? 1 : 0 ); 2998 if( pMetrics ) 2999 { 3000 for( int i = 0; i< nGlyphs; i++ ) 3001 rWidths[i] = pMetrics[i].adv; 3002 free( pMetrics ); 3003 rUnicodeEnc.clear(); 3004 } 3005 const ImplWinFontData* pWinFont = static_cast<const ImplWinFontData*>(pFont); 3006 const ImplFontCharMap* pMap = pWinFont->GetImplFontCharMap(); 3007 DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" ); 3008 pMap->AddReference(); 3009 3010 int nCharCount = pMap->GetCharCount(); 3011 sal_uInt32 nChar = pMap->GetFirstChar(); 3012 for( int i = 0; i < nCharCount; i++ ) 3013 { 3014 if( nChar < 0x00010000 ) 3015 { 3016 sal_uInt16 nGlyph = ::MapChar( aSftTTF.get(), 3017 static_cast<sal_Ucs>(nChar), 3018 bVertical ? 1 : 0 ); 3019 if( nGlyph ) 3020 rUnicodeEnc[ static_cast<sal_Unicode>(nChar) ] = nGlyph; 3021 } 3022 nChar = pMap->GetNextChar( nChar ); 3023 } 3024 3025 pMap->DeReference(); // TODO: and and use a RAII object 3026 } 3027 } 3028 else if( pFont->IsEmbeddable() ) 3029 { 3030 // get individual character widths 3031 rWidths.clear(); 3032 rUnicodeEnc.clear(); 3033 rWidths.reserve( 224 ); 3034 for( sal_Unicode i = 32; i < 256; ++i ) 3035 { 3036 int nCharWidth = 0; 3037 if( ::GetCharWidth32W( mhDC, i, i, &nCharWidth ) ) 3038 { 3039 rUnicodeEnc[ i ] = rWidths.size(); 3040 rWidths.push_back( nCharWidth ); 3041 } 3042 } 3043 } 3044 } 3045 3046 //-------------------------------------------------------------------------- 3047 3048 void WinSalGraphics::DrawServerFontLayout( const ServerFontLayout& ) 3049 {} 3050 3051 //-------------------------------------------------------------------------- 3052 3053 SystemFontData WinSalGraphics::GetSysFontData( int nFallbacklevel ) const 3054 { 3055 SystemFontData aSysFontData; 3056 3057 if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1; 3058 if (nFallbacklevel < 0 ) nFallbacklevel = 0; 3059 3060 aSysFontData.nSize = sizeof( SystemFontData ); 3061 aSysFontData.hFont = mhFonts[nFallbacklevel]; 3062 aSysFontData.bFakeBold = false; 3063 aSysFontData.bFakeItalic = false; 3064 aSysFontData.bAntialias = true; 3065 aSysFontData.bVerticalCharacterType = false; 3066 3067 OSL_TRACE("\r\n:WinSalGraphics::GetSysFontData(): FontID: %p, Fallback level: %d", 3068 aSysFontData.hFont, 3069 nFallbacklevel); 3070 3071 return aSysFontData; 3072 } 3073 3074 //-------------------------------------------------------------------------- 3075 3076