PageRenderTime 62ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

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

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