PageRenderTime 97ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 2ms

/OOO330_m20/vcl/win/source/gdi/salgdi3.cxx

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