merge the formfield patch from ooo-build
[ooovba.git] / vcl / win / source / gdi / salgdi3.cxx
blobbdc4fab8aec0116a09ff68fc93fd5f7ddce95943
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
31 #include <string.h>
32 #include <malloc.h>
34 #include <tools/prewin.h>
35 #include <windows.h>
36 #include <tools/postwin.h>
37 #include <vcl/sysdata.hxx>
38 #include "tools/svwin.h"
40 #include "wincomp.hxx"
41 #include "saldata.hxx"
42 #include "salgdi.h"
44 #include "vcl/svapp.hxx"
45 #include "vcl/outfont.hxx"
46 #include "vcl/font.hxx"
47 #include "vcl/fontsubset.hxx"
48 #include "vcl/sallayout.hxx"
50 #include "rtl/logfile.hxx"
51 #include "rtl/tencinfo.h"
52 #include "rtl/textcvt.h"
53 #include "rtl/bootstrap.hxx"
56 #include "osl/module.h"
57 #include "osl/file.hxx"
58 #include "osl/thread.hxx"
59 #include "osl/process.h"
61 #include "tools/poly.hxx"
62 #include "tools/debug.hxx"
63 #include "tools/stream.hxx"
65 #include "basegfx/polygon/b2dpolygon.hxx"
66 #include "basegfx/polygon/b2dpolypolygon.hxx"
67 #include "basegfx/matrix/b2dhommatrix.hxx"
69 #include "sft.hxx"
71 #ifdef GCP_KERN_HACK
72 #include <algorithm>
73 #endif
75 #ifdef ENABLE_GRAPHITE
76 #include <graphite/GrClient.h>
77 #include <graphite/WinFont.h>
78 #endif
80 #include <vector>
81 #include <set>
82 #include <map>
85 using namespace vcl;
87 static const int MAXFONTHEIGHT = 2048;
89 // -----------
90 // - Inlines -
91 // -----------
93 inline FIXED FixedFromDouble( double d )
95 const long l = (long) ( d * 65536. );
96 return *(FIXED*) &l;
99 // -----------------------------------------------------------------------
101 inline int IntTimes256FromFixed(FIXED f)
103 int nFixedTimes256 = (f.value << 8) + ((f.fract+0x80) >> 8);
104 return nFixedTimes256;
107 // =======================================================================
109 // these variables can be static because they store system wide settings
110 static bool bImplSalCourierScalable = false;
111 static bool bImplSalCourierNew = false;
114 // =======================================================================
116 // -----------------------------------------------------------------------
118 // TODO: also support temporary TTC font files
119 typedef std::map< String, ImplDevFontAttributes > FontAttrMap;
121 class ImplFontAttrCache
123 private:
124 FontAttrMap aFontAttributes;
125 rtl::OUString aCacheFileName;
126 String aBaseURL;
127 BOOL bModified;
129 protected:
130 String OptimizeURL( const String& rURL ) const;
132 enum{ MAGIC = 0x12349876 }; // change if fontattrcache format changes
134 public:
135 ImplFontAttrCache( const String& rCacheFileName, const String& rBaseURL );
136 ~ImplFontAttrCache();
138 ImplDevFontAttributes GetFontAttr( const String& rFontFileName ) const;
139 void AddFontAttr( const String& rFontFileName, const ImplDevFontAttributes& );
142 ImplFontAttrCache::ImplFontAttrCache( const String& rFileNameURL, const String& rBaseURL ) : aBaseURL( rBaseURL )
144 bModified = FALSE;
145 aBaseURL.ToLowerAscii(); // Windows only, no problem...
147 // open the cache file
148 osl::FileBase::getSystemPathFromFileURL( rFileNameURL, aCacheFileName );
149 SvFileStream aCacheFile( aCacheFileName, STREAM_READ );
150 if( !aCacheFile.IsOpen() )
151 return;
153 // check the cache version
154 sal_uInt32 nCacheMagic;
155 aCacheFile >> nCacheMagic;
156 if( nCacheMagic != ImplFontAttrCache::MAGIC )
157 return; // ignore cache and rewrite if no match
159 // read the cache entries from the file
160 String aFontFileURL, aFontName;
161 ImplDevFontAttributes aDFA;
162 for(;;)
164 aCacheFile.ReadByteString( aFontFileURL, RTL_TEXTENCODING_UTF8 );
165 if( !aFontFileURL.Len() )
166 break;
167 aCacheFile.ReadByteString( aDFA.maName, RTL_TEXTENCODING_UTF8 );
169 short n;
170 aCacheFile >> n; aDFA.meWeight = static_cast<FontWeight>(n);
171 aCacheFile >> n; aDFA.meItalic = static_cast<FontItalic>(n);
172 aCacheFile >> n; aDFA.mePitch = static_cast<FontPitch>(n);
173 aCacheFile >> n; aDFA.meWidthType = static_cast<FontWidth>(n);
174 aCacheFile >> n; aDFA.meFamily = static_cast<FontFamily>(n);
175 aCacheFile >> n; aDFA.mbSymbolFlag = (n != 0);
177 aCacheFile.ReadByteStringLine( aDFA.maStyleName, RTL_TEXTENCODING_UTF8 );
179 aFontAttributes[ aFontFileURL ] = aDFA;
183 ImplFontAttrCache::~ImplFontAttrCache()
185 if ( bModified )
187 SvFileStream aCacheFile( aCacheFileName, STREAM_WRITE|STREAM_TRUNC );
188 if ( aCacheFile.IsWritable() )
190 sal_uInt32 nCacheMagic = ImplFontAttrCache::MAGIC;
191 aCacheFile << nCacheMagic;
193 // write the cache entries to the file
194 FontAttrMap::const_iterator aIter = aFontAttributes.begin();
195 while ( aIter != aFontAttributes.end() )
197 const String rFontFileURL( (*aIter).first );
198 const ImplDevFontAttributes& rDFA( (*aIter).second );
199 aCacheFile.WriteByteString( rFontFileURL, RTL_TEXTENCODING_UTF8 );
200 aCacheFile.WriteByteString( rDFA.maName, RTL_TEXTENCODING_UTF8 );
202 aCacheFile << static_cast<short>(rDFA.meWeight);
203 aCacheFile << static_cast<short>(rDFA.meItalic);
204 aCacheFile << static_cast<short>(rDFA.mePitch);
205 aCacheFile << static_cast<short>(rDFA.meWidthType);
206 aCacheFile << static_cast<short>(rDFA.meFamily);
207 aCacheFile << static_cast<short>(rDFA.mbSymbolFlag != false);
209 aCacheFile.WriteByteStringLine( rDFA.maStyleName, RTL_TEXTENCODING_UTF8 );
211 aIter++;
213 // EOF Marker
214 String aEmptyStr;
215 aCacheFile.WriteByteString( aEmptyStr, RTL_TEXTENCODING_UTF8 );
220 String ImplFontAttrCache::OptimizeURL( const String& rURL ) const
222 String aOptimizedFontFileURL( rURL );
223 aOptimizedFontFileURL.ToLowerAscii(); // Windows only, no problem...
224 if ( aOptimizedFontFileURL.CompareTo( aBaseURL, aBaseURL.Len() ) == COMPARE_EQUAL )
225 aOptimizedFontFileURL = aOptimizedFontFileURL.Copy( aBaseURL.Len() );
226 return aOptimizedFontFileURL;
229 ImplDevFontAttributes ImplFontAttrCache::GetFontAttr( const String& rFontFileName ) const
231 ImplDevFontAttributes aDFA;
232 FontAttrMap::const_iterator it = aFontAttributes.find( OptimizeURL( rFontFileName ) );
233 if( it != aFontAttributes.end() )
235 aDFA = it->second;
237 return aDFA;
240 void ImplFontAttrCache::AddFontAttr( const String& rFontFileName, const ImplDevFontAttributes& rDFA )
242 DBG_ASSERT( rFontFileName.Len() && rDFA.maName.Len(), "ImplFontNameCache::AddFontName - invalid data!" );
243 if ( rFontFileName.Len() && rDFA.maName.Len() )
245 aFontAttributes.insert( FontAttrMap::value_type( OptimizeURL( rFontFileName ), rDFA ) );
246 bModified = TRUE;
250 // =======================================================================
252 // raw font data with a scoped lifetime
253 class RawFontData
255 public:
256 explicit RawFontData( HDC, DWORD nTableTag=0 );
257 ~RawFontData() { delete[] mpRawBytes; }
258 const unsigned char* get() const { return mpRawBytes; }
259 const unsigned char* steal() { unsigned char* p = mpRawBytes; mpRawBytes = NULL; return p; }
260 const int size() const { return mnByteCount; }
262 private:
263 unsigned char* mpRawBytes;
264 int mnByteCount;
267 RawFontData::RawFontData( HDC hDC, DWORD nTableTag )
268 : mpRawBytes( NULL )
269 , mnByteCount( 0 )
271 // get required size in bytes
272 mnByteCount = ::GetFontData( hDC, nTableTag, 0, NULL, 0 );
273 if( mnByteCount == GDI_ERROR )
274 return;
275 else if( !mnByteCount )
276 return;
278 // allocate the array
279 mpRawBytes = new unsigned char[ mnByteCount ];
281 // get raw data in chunks small enough for GetFontData()
282 int nRawDataOfs = 0;
283 DWORD nMaxChunkSize = 0x100000;
284 for(;;)
286 // calculate remaining raw data to get
287 DWORD nFDGet = mnByteCount - nRawDataOfs;
288 if( nFDGet <= 0 )
289 break;
290 // #i56745# limit GetFontData requests
291 if( nFDGet > nMaxChunkSize )
292 nFDGet = nMaxChunkSize;
293 const DWORD nFDGot = ::GetFontData( hDC, nTableTag, nRawDataOfs,
294 (void*)(mpRawBytes + nRawDataOfs), nFDGet );
295 if( !nFDGot )
296 break;
297 else if( nFDGot != GDI_ERROR )
298 nRawDataOfs += nFDGot;
299 else
301 // was the chunk too big? reduce it
302 nMaxChunkSize /= 2;
303 if( nMaxChunkSize < 0x10000 )
304 break;
308 // cleanup if the raw data is incomplete
309 if( nRawDataOfs != mnByteCount )
311 delete[] mpRawBytes;
312 mpRawBytes = NULL;
316 // =======================================================================
318 struct ImplEnumInfo
320 HDC mhDC;
321 ImplDevFontList* mpList;
322 String* mpName;
323 LOGFONTA* mpLogFontA;
324 LOGFONTW* mpLogFontW;
325 UINT mnPreferedCharSet;
326 bool mbCourier;
327 bool mbImplSalCourierScalable;
328 bool mbImplSalCourierNew;
329 bool mbPrinter;
330 int mnFontCount;
333 // =======================================================================
335 static CharSet ImplCharSetToSal( BYTE nCharSet )
337 rtl_TextEncoding eTextEncoding;
339 if ( nCharSet == OEM_CHARSET )
341 UINT nCP = (USHORT)GetOEMCP();
342 switch ( nCP )
344 // It is unclear why these two (undefined?) code page numbers are
345 // handled specially here:
346 case 1004: eTextEncoding = RTL_TEXTENCODING_MS_1252; break;
347 case 65400: eTextEncoding = RTL_TEXTENCODING_SYMBOL; break;
348 default:
349 eTextEncoding = rtl_getTextEncodingFromWindowsCodePage(nCP);
350 break;
353 else
355 if( nCharSet )
356 eTextEncoding = rtl_getTextEncodingFromWindowsCharset( nCharSet );
357 else
358 eTextEncoding = RTL_TEXTENCODING_UNICODE;
361 return eTextEncoding;
364 // -----------------------------------------------------------------------
366 static FontFamily ImplFamilyToSal( BYTE nFamily )
368 switch ( nFamily & 0xF0 )
370 case FF_DECORATIVE:
371 return FAMILY_DECORATIVE;
373 case FF_MODERN:
374 return FAMILY_MODERN;
376 case FF_ROMAN:
377 return FAMILY_ROMAN;
379 case FF_SCRIPT:
380 return FAMILY_SCRIPT;
382 case FF_SWISS:
383 return FAMILY_SWISS;
385 default:
386 break;
389 return FAMILY_DONTKNOW;
392 // -----------------------------------------------------------------------
394 static BYTE ImplFamilyToWin( FontFamily eFamily )
396 switch ( eFamily )
398 case FAMILY_DECORATIVE:
399 return FF_DECORATIVE;
401 case FAMILY_MODERN:
402 return FF_MODERN;
404 case FAMILY_ROMAN:
405 return FF_ROMAN;
407 case FAMILY_SCRIPT:
408 return FF_SCRIPT;
410 case FAMILY_SWISS:
411 return FF_SWISS;
413 case FAMILY_SYSTEM:
414 return FF_SWISS;
416 default:
417 break;
420 return FF_DONTCARE;
423 // -----------------------------------------------------------------------
425 static FontWeight ImplWeightToSal( int nWeight )
427 if ( nWeight <= FW_THIN )
428 return WEIGHT_THIN;
429 else if ( nWeight <= FW_ULTRALIGHT )
430 return WEIGHT_ULTRALIGHT;
431 else if ( nWeight <= FW_LIGHT )
432 return WEIGHT_LIGHT;
433 else if ( nWeight < FW_MEDIUM )
434 return WEIGHT_NORMAL;
435 else if ( nWeight == FW_MEDIUM )
436 return WEIGHT_MEDIUM;
437 else if ( nWeight <= FW_SEMIBOLD )
438 return WEIGHT_SEMIBOLD;
439 else if ( nWeight <= FW_BOLD )
440 return WEIGHT_BOLD;
441 else if ( nWeight <= FW_ULTRABOLD )
442 return WEIGHT_ULTRABOLD;
443 else
444 return WEIGHT_BLACK;
447 // -----------------------------------------------------------------------
449 static int ImplWeightToWin( FontWeight eWeight )
451 switch ( eWeight )
453 case WEIGHT_THIN:
454 return FW_THIN;
456 case WEIGHT_ULTRALIGHT:
457 return FW_ULTRALIGHT;
459 case WEIGHT_LIGHT:
460 return FW_LIGHT;
462 case WEIGHT_SEMILIGHT:
463 case WEIGHT_NORMAL:
464 return FW_NORMAL;
466 case WEIGHT_MEDIUM:
467 return FW_MEDIUM;
469 case WEIGHT_SEMIBOLD:
470 return FW_SEMIBOLD;
472 case WEIGHT_BOLD:
473 return FW_BOLD;
475 case WEIGHT_ULTRABOLD:
476 return FW_ULTRABOLD;
478 case WEIGHT_BLACK:
479 return FW_BLACK;
481 default:
482 break;
485 return 0;
488 // -----------------------------------------------------------------------
490 inline FontPitch ImplLogPitchToSal( BYTE nPitch )
492 if ( nPitch & FIXED_PITCH )
493 return PITCH_FIXED;
494 else
495 return PITCH_VARIABLE;
498 // -----------------------------------------------------------------------
500 inline FontPitch ImplMetricPitchToSal( BYTE nPitch )
502 // Sausaecke bei MS !! siehe NT Hilfe
503 if ( !(nPitch & TMPF_FIXED_PITCH) )
504 return PITCH_FIXED;
505 else
506 return PITCH_VARIABLE;
509 // -----------------------------------------------------------------------
511 inline BYTE ImplPitchToWin( FontPitch ePitch )
513 if ( ePitch == PITCH_FIXED )
514 return FIXED_PITCH;
515 else if ( ePitch == PITCH_VARIABLE )
516 return VARIABLE_PITCH;
517 else
518 return DEFAULT_PITCH;
521 // -----------------------------------------------------------------------
523 static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXA& rEnumFont,
524 const NEWTEXTMETRICA& rMetric, DWORD nFontType )
526 ImplDevFontAttributes aDFA;
528 const LOGFONTA rLogFont = rEnumFont.elfLogFont;
530 // get font face attributes
531 aDFA.meFamily = ImplFamilyToSal( rLogFont.lfPitchAndFamily );
532 aDFA.meWidthType = WIDTH_DONTKNOW;
533 aDFA.meWeight = ImplWeightToSal( rLogFont.lfWeight );
534 aDFA.meItalic = (rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE;
535 aDFA.mePitch = ImplLogPitchToSal( rLogFont.lfPitchAndFamily );
536 aDFA.mbSymbolFlag = (rLogFont.lfCharSet == SYMBOL_CHARSET);
538 // get the font face name
539 aDFA.maName = ImplSalGetUniString( rLogFont.lfFaceName );
541 // use the face's style name only if it looks reasonable
542 const char* pStyleName = (const char*)rEnumFont.elfStyle;
543 const char* pEnd = pStyleName + sizeof( rEnumFont.elfStyle );
544 const char* p = pStyleName;
545 for(; *p && (p < pEnd); ++p )
546 if( (0x00 < *p) && (*p < 0x20) )
547 break;
548 if( p < pEnd )
549 aDFA.maStyleName = ImplSalGetUniString( pStyleName );
551 // get device specific font attributes
552 aDFA.mbOrientation = (nFontType & RASTER_FONTTYPE) == 0;
553 aDFA.mbDevice = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
555 aDFA.mbEmbeddable = false;
556 aDFA.mbSubsettable = false;
557 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
558 || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
559 aDFA.mbSubsettable = true;
560 else if( 0 != (rMetric.tmPitchAndFamily & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
561 aDFA.mbEmbeddable = true;
563 // heuristics for font quality
564 // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
565 // - subsetting > embedding > none
566 aDFA.mnQuality = 0;
567 if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
568 aDFA.mnQuality += 50;
569 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
570 aDFA.mnQuality += 10;
571 if( aDFA.mbSubsettable )
572 aDFA.mnQuality += 200;
573 else if( aDFA.mbEmbeddable )
574 aDFA.mnQuality += 100;
576 // #i38665# prefer Type1 versions of the standard postscript fonts
577 if( aDFA.mbEmbeddable )
579 if( aDFA.maName.EqualsAscii( "AvantGarde" )
580 || aDFA.maName.EqualsAscii( "Bookman" )
581 || aDFA.maName.EqualsAscii( "Courier" )
582 || aDFA.maName.EqualsAscii( "Helvetica" )
583 || aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
584 || aDFA.maName.EqualsAscii( "Palatino" )
585 || aDFA.maName.EqualsAscii( "Symbol" )
586 || aDFA.maName.EqualsAscii( "Times" )
587 || aDFA.maName.EqualsAscii( "ZapfChancery" )
588 || aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
589 aDFA.mnQuality += 500;
592 aDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW;
593 aDFA.meAntiAlias = ANTIALIAS_DONTKNOW;
595 // TODO: add alias names
597 return aDFA;
600 // -----------------------------------------------------------------------
602 static ImplDevFontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXW& rEnumFont,
603 const NEWTEXTMETRICW& rMetric, DWORD nFontType )
605 ImplDevFontAttributes aDFA;
607 const LOGFONTW rLogFont = rEnumFont.elfLogFont;
609 // get font face attributes
610 aDFA.meFamily = ImplFamilyToSal( rLogFont.lfPitchAndFamily );
611 aDFA.meWidthType = WIDTH_DONTKNOW;
612 aDFA.meWeight = ImplWeightToSal( rLogFont.lfWeight );
613 aDFA.meItalic = (rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE;
614 aDFA.mePitch = ImplLogPitchToSal( rLogFont.lfPitchAndFamily );
615 aDFA.mbSymbolFlag = (rLogFont.lfCharSet == SYMBOL_CHARSET);
617 // get the font face name
618 aDFA.maName = reinterpret_cast<const sal_Unicode*>(rLogFont.lfFaceName);
620 // use the face's style name only if it looks reasonable
621 const wchar_t* pStyleName = rEnumFont.elfStyle;
622 const wchar_t* pEnd = pStyleName + sizeof(rEnumFont.elfStyle)/sizeof(*rEnumFont.elfStyle);
623 const wchar_t* p = pStyleName;
624 for(; *p && (p < pEnd); ++p )
625 if( *p < 0x0020 )
626 break;
627 if( p < pEnd )
628 aDFA.maStyleName = reinterpret_cast<const sal_Unicode*>(pStyleName);
630 // get device specific font attributes
631 aDFA.mbOrientation = (nFontType & RASTER_FONTTYPE) == 0;
632 aDFA.mbDevice = (rMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
634 aDFA.mbEmbeddable = false;
635 aDFA.mbSubsettable = false;
636 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
637 || 0 != (rMetric.tmPitchAndFamily & TMPF_TRUETYPE))
638 aDFA.mbSubsettable = true;
639 else if( 0 != (rMetric.tmPitchAndFamily & NTM_TYPE1) ) // TODO: implement subsetting for type1 too
640 aDFA.mbEmbeddable = true;
642 // heuristics for font quality
643 // - standard-type1 > opentypeTT > truetype > non-standard-type1 > raster
644 // - subsetting > embedding > none
645 aDFA.mnQuality = 0;
646 if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
647 aDFA.mnQuality += 50;
648 if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
649 aDFA.mnQuality += 10;
650 if( aDFA.mbSubsettable )
651 aDFA.mnQuality += 200;
652 else if( aDFA.mbEmbeddable )
653 aDFA.mnQuality += 100;
655 // #i38665# prefer Type1 versions of the standard postscript fonts
656 if( aDFA.mbEmbeddable )
658 if( aDFA.maName.EqualsAscii( "AvantGarde" )
659 || aDFA.maName.EqualsAscii( "Bookman" )
660 || aDFA.maName.EqualsAscii( "Courier" )
661 || aDFA.maName.EqualsAscii( "Helvetica" )
662 || aDFA.maName.EqualsAscii( "NewCenturySchlbk" )
663 || aDFA.maName.EqualsAscii( "Palatino" )
664 || aDFA.maName.EqualsAscii( "Symbol" )
665 || aDFA.maName.EqualsAscii( "Times" )
666 || aDFA.maName.EqualsAscii( "ZapfChancery" )
667 || aDFA.maName.EqualsAscii( "ZapfDingbats" ) )
668 aDFA.mnQuality += 500;
671 aDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW;
672 aDFA.meAntiAlias = ANTIALIAS_DONTKNOW;
674 // TODO: add alias names
675 return aDFA;
678 // -----------------------------------------------------------------------
680 static ImplWinFontData* ImplLogMetricToDevFontDataA( const ENUMLOGFONTEXA* pLogFont,
681 const NEWTEXTMETRICA* pMetric,
682 DWORD nFontType )
684 int nHeight = 0;
685 if ( nFontType & RASTER_FONTTYPE )
686 nHeight = pMetric->tmHeight - pMetric->tmInternalLeading;
688 ImplWinFontData* pData = new ImplWinFontData(
689 WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType),
690 nHeight,
691 pLogFont->elfLogFont.lfCharSet,
692 pMetric->tmPitchAndFamily );
694 return pData;
697 // -----------------------------------------------------------------------
699 static ImplWinFontData* ImplLogMetricToDevFontDataW( const ENUMLOGFONTEXW* pLogFont,
700 const NEWTEXTMETRICW* pMetric,
701 DWORD nFontType )
703 int nHeight = 0;
704 if ( nFontType & RASTER_FONTTYPE )
705 nHeight = pMetric->tmHeight - pMetric->tmInternalLeading;
707 ImplWinFontData* pData = new ImplWinFontData(
708 WinFont2DevFontAttributes(*pLogFont, *pMetric, nFontType),
709 nHeight,
710 pLogFont->elfLogFont.lfCharSet,
711 pMetric->tmPitchAndFamily );
713 return pData;
716 // -----------------------------------------------------------------------
718 void ImplSalLogFontToFontA( HDC hDC, const LOGFONTA& rLogFont, Font& rFont )
720 String aFontName( ImplSalGetUniString( rLogFont.lfFaceName ) );
721 if ( aFontName.Len() )
723 rFont.SetName( aFontName );
724 rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) );
725 rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) );
726 rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) );
727 rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) );
729 long nFontHeight = rLogFont.lfHeight;
730 if ( nFontHeight < 0 )
731 nFontHeight = -nFontHeight;
732 long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
733 if( !nDPIY )
734 nDPIY = 600;
735 nFontHeight *= 72;
736 nFontHeight += nDPIY/2;
737 nFontHeight /= nDPIY;
738 rFont.SetSize( Size( 0, nFontHeight ) );
739 rFont.SetOrientation( (short)rLogFont.lfEscapement );
740 if ( rLogFont.lfItalic )
741 rFont.SetItalic( ITALIC_NORMAL );
742 else
743 rFont.SetItalic( ITALIC_NONE );
744 if ( rLogFont.lfUnderline )
745 rFont.SetUnderline( UNDERLINE_SINGLE );
746 else
747 rFont.SetUnderline( UNDERLINE_NONE );
748 if ( rLogFont.lfStrikeOut )
749 rFont.SetStrikeout( STRIKEOUT_SINGLE );
750 else
751 rFont.SetStrikeout( STRIKEOUT_NONE );
755 // -----------------------------------------------------------------------
757 void ImplSalLogFontToFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont )
759 XubString aFontName( reinterpret_cast<const xub_Unicode*>(rLogFont.lfFaceName) );
760 if ( aFontName.Len() )
762 rFont.SetName( aFontName );
763 rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) );
764 rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) );
765 rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) );
766 rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) );
768 long nFontHeight = rLogFont.lfHeight;
769 if ( nFontHeight < 0 )
770 nFontHeight = -nFontHeight;
771 long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
772 if( !nDPIY )
773 nDPIY = 600;
774 nFontHeight *= 72;
775 nFontHeight += nDPIY/2;
776 nFontHeight /= nDPIY;
777 rFont.SetSize( Size( 0, nFontHeight ) );
778 rFont.SetOrientation( (short)rLogFont.lfEscapement );
779 if ( rLogFont.lfItalic )
780 rFont.SetItalic( ITALIC_NORMAL );
781 else
782 rFont.SetItalic( ITALIC_NONE );
783 if ( rLogFont.lfUnderline )
784 rFont.SetUnderline( UNDERLINE_SINGLE );
785 else
786 rFont.SetUnderline( UNDERLINE_NONE );
787 if ( rLogFont.lfStrikeOut )
788 rFont.SetStrikeout( STRIKEOUT_SINGLE );
789 else
790 rFont.SetStrikeout( STRIKEOUT_NONE );
794 // =======================================================================
796 ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes& rDFS,
797 int nHeight, WIN_BYTE eWinCharSet, WIN_BYTE nPitchAndFamily )
798 : ImplFontData( rDFS, 0 ),
799 meWinCharSet( eWinCharSet ),
800 mnPitchAndFamily( nPitchAndFamily ),
801 mpFontCharSets( NULL ),
802 mpUnicodeMap( NULL ),
803 mbGsubRead( false ),
804 mbDisableGlyphApi( false ),
805 mbHasKoreanRange( false ),
806 mbHasCJKSupport( false ),
807 #ifdef ENABLE_GRAPHITE
808 mbHasGraphiteSupport( false ),
809 #endif
810 mbHasArabicSupport ( false ),
811 mbAliasSymbolsLow( false ),
812 mbAliasSymbolsHigh( false ),
813 mnId( 0 ),
814 mpEncodingVector( NULL )
816 SetBitmapSize( 0, nHeight );
818 if( eWinCharSet == SYMBOL_CHARSET )
820 if( (nPitchAndFamily & TMPF_TRUETYPE) != 0 )
822 // truetype fonts need their symbols as U+F0xx
823 mbAliasSymbolsHigh = true;
825 else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_DEVICE))
826 == (TMPF_VECTOR|TMPF_DEVICE) )
828 // scalable device fonts (e.g. builtin printer fonts)
829 // need their symbols as U+00xx
830 mbAliasSymbolsLow = true;
832 else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) == 0 )
834 // bitmap fonts need their symbols as U+F0xx
835 mbAliasSymbolsHigh = true;
840 // -----------------------------------------------------------------------
842 ImplWinFontData::~ImplWinFontData()
844 delete[] mpFontCharSets;
846 if( mpUnicodeMap )
847 mpUnicodeMap->DeReference();
848 delete mpEncodingVector;
851 // -----------------------------------------------------------------------
853 sal_IntPtr ImplWinFontData::GetFontId() const
855 return mnId;
858 // -----------------------------------------------------------------------
860 void ImplWinFontData::UpdateFromHDC( HDC hDC ) const
862 // short circuit if already initialized
863 if( mpUnicodeMap != NULL )
864 return;
866 ReadCmapTable( hDC );
867 ReadOs2Table( hDC );
868 #ifdef ENABLE_GRAPHITE
869 static const char* pDisableGraphiteText = getenv( "SAL_DISABLE_GRAPHITE" );
870 if( !pDisableGraphiteText || (pDisableGraphiteText[0] == '0') )
872 mbHasGraphiteSupport = gr::WinFont::FontHasGraphiteTables(hDC);
874 #endif
876 // even if the font works some fonts have problems with the glyph API
877 // => the heuristic below tries to figure out which fonts have the problem
878 TEXTMETRICA aTextMetric;
879 if( ::GetTextMetricsA( hDC, &aTextMetric ) )
880 if( !(aTextMetric.tmPitchAndFamily & TMPF_TRUETYPE)
881 || (aTextMetric.tmPitchAndFamily & TMPF_DEVICE) )
882 mbDisableGlyphApi = true;
884 #if 0
885 // #110548# more important than #107885# => TODO: better solution
886 DWORD nFLI = GetFontLanguageInfo( hDC );
887 if( 0 == (nFLI & GCP_GLYPHSHAPE) )
888 mbDisableGlyphApi = true;
889 #endif
892 // -----------------------------------------------------------------------
894 bool ImplWinFontData::HasGSUBstitutions( HDC hDC ) const
896 if( !mbGsubRead )
897 ReadGsubTable( hDC );
898 return !maGsubTable.empty();
901 // -----------------------------------------------------------------------
903 bool ImplWinFontData::IsGSUBstituted( sal_UCS4 cChar ) const
905 return( maGsubTable.find( cChar ) != maGsubTable.end() );
908 // -----------------------------------------------------------------------
910 ImplFontCharMap* ImplWinFontData::GetImplFontCharMap() const
912 mpUnicodeMap->AddReference();
913 return mpUnicodeMap;
916 // -----------------------------------------------------------------------
918 static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
919 static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);}
920 //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));}
921 static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); }
923 void ImplWinFontData::ReadOs2Table( HDC hDC ) const
925 const DWORD Os2Tag = CalcTag( "OS/2" );
926 DWORD nLength = ::GetFontData( hDC, Os2Tag, 0, NULL, 0 );
927 if( (nLength == GDI_ERROR) || !nLength )
928 return;
929 std::vector<unsigned char> aOS2map( nLength );
930 unsigned char* pOS2map = &aOS2map[0];
931 ::GetFontData( hDC, Os2Tag, 0, pOS2map, nLength );
932 sal_uInt32 nVersion = GetUShort( pOS2map );
933 if ( nVersion >= 0x0001 && nLength >= 58 )
935 // We need at least version 0x0001 (TrueType rev 1.66)
936 // to have access to the needed struct members.
937 sal_uInt32 ulUnicodeRange1 = GetUInt( pOS2map + 42 );
938 sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 );
939 #if 0
940 sal_uInt32 ulUnicodeRange3 = GetUInt( pOS2map + 50 );
941 sal_uInt32 ulUnicodeRange4 = GetUInt( pOS2map + 54 );
942 #endif
944 // Check for CJK capabilities of the current font
945 mbHasCJKSupport = (ulUnicodeRange2 & 0x2DF00000);
946 mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000)
947 | (ulUnicodeRange2 & 0x01100000);
948 mbHasArabicSupport = (ulUnicodeRange1 & 0x00002000);
952 // -----------------------------------------------------------------------
954 void ImplWinFontData::ReadGsubTable( HDC hDC ) const
956 mbGsubRead = true;
958 // check the existence of a GSUB table
959 const DWORD GsubTag = CalcTag( "GSUB" );
960 DWORD nRC = ::GetFontData( hDC, GsubTag, 0, NULL, 0 );
961 if( (nRC == GDI_ERROR) || !nRC )
962 return;
964 // parse the GSUB table through sft
965 // TODO: parse it directly
967 // sft needs the full font file data => get it
968 const RawFontData aRawFontData( hDC );
969 if( !aRawFontData.get() )
970 return;
972 // open font file
973 sal_uInt32 nFaceNum = 0;
974 if( !*aRawFontData.get() ) // TTC candidate
975 nFaceNum = ~0U; // indicate "TTC font extracts only"
977 TrueTypeFont* pTTFont = NULL;
978 ::OpenTTFontBuffer( (void*)aRawFontData.get(), aRawFontData.size(), nFaceNum, &pTTFont );
979 if( !pTTFont )
980 return;
982 // add vertically substituted characters to list
983 static const sal_Unicode aGSUBCandidates[] = {
984 0x0020, 0x0080, // ASCII
985 0x2000, 0x2600, // misc
986 0x3000, 0x3100, // CJK punctutation
987 0x3300, 0x3400, // squared words
988 0xFF00, 0xFFF0, // halfwidth|fullwidth forms
989 0 };
991 for( const sal_Unicode* pPair = aGSUBCandidates; *pPair; pPair += 2 )
992 for( sal_Unicode cChar = pPair[0]; cChar < pPair[1]; ++cChar )
993 if( ::MapChar( pTTFont, cChar, 0 ) != ::MapChar( pTTFont, cChar, 1 ) )
994 maGsubTable.insert( cChar ); // insert GSUBbed unicodes
996 CloseTTFont( pTTFont );
999 // -----------------------------------------------------------------------
1001 void ImplWinFontData::ReadCmapTable( HDC hDC ) const
1003 if( mpUnicodeMap != NULL )
1004 return;
1006 bool bIsSymbolFont = (meWinCharSet == SYMBOL_CHARSET);
1007 // get the CMAP table from the font which is selected into the DC
1008 const DWORD nCmapTag = CalcTag( "cmap" );
1009 const RawFontData aRawFontData( hDC, nCmapTag );
1010 // parse the CMAP table if available
1011 if( aRawFontData.get() ) {
1012 CmapResult aResult;
1013 ParseCMAP( aRawFontData.get(), aRawFontData.size(), aResult );
1014 mbDisableGlyphApi |= aResult.mbRecoded;
1015 aResult.mbSymbolic = bIsSymbolFont;
1016 if( aResult.mnRangeCount > 0 )
1017 mpUnicodeMap = new ImplFontCharMap( aResult );
1020 if( !mpUnicodeMap )
1021 mpUnicodeMap = ImplFontCharMap::GetDefaultMap( bIsSymbolFont );
1024 // =======================================================================
1026 void WinSalGraphics::SetTextColor( SalColor nSalColor )
1028 COLORREF aCol = PALETTERGB( SALCOLOR_RED( nSalColor ),
1029 SALCOLOR_GREEN( nSalColor ),
1030 SALCOLOR_BLUE( nSalColor ) );
1032 if( !mbPrinter &&
1033 GetSalData()->mhDitherPal &&
1034 ImplIsSysColorEntry( nSalColor ) )
1036 aCol = PALRGB_TO_RGB( aCol );
1039 ::SetTextColor( mhDC, aCol );
1042 // -----------------------------------------------------------------------
1044 int CALLBACK SalEnumQueryFontProcExW( const ENUMLOGFONTEXW*,
1045 const NEWTEXTMETRICEXW*,
1046 DWORD, LPARAM lParam )
1048 *((bool*)(void*)lParam) = true;
1049 return 0;
1052 // -----------------------------------------------------------------------
1054 int CALLBACK SalEnumQueryFontProcExA( const ENUMLOGFONTEXA*,
1055 const NEWTEXTMETRICEXA*,
1056 DWORD, LPARAM lParam )
1058 *((bool*)(void*)lParam) = true;
1059 return 0;
1062 // -----------------------------------------------------------------------
1064 bool ImplIsFontAvailable( HDC hDC, const UniString& rName )
1066 bool bAvailable = false;
1068 if ( aSalShlData.mbWNT )
1070 // Test, if Font available
1071 LOGFONTW aLogFont;
1072 memset( &aLogFont, 0, sizeof( aLogFont ) );
1073 aLogFont.lfCharSet = DEFAULT_CHARSET;
1075 UINT nNameLen = rName.Len();
1076 if ( nNameLen > (sizeof( aLogFont.lfFaceName )/sizeof( wchar_t ))-1 )
1077 nNameLen = (sizeof( aLogFont.lfFaceName )/sizeof( wchar_t ))-1;
1078 memcpy( aLogFont.lfFaceName, rName.GetBuffer(), nNameLen*sizeof( wchar_t ) );
1079 aLogFont.lfFaceName[nNameLen] = 0;
1081 EnumFontFamiliesExW( hDC, &aLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW,
1082 (LPARAM)(void*)&bAvailable, 0 );
1084 else
1086 ByteString aTemp = ImplSalGetWinAnsiString( rName );
1088 // Test, if Font available
1089 LOGFONTA aLogFont;
1090 memset( &aLogFont, 0, sizeof( aLogFont ) );
1091 aLogFont.lfCharSet = DEFAULT_CHARSET;
1093 UINT nNameLen = aTemp.Len();
1094 if ( nNameLen > sizeof( aLogFont.lfFaceName )-1 )
1095 nNameLen = sizeof( aLogFont.lfFaceName )-1;
1096 memcpy( aLogFont.lfFaceName, aTemp.GetBuffer(), nNameLen );
1097 aLogFont.lfFaceName[nNameLen] = 0;
1099 EnumFontFamiliesExA( hDC, &aLogFont, (FONTENUMPROCA)SalEnumQueryFontProcExA,
1100 (LPARAM)(void*)&bAvailable, 0 );
1103 return bAvailable;
1106 // -----------------------------------------------------------------------
1108 void ImplGetLogFontFromFontSelect( HDC hDC,
1109 const ImplFontSelectData* pFont,
1110 LOGFONTW& rLogFont,
1111 bool /*bTestVerticalAvail*/ )
1113 UniString aName;
1114 if ( pFont->mpFontData )
1115 aName = pFont->mpFontData->maName;
1116 else
1117 aName = pFont->maName.GetToken( 0 );
1119 UINT nNameLen = aName.Len();
1120 if ( nNameLen > (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1 )
1121 nNameLen = (sizeof( rLogFont.lfFaceName )/sizeof( wchar_t ))-1;
1122 memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen*sizeof( wchar_t ) );
1123 rLogFont.lfFaceName[nNameLen] = 0;
1125 if( !pFont->mpFontData )
1127 rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET;
1128 rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->mePitch )
1129 | ImplFamilyToWin( pFont->meFamily );
1131 else
1133 const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData );
1134 rLogFont.lfCharSet = pWinFontData->GetCharSet();
1135 rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily();
1138 rLogFont.lfWeight = ImplWeightToWin( pFont->meWeight );
1139 rLogFont.lfHeight = (LONG)-pFont->mnHeight;
1140 rLogFont.lfWidth = (LONG)pFont->mnWidth;
1141 rLogFont.lfUnderline = 0;
1142 rLogFont.lfStrikeOut = 0;
1143 rLogFont.lfItalic = (pFont->meItalic) != ITALIC_NONE;
1144 rLogFont.lfEscapement = pFont->mnOrientation;
1145 rLogFont.lfOrientation = rLogFont.lfEscapement;
1146 rLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1147 rLogFont.lfQuality = DEFAULT_QUALITY;
1148 rLogFont.lfOutPrecision = OUT_TT_PRECIS;
1149 if ( pFont->mnOrientation )
1150 rLogFont.lfClipPrecision |= CLIP_LH_ANGLES;
1152 // disable antialiasing if requested
1153 if ( pFont->mbNonAntialiased )
1154 rLogFont.lfQuality = NONANTIALIASED_QUALITY;
1156 // select vertical mode if requested and available
1157 if( pFont->mbVertical && nNameLen )
1159 // vertical fonts start with an '@'
1160 memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0],
1161 sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) );
1162 rLogFont.lfFaceName[0] = '@';
1164 // check availability of vertical mode for this font
1165 bool bAvailable = false;
1166 EnumFontFamiliesExW( hDC, &rLogFont, (FONTENUMPROCW)SalEnumQueryFontProcExW,
1167 (LPARAM)&bAvailable, 0 );
1169 if( !bAvailable )
1171 // restore non-vertical name if not vertical mode isn't available
1172 memcpy( &rLogFont.lfFaceName[0], aName.GetBuffer(), nNameLen*sizeof(wchar_t) );
1173 if( nNameLen < LF_FACESIZE )
1174 rLogFont.lfFaceName[nNameLen] = '\0';
1179 // -----------------------------------------------------------------------
1181 static void ImplGetLogFontFromFontSelect( HDC hDC,
1182 const ImplFontSelectData* pFont,
1183 LOGFONTA& rLogFont,
1184 bool /*bTestVerticalAvail*/ )
1186 ByteString aName;
1187 if( pFont->mpFontData )
1188 aName = ImplSalGetWinAnsiString( pFont->mpFontData->maName );
1189 else
1190 aName = ImplSalGetWinAnsiString( pFont->maName.GetToken( 0 ) );
1192 int nNameLen = aName.Len();
1193 if( nNameLen > LF_FACESIZE )
1194 nNameLen = LF_FACESIZE;
1195 memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen );
1196 if( nNameLen < LF_FACESIZE )
1197 rLogFont.lfFaceName[nNameLen] = '\0';
1199 if( !pFont->mpFontData )
1201 rLogFont.lfCharSet = pFont->IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET;
1202 rLogFont.lfPitchAndFamily = ImplPitchToWin( pFont->mePitch )
1203 | ImplFamilyToWin( pFont->meFamily );
1205 else
1207 const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>( pFont->mpFontData );
1208 rLogFont.lfCharSet = pWinFontData->GetCharSet();
1209 rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily();
1212 rLogFont.lfWeight = ImplWeightToWin( pFont->meWeight );
1213 rLogFont.lfHeight = (LONG)-pFont->mnHeight;
1214 rLogFont.lfWidth = (LONG)pFont->mnWidth;
1215 rLogFont.lfUnderline = 0;
1216 rLogFont.lfStrikeOut = 0;
1217 rLogFont.lfItalic = (pFont->meItalic) != ITALIC_NONE;
1218 rLogFont.lfEscapement = pFont->mnOrientation;
1219 rLogFont.lfOrientation = rLogFont.lfEscapement; // ignored by W98
1220 rLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1221 rLogFont.lfQuality = DEFAULT_QUALITY;
1222 rLogFont.lfOutPrecision = OUT_TT_PRECIS;
1223 if( pFont->mnOrientation )
1224 rLogFont.lfClipPrecision |= CLIP_LH_ANGLES;
1226 // disable antialiasing if requested
1227 if( pFont->mbNonAntialiased )
1228 rLogFont.lfQuality = NONANTIALIASED_QUALITY;
1230 // select vertical mode if requested and available
1231 if( pFont->mbVertical && nNameLen )
1233 // vertical fonts start with an '@'
1234 memmove( &rLogFont.lfFaceName[1], &rLogFont.lfFaceName[0],
1235 sizeof(rLogFont.lfFaceName)-sizeof(rLogFont.lfFaceName[0]) );
1236 rLogFont.lfFaceName[0] = '@';
1238 // check availability of vertical mode for this font
1239 bool bAvailable = false;
1240 EnumFontFamiliesExA( hDC, &rLogFont, (FONTENUMPROCA)SalEnumQueryFontProcExA,
1241 (LPARAM)&bAvailable, 0 );
1243 if( !bAvailable )
1245 // restore non-vertical name if vertical mode is not supported
1246 memcpy( rLogFont.lfFaceName, aName.GetBuffer(), nNameLen );
1247 if( nNameLen < LF_FACESIZE )
1248 rLogFont.lfFaceName[nNameLen] = '\0';
1253 // -----------------------------------------------------------------------
1255 HFONT WinSalGraphics::ImplDoSetFont( ImplFontSelectData* i_pFont, float& o_rFontScale, HFONT& o_rOldFont )
1257 HFONT hNewFont = 0;
1259 HDC hdcScreen = 0;
1260 if( mbVirDev )
1261 // only required for virtual devices, see below for details
1262 hdcScreen = GetDC(0);
1264 if( aSalShlData.mbWNT )
1266 LOGFONTW aLogFont;
1267 ImplGetLogFontFromFontSelect( mhDC, i_pFont, aLogFont, true );
1269 // on the display we prefer Courier New when Courier is a
1270 // bitmap only font and we need to stretch or rotate it
1271 if( mbScreen
1272 && (i_pFont->mnWidth != 0
1273 || i_pFont->mnOrientation != 0
1274 || i_pFont->mpFontData == NULL
1275 || (i_pFont->mpFontData->GetHeight() != i_pFont->mnHeight))
1276 && !bImplSalCourierScalable
1277 && bImplSalCourierNew
1278 && (ImplSalWICompareAscii( aLogFont.lfFaceName, "Courier" ) == 0) )
1279 lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 );
1281 // limit font requests to MAXFONTHEIGHT
1282 // TODO: share MAXFONTHEIGHT font instance
1283 if( -aLogFont.lfHeight <= MAXFONTHEIGHT )
1284 o_rFontScale = 1.0;
1285 else
1287 o_rFontScale = -aLogFont.lfHeight / (float)MAXFONTHEIGHT;
1288 aLogFont.lfHeight = -MAXFONTHEIGHT;
1289 aLogFont.lfWidth = static_cast<LONG>( aLogFont.lfWidth / o_rFontScale );
1292 hNewFont = ::CreateFontIndirectW( &aLogFont );
1293 if( hdcScreen )
1295 // select font into screen hdc first to get an antialiased font
1296 // see knowledge base article 305290:
1297 // "PRB: Fonts Not Drawn Antialiased on Device Context for DirectDraw Surface"
1298 SelectFont( hdcScreen, SelectFont( hdcScreen , hNewFont ) );
1300 o_rOldFont = ::SelectFont( mhDC, hNewFont );
1302 TEXTMETRICW aTextMetricW;
1303 if( !::GetTextMetricsW( mhDC, &aTextMetricW ) )
1305 // the selected font doesn't work => try a replacement
1306 // TODO: use its font fallback instead
1307 lstrcpynW( aLogFont.lfFaceName, L"Courier New", 11 );
1308 aLogFont.lfPitchAndFamily = FIXED_PITCH;
1309 HFONT hNewFont2 = CreateFontIndirectW( &aLogFont );
1310 SelectFont( mhDC, hNewFont2 );
1311 DeleteFont( hNewFont );
1312 hNewFont = hNewFont2;
1315 else
1317 if( !mpLogFont )
1318 // mpLogFont is needed for getting the kerning pairs
1319 // TODO: get them from somewhere else
1320 mpLogFont = new LOGFONTA;
1321 LOGFONTA& aLogFont = *mpLogFont;
1322 ImplGetLogFontFromFontSelect( mhDC, i_pFont, aLogFont, true );
1324 // on the display we prefer Courier New when Courier is a
1325 // bitmap only font and we need to stretch or rotate it
1326 if( mbScreen
1327 && (i_pFont->mnWidth != 0
1328 || i_pFont->mnOrientation != 0
1329 || i_pFont->mpFontData == NULL
1330 || (i_pFont->mpFontData->GetHeight() != i_pFont->mnHeight))
1331 && !bImplSalCourierScalable
1332 && bImplSalCourierNew
1333 && (stricmp( aLogFont.lfFaceName, "Courier" ) == 0) )
1334 strncpy( aLogFont.lfFaceName, "Courier New", 11 );
1336 // limit font requests to MAXFONTHEIGHT to work around driver problems
1337 // TODO: share MAXFONTHEIGHT font instance
1338 if( -aLogFont.lfHeight <= MAXFONTHEIGHT )
1339 o_rFontScale = 1.0;
1340 else
1342 o_rFontScale = -aLogFont.lfHeight / (float)MAXFONTHEIGHT;
1343 aLogFont.lfHeight = -MAXFONTHEIGHT;
1344 aLogFont.lfWidth = static_cast<LONG>( aLogFont.lfWidth / o_rFontScale );
1347 hNewFont = ::CreateFontIndirectA( &aLogFont );
1348 if( hdcScreen )
1350 // select font into screen hdc first to get an antialiased font
1351 // see knowledge base article 305290:
1352 // "PRB: Fonts Not Drawn Antialiased on Device Context for DirectDraw Surface"
1353 ::SelectFont( hdcScreen, ::SelectFont( hdcScreen , hNewFont ) );
1355 o_rOldFont = ::SelectFont( mhDC, hNewFont );
1357 TEXTMETRICA aTextMetricA;
1358 // when the font doesn't work try a replacement
1359 if ( !::GetTextMetricsA( mhDC, &aTextMetricA ) )
1361 // the selected font doesn't work => try a replacement
1362 // TODO: use its font fallback instead
1363 LOGFONTA aTempLogFont = aLogFont;
1364 strncpy( aTempLogFont.lfFaceName, "Courier New", 11 );
1365 aTempLogFont.lfPitchAndFamily = FIXED_PITCH;
1366 HFONT hNewFont2 = CreateFontIndirectA( &aTempLogFont );
1367 ::SelectFont( mhDC, hNewFont2 );
1368 ::DeleteFont( hNewFont );
1369 hNewFont = hNewFont2;
1373 if( hdcScreen )
1374 ::ReleaseDC( NULL, hdcScreen );
1376 return hNewFont;
1379 USHORT WinSalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel )
1381 // return early if there is no new font
1382 if( !pFont )
1384 // deselect still active font
1385 if( mhDefFont )
1386 ::SelectFont( mhDC, mhDefFont );
1387 // release no longer referenced font handles
1388 for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
1390 if( mhFonts[i] )
1391 ::DeleteFont( mhFonts[i] );
1392 mhFonts[ i ] = 0;
1394 mhDefFont = 0;
1395 return 0;
1398 DBG_ASSERT( pFont->mpFontData, "WinSalGraphics mpFontData==NULL");
1399 mpWinFontEntry[ nFallbackLevel ] = reinterpret_cast<ImplWinFontEntry*>( pFont->mpFontEntry );
1400 mpWinFontData[ nFallbackLevel ] = static_cast<const ImplWinFontData*>( pFont->mpFontData );
1402 HFONT hOldFont = 0;
1403 HFONT hNewFont = ImplDoSetFont( pFont, mfFontScale, hOldFont );
1405 if( !mhDefFont )
1407 // keep default font
1408 mhDefFont = hOldFont;
1410 else
1412 // release no longer referenced font handles
1413 for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
1415 if( mhFonts[i] )
1417 ::DeleteFont( mhFonts[i] );
1418 mhFonts[i] = 0;
1423 // store new font in correct layer
1424 mhFonts[ nFallbackLevel ] = hNewFont;
1425 // now the font is live => update font face
1426 if( mpWinFontData[ nFallbackLevel ] )
1427 mpWinFontData[ nFallbackLevel ]->UpdateFromHDC( mhDC );
1429 if( !nFallbackLevel )
1431 mbFontKernInit = TRUE;
1432 if ( mpFontKernPairs )
1434 delete[] mpFontKernPairs;
1435 mpFontKernPairs = NULL;
1437 mnFontKernPairCount = 0;
1440 mnFontCharSetCount = 0;
1442 // some printers have higher internal resolution, so their
1443 // text output would be different from what we calculated
1444 // => suggest DrawTextArray to workaround this problem
1445 if ( mbPrinter )
1446 return SAL_SETFONT_USEDRAWTEXTARRAY;
1447 else
1448 return 0;
1451 // -----------------------------------------------------------------------
1453 void WinSalGraphics::GetFontMetric( ImplFontMetricData* pMetric )
1455 if ( aSalShlData.mbWNT )
1457 wchar_t aFaceName[LF_FACESIZE+60];
1458 if( ::GetTextFaceW( mhDC, sizeof(aFaceName)/sizeof(wchar_t), aFaceName ) )
1459 pMetric->maName = reinterpret_cast<const sal_Unicode*>(aFaceName);
1461 else
1463 char aFaceName[LF_FACESIZE+60];
1464 if( ::GetTextFaceA( mhDC, sizeof(aFaceName), aFaceName ) )
1465 pMetric->maName = ImplSalGetUniString( aFaceName );
1468 TEXTMETRICA aWinMetric;
1469 if( !GetTextMetricsA( mhDC, &aWinMetric ) )
1470 return;
1472 // device independent font attributes
1473 pMetric->meFamily = ImplFamilyToSal( aWinMetric.tmPitchAndFamily );;
1474 pMetric->mbSymbolFlag = (aWinMetric.tmCharSet == SYMBOL_CHARSET);
1475 pMetric->meWeight = ImplWeightToSal( aWinMetric.tmWeight );
1476 pMetric->mePitch = ImplMetricPitchToSal( aWinMetric.tmPitchAndFamily );
1477 pMetric->meItalic = aWinMetric.tmItalic ? ITALIC_NORMAL : ITALIC_NONE;
1478 pMetric->mnSlant = 0;
1480 // device dependend font attributes
1481 pMetric->mbDevice = (aWinMetric.tmPitchAndFamily & TMPF_DEVICE) != 0;
1482 pMetric->mbScalableFont = (aWinMetric.tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) != 0;
1483 if( pMetric->mbScalableFont )
1485 // check if there are kern pairs
1486 // TODO: does this work with GPOS kerning?
1487 DWORD nKernPairs = ::GetKerningPairsA( mhDC, 0, NULL );
1488 pMetric->mbKernableFont = (nKernPairs > 0);
1490 else
1492 // bitmap fonts cannot be rotated directly
1493 pMetric->mnOrientation = 0;
1494 // bitmap fonts have no kerning
1495 pMetric->mbKernableFont = false;
1498 // transformation dependend font metrics
1499 pMetric->mnWidth = static_cast<int>( mfFontScale * aWinMetric.tmAveCharWidth );
1500 pMetric->mnIntLeading = static_cast<int>( mfFontScale * aWinMetric.tmInternalLeading );
1501 pMetric->mnExtLeading = static_cast<int>( mfFontScale * aWinMetric.tmExternalLeading );
1502 pMetric->mnAscent = static_cast<int>( mfFontScale * aWinMetric.tmAscent );
1503 pMetric->mnDescent = static_cast<int>( mfFontScale * aWinMetric.tmDescent );
1505 // #107888# improved metric compatibility for Asian fonts...
1506 // TODO: assess workaround below for CWS >= extleading
1507 // TODO: evaluate use of aWinMetric.sTypo* members for CJK
1508 if( mpWinFontData[0] && mpWinFontData[0]->SupportsCJK() )
1510 pMetric->mnIntLeading += pMetric->mnExtLeading;
1512 // #109280# The line height for Asian fonts is too small.
1513 // Therefore we add half of the external leading to the
1514 // ascent, the other half is added to the descent.
1515 const long nHalfTmpExtLeading = pMetric->mnExtLeading / 2;
1516 const long nOtherHalfTmpExtLeading = pMetric->mnExtLeading - nHalfTmpExtLeading;
1518 // #110641# external leading for Asian fonts.
1519 // The factor 0.3 has been confirmed with experiments.
1520 long nCJKExtLeading = static_cast<long>(0.30 * (pMetric->mnAscent + pMetric->mnDescent));
1521 nCJKExtLeading -= pMetric->mnExtLeading;
1522 pMetric->mnExtLeading = (nCJKExtLeading > 0) ? nCJKExtLeading : 0;
1524 pMetric->mnAscent += nHalfTmpExtLeading;
1525 pMetric->mnDescent += nOtherHalfTmpExtLeading;
1527 // #109280# HACK korean only: increase descent for wavelines and impr
1528 if( !aSalShlData.mbWNT )
1529 if( mpWinFontData[0]->SupportsKorean() )
1530 pMetric->mnDescent += pMetric->mnExtLeading;
1533 pMetric->mnMinKashida = GetMinKashidaWidth();
1536 // -----------------------------------------------------------------------
1538 int CALLBACK SalEnumCharSetsProcExA( const ENUMLOGFONTEXA* pLogFont,
1539 const NEWTEXTMETRICEXA* /*pMetric*/,
1540 DWORD /*nFontType*/, LPARAM lParam )
1542 WinSalGraphics* pData = (WinSalGraphics*)lParam;
1543 // Charset already in the list?
1544 for ( BYTE i = 0; i < pData->mnFontCharSetCount; i++ )
1546 if ( pData->mpFontCharSets[i] == pLogFont->elfLogFont.lfCharSet )
1547 return 1;
1549 pData->mpFontCharSets[pData->mnFontCharSetCount] = pLogFont->elfLogFont.lfCharSet;
1550 pData->mnFontCharSetCount++;
1551 return 1;
1554 // -----------------------------------------------------------------------
1556 static void ImplGetAllFontCharSets( WinSalGraphics* pData )
1558 if ( !pData->mpFontCharSets )
1559 pData->mpFontCharSets = new BYTE[256];
1561 LOGFONTA aLogFont;
1562 memset( &aLogFont, 0, sizeof( aLogFont ) );
1563 aLogFont.lfCharSet = DEFAULT_CHARSET;
1564 GetTextFaceA( pData->mhDC, sizeof( aLogFont.lfFaceName ), aLogFont.lfFaceName );
1565 EnumFontFamiliesExA( pData->mhDC, &aLogFont, (FONTENUMPROCA)SalEnumCharSetsProcExA,
1566 (LPARAM)(void*)pData, 0 );
1569 // -----------------------------------------------------------------------
1571 static void ImplAddKerningPairs( WinSalGraphics* pData )
1573 ULONG nPairs = ::GetKerningPairsA( pData->mhDC, 0, NULL );
1574 if ( !nPairs )
1575 return;
1577 CHARSETINFO aInfo;
1578 if ( !TranslateCharsetInfo( (DWORD*)(ULONG)GetTextCharset( pData->mhDC ), &aInfo, TCI_SRCCHARSET ) )
1579 return;
1581 if ( !pData->mpFontKernPairs )
1582 pData->mpFontKernPairs = new KERNINGPAIR[nPairs];
1583 else
1585 KERNINGPAIR* pOldPairs = pData->mpFontKernPairs;
1586 pData->mpFontKernPairs = new KERNINGPAIR[nPairs+pData->mnFontKernPairCount];
1587 memcpy( pData->mpFontKernPairs, pOldPairs,
1588 pData->mnFontKernPairCount*sizeof( KERNINGPAIR ) );
1589 delete[] pOldPairs;
1592 UINT nCP = aInfo.ciACP;
1593 ULONG nOldPairs = pData->mnFontKernPairCount;
1594 KERNINGPAIR* pTempPair = pData->mpFontKernPairs+pData->mnFontKernPairCount;
1595 nPairs = ::GetKerningPairsA( pData->mhDC, nPairs, pTempPair );
1596 for ( ULONG i = 0; i < nPairs; i++ )
1598 unsigned char aBuf[2];
1599 wchar_t nChar;
1600 int nLen;
1601 BOOL bAdd = TRUE;
1603 // None-ASCII?, then we must convert the char
1604 if ( (pTempPair->wFirst > 125) || (pTempPair->wFirst == 92) )
1606 if ( pTempPair->wFirst < 256 )
1608 aBuf[0] = (unsigned char)pTempPair->wFirst;
1609 nLen = 1;
1611 else
1613 aBuf[0] = (unsigned char)(pTempPair->wFirst >> 8);
1614 aBuf[1] = (unsigned char)(pTempPair->wFirst & 0xFF);
1615 nLen = 2;
1617 if ( MultiByteToWideChar( nCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
1618 (const char*)aBuf, nLen, &nChar, 1 ) )
1619 pTempPair->wFirst = nChar;
1620 else
1621 bAdd = FALSE;
1623 if ( (pTempPair->wSecond > 125) || (pTempPair->wSecond == 92) )
1625 if ( pTempPair->wSecond < 256 )
1627 aBuf[0] = (unsigned char)pTempPair->wSecond;
1628 nLen = 1;
1630 else
1632 aBuf[0] = (unsigned char)(pTempPair->wSecond >> 8);
1633 aBuf[1] = (unsigned char)(pTempPair->wSecond & 0xFF);
1634 nLen = 2;
1636 if ( MultiByteToWideChar( nCP, MB_PRECOMPOSED | MB_USEGLYPHCHARS,
1637 (const char*)aBuf, nLen, &nChar, 1 ) )
1638 pTempPair->wSecond = nChar;
1639 else
1640 bAdd = FALSE;
1643 // TODO: get rid of linear search!
1644 KERNINGPAIR* pTempPair2 = pData->mpFontKernPairs;
1645 for ( ULONG j = 0; j < nOldPairs; j++ )
1647 if ( (pTempPair2->wFirst == pTempPair->wFirst) &&
1648 (pTempPair2->wSecond == pTempPair->wSecond) )
1650 bAdd = FALSE;
1651 break;
1653 pTempPair2++;
1656 if ( bAdd )
1658 KERNINGPAIR* pDestPair = pData->mpFontKernPairs+pData->mnFontKernPairCount;
1659 if ( pDestPair != pTempPair )
1660 memcpy( pDestPair, pTempPair, sizeof( KERNINGPAIR ) );
1661 pData->mnFontKernPairCount++;
1664 pTempPair++;
1668 // -----------------------------------------------------------------------
1670 ULONG WinSalGraphics::GetKernPairs( ULONG nPairs, ImplKernPairData* pKernPairs )
1672 DBG_ASSERT( sizeof( KERNINGPAIR ) == sizeof( ImplKernPairData ),
1673 "WinSalGraphics::GetKernPairs(): KERNINGPAIR != ImplKernPairData" );
1675 if ( mbFontKernInit )
1677 if( mpFontKernPairs )
1679 delete[] mpFontKernPairs;
1680 mpFontKernPairs = NULL;
1682 mnFontKernPairCount = 0;
1684 if ( aSalShlData.mbWNT )
1686 KERNINGPAIR* pPairs = NULL;
1687 int nCount = ::GetKerningPairsW( mhDC, 0, NULL );
1688 if( nCount )
1690 #ifdef GCP_KERN_HACK
1691 pPairs = new KERNINGPAIR[ nCount+1 ];
1692 mpFontKernPairs = pPairs;
1693 mnFontKernPairCount = nCount;
1694 ::GetKerningPairsW( mhDC, nCount, pPairs );
1695 #else // GCP_KERN_HACK
1696 pPairs = pKernPairs;
1697 nCount = (nCount < nPairs) : nCount : nPairs;
1698 ::GetKerningPairsW( mhDC, nCount, pPairs );
1699 return nCount;
1700 #endif // GCP_KERN_HACK
1703 else
1705 if ( !mnFontCharSetCount )
1706 ImplGetAllFontCharSets( this );
1708 if ( mnFontCharSetCount <= 1 )
1709 ImplAddKerningPairs( this );
1710 else
1712 // Query All Kerning Pairs from all possible CharSets
1713 for ( BYTE i = 0; i < mnFontCharSetCount; i++ )
1715 mpLogFont->lfCharSet = mpFontCharSets[i];
1716 HFONT hNewFont = CreateFontIndirectA( mpLogFont );
1717 HFONT hOldFont = SelectFont( mhDC, hNewFont );
1718 ImplAddKerningPairs( this );
1719 SelectFont( mhDC, hOldFont );
1720 DeleteFont( hNewFont );
1725 mbFontKernInit = FALSE;
1727 std::sort( mpFontKernPairs, mpFontKernPairs + mnFontKernPairCount, ImplCmpKernData );
1730 if( !pKernPairs )
1731 return mnFontKernPairCount;
1732 else if( mpFontKernPairs )
1734 if ( nPairs < mnFontKernPairCount )
1735 nPairs = mnFontKernPairCount;
1736 memcpy( pKernPairs, mpFontKernPairs,
1737 nPairs*sizeof( ImplKernPairData ) );
1738 return nPairs;
1741 return 0;
1744 // -----------------------------------------------------------------------
1746 ImplFontCharMap* WinSalGraphics::GetImplFontCharMap() const
1748 if( !mpWinFontData[0] )
1749 return ImplFontCharMap::GetDefaultMap();
1750 return mpWinFontData[0]->GetImplFontCharMap();
1753 // -----------------------------------------------------------------------
1755 int CALLBACK SalEnumFontsProcExA( const ENUMLOGFONTEXA* pLogFont,
1756 const NEWTEXTMETRICEXA* pMetric,
1757 DWORD nFontType, LPARAM lParam )
1759 ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam;
1760 if ( !pInfo->mpName )
1762 // Ignore vertical fonts
1763 if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
1765 if ( !pInfo->mbImplSalCourierNew )
1766 pInfo->mbImplSalCourierNew = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0;
1767 if ( !pInfo->mbImplSalCourierScalable )
1768 pInfo->mbCourier = stricmp( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0;
1769 else
1770 pInfo->mbCourier = FALSE;
1771 String aName( ImplSalGetUniString( pLogFont->elfLogFont.lfFaceName ) );
1772 pInfo->mpName = &aName;
1773 strncpy( pInfo->mpLogFontA->lfFaceName, pLogFont->elfLogFont.lfFaceName, LF_FACESIZE );
1774 pInfo->mpLogFontA->lfCharSet = pLogFont->elfLogFont.lfCharSet;
1775 EnumFontFamiliesExA( pInfo->mhDC, pInfo->mpLogFontA, (FONTENUMPROCA)SalEnumFontsProcExA,
1776 (LPARAM)(void*)pInfo, 0 );
1777 pInfo->mpLogFontA->lfFaceName[0] = '\0';
1778 pInfo->mpLogFontA->lfCharSet = DEFAULT_CHARSET;
1779 pInfo->mpName = NULL;
1780 pInfo->mbCourier = FALSE;
1783 else
1785 // ignore non-scalable non-device font on printer
1786 if( pInfo->mbPrinter )
1787 if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) )
1788 return 1;
1790 ImplWinFontData* pData = ImplLogMetricToDevFontDataA( pLogFont, &(pMetric->ntmTm), nFontType );
1791 pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
1793 // prefer the system character set, so that we get as much as
1794 // possible important characters. In the other case we could only
1795 // display a limited set of characters (#87309#)
1796 if ( pInfo->mnPreferedCharSet == pLogFont->elfLogFont.lfCharSet )
1797 pData->mnQuality += 100;
1799 // knowing Courier to be scalable is nice
1800 if( pInfo->mbCourier )
1801 pInfo->mbImplSalCourierScalable |= pData->IsScalable();
1803 pInfo->mpList->Add( pData );
1806 return 1;
1809 // -----------------------------------------------------------------------
1811 int CALLBACK SalEnumFontsProcExW( const ENUMLOGFONTEXW* pLogFont,
1812 const NEWTEXTMETRICEXW* pMetric,
1813 DWORD nFontType, LPARAM lParam )
1815 ImplEnumInfo* pInfo = (ImplEnumInfo*)(void*)lParam;
1816 if ( !pInfo->mpName )
1818 // Ignore vertical fonts
1819 if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
1821 if ( !pInfo->mbImplSalCourierNew )
1822 pInfo->mbImplSalCourierNew = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier New" ) == 0;
1823 if ( !pInfo->mbImplSalCourierScalable )
1824 pInfo->mbCourier = ImplSalWICompareAscii( pLogFont->elfLogFont.lfFaceName, "Courier" ) == 0;
1825 else
1826 pInfo->mbCourier = FALSE;
1827 String aName( reinterpret_cast<const sal_Unicode*>(pLogFont->elfLogFont.lfFaceName) );
1828 pInfo->mpName = &aName;
1829 memcpy( pInfo->mpLogFontW->lfFaceName, pLogFont->elfLogFont.lfFaceName, (aName.Len()+1)*sizeof( wchar_t ) );
1830 pInfo->mpLogFontW->lfCharSet = pLogFont->elfLogFont.lfCharSet;
1831 EnumFontFamiliesExW( pInfo->mhDC, pInfo->mpLogFontW, (FONTENUMPROCW)SalEnumFontsProcExW,
1832 (LPARAM)(void*)pInfo, 0 );
1833 pInfo->mpLogFontW->lfFaceName[0] = '\0';
1834 pInfo->mpLogFontW->lfCharSet = DEFAULT_CHARSET;
1835 pInfo->mpName = NULL;
1836 pInfo->mbCourier = FALSE;
1839 else
1841 // ignore non-scalable non-device font on printer
1842 if( pInfo->mbPrinter )
1843 if( (nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE) )
1844 return 1;
1846 ImplWinFontData* pData = ImplLogMetricToDevFontDataW( pLogFont, &(pMetric->ntmTm), nFontType );
1847 pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
1849 // knowing Courier to be scalable is nice
1850 if( pInfo->mbCourier )
1851 pInfo->mbImplSalCourierScalable |= pData->IsScalable();
1853 pInfo->mpList->Add( pData );
1856 return 1;
1859 // -----------------------------------------------------------------------
1861 struct TempFontItem
1863 ::rtl::OUString maFontFilePath;
1864 ::rtl::OString maResourcePath;
1865 TempFontItem* mpNextItem;
1868 #ifdef FR_PRIVATE
1869 static int WINAPI __AddFontResourceExW( LPCWSTR lpszfileName, DWORD fl, PVOID pdv )
1871 typedef int (WINAPI *AddFontResourceExW_FUNC)(LPCWSTR, DWORD, PVOID );
1873 static AddFontResourceExW_FUNC pFunc = NULL;
1874 static HMODULE hmGDI = NULL;
1876 if ( !pFunc && !hmGDI )
1878 hmGDI = GetModuleHandleA( "GDI32" );
1879 if ( hmGDI )
1880 pFunc = reinterpret_cast<AddFontResourceExW_FUNC>( GetProcAddress( hmGDI, "AddFontResourceExW" ) );
1883 if ( pFunc )
1884 return pFunc( lpszfileName, fl, pdv );
1885 else
1887 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1888 return 0;
1891 #endif
1893 bool ImplAddTempFont( SalData& rSalData, const String& rFontFileURL )
1895 int nRet = 0;
1896 ::rtl::OUString aUSytemPath;
1897 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
1899 #ifdef FR_PRIVATE
1900 nRet = __AddFontResourceExW( reinterpret_cast<LPCWSTR>(aUSytemPath.getStr()), FR_PRIVATE, NULL );
1901 #endif
1903 if ( !nRet )
1905 static int nCounter = 0;
1906 char aFileName[] = "soAA.fot";
1907 aFileName[2] = sal::static_int_cast<char>('A' + (15 & (nCounter>>4)));
1908 aFileName[3] = sal::static_int_cast<char>('A' + (15 & nCounter));
1909 char aResourceName[512];
1910 int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16;
1911 int nLen = ::GetTempPathA( nMaxLen, aResourceName );
1912 ::strncpy( aResourceName + nLen, aFileName, sizeof( aResourceName )- nLen );
1913 // security: end buffer in any case
1914 aResourceName[ (sizeof(aResourceName)/sizeof(*aResourceName))-1 ] = 0;
1915 ::DeleteFileA( aResourceName );
1917 rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
1918 ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
1919 // TODO: font should be private => need to investigate why it doesn't work then
1920 if( !::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL ) )
1921 return false;
1922 ++nCounter;
1924 nRet = ::AddFontResourceA( aResourceName );
1925 if( nRet > 0 )
1927 TempFontItem* pNewItem = new TempFontItem;
1928 pNewItem->maResourcePath = rtl::OString( aResourceName );
1929 pNewItem->maFontFilePath = aUSytemPath.getStr();
1930 pNewItem->mpNextItem = rSalData.mpTempFontItem;
1931 rSalData.mpTempFontItem = pNewItem;
1935 return (nRet > 0);
1938 // -----------------------------------------------------------------------
1940 void ImplReleaseTempFonts( SalData& rSalData )
1942 int nCount = 0;
1943 while( TempFontItem* p = rSalData.mpTempFontItem )
1945 ++nCount;
1946 if( p->maResourcePath.getLength() )
1948 const char* pResourcePath = p->maResourcePath.getStr();
1949 ::RemoveFontResourceA( pResourcePath );
1950 ::DeleteFileA( pResourcePath );
1952 else
1954 if( aSalShlData.mbWNT )
1955 ::RemoveFontResourceW( reinterpret_cast<LPCWSTR>(p->maFontFilePath.getStr()) );
1956 else
1958 // poor man's string conversion because converter is gone
1959 int nLen = p->maFontFilePath.getLength();
1960 char* pNameA = new char[ nLen + 1 ];
1961 for( int i = 0; i < nLen; ++i )
1962 pNameA[i] = (char)(p->maFontFilePath.getStr())[i];
1963 pNameA[ nLen ] = 0;
1964 ::RemoveFontResourceA( pNameA );
1965 delete[] pNameA;
1969 rSalData.mpTempFontItem = p->mpNextItem;
1970 delete p;
1973 #ifndef FR_PRIVATE
1974 // notify every other application
1975 // unless the temp fonts were installed as private fonts
1976 if( nCount > 0 )
1977 ::PostMessage( HWND_BROADCAST, WM_FONTCHANGE, 0, NULL );
1978 #endif // FR_PRIVATE
1981 // -----------------------------------------------------------------------
1983 static bool ImplGetFontAttrFromFile( const String& rFontFileURL,
1984 ImplDevFontAttributes& rDFA )
1986 ::rtl::OUString aUSytemPath;
1987 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) );
1989 // get FontAttributes from a *fot file
1990 // TODO: use GetTTGlobalFontInfo() to access the font directly
1991 rDFA.mnQuality = 1000;
1992 rDFA.mbDevice = true;
1993 rDFA.meFamily = FAMILY_DONTKNOW;
1994 rDFA.meWidthType = WIDTH_DONTKNOW;
1995 rDFA.meWeight = WEIGHT_DONTKNOW;
1996 rDFA.meItalic = ITALIC_DONTKNOW;
1997 rDFA.mePitch = PITCH_DONTKNOW;;
1998 rDFA.mbSubsettable= true;
1999 rDFA.mbEmbeddable = false;
2000 rDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW;
2001 rDFA.meAntiAlias = ANTIALIAS_DONTKNOW;
2003 // Create temporary file name
2004 char aFileName[] = "soAAT.fot";
2005 char aResourceName[512];
2006 int nMaxLen = sizeof(aResourceName)/sizeof(*aResourceName) - 16;
2007 int nLen = ::GetTempPathA( nMaxLen, aResourceName );
2008 ::strncpy( aResourceName + nLen, aFileName, Max( 0, nMaxLen - nLen ));
2009 ::DeleteFileA( aResourceName );
2011 // Create font resource file (typically with a .fot file name extension).
2012 rtl_TextEncoding theEncoding = osl_getThreadTextEncoding();
2013 ::rtl::OString aCFileName = rtl::OUStringToOString( aUSytemPath, theEncoding );
2014 ::CreateScalableFontResourceA( 0, aResourceName, aCFileName.getStr(), NULL );
2016 // Open and read the font resource file
2017 rtl::OUString aFotFileName = rtl::OStringToOUString( aResourceName, osl_getThreadTextEncoding() );
2018 osl::FileBase::getFileURLFromSystemPath( aFotFileName, aFotFileName );
2019 osl::File aFotFile( aFotFileName );
2020 osl::FileBase::RC aError = aFotFile.open( osl_File_OpenFlag_Read );
2021 if( aError != osl::FileBase::E_None )
2022 return false;
2024 sal_uInt64 nBytesRead = 0;
2025 char aBuffer[4096];
2026 aFotFile.read( aBuffer, sizeof( aBuffer ), nBytesRead );
2027 // clean up temporary resource file
2028 aFotFile.close();
2029 ::DeleteFileA( aResourceName );
2031 // retrieve font family name from byte offset 0x4F6
2032 int i = 0x4F6;
2033 int nNameOfs = i;
2034 while( (i < nBytesRead) && (aBuffer[i++] != 0) );
2035 // skip full name
2036 while( (i < nBytesRead) && (aBuffer[i++] != 0) );
2037 // retrieve font style name
2038 int nStyleOfs = i;
2039 while( (i < nBytesRead) && (aBuffer[i++] != 0) );
2040 if( i >= nBytesRead )
2041 return false;
2043 // convert byte strings to unicode
2044 rDFA.maName = String( aBuffer + nNameOfs, osl_getThreadTextEncoding() );
2045 rDFA.maStyleName = String( aBuffer + nStyleOfs, osl_getThreadTextEncoding() );
2047 // byte offset 0x4C7: OS2_fsSelection
2048 const char nFSS = aBuffer[ 0x4C7 ];
2049 if( nFSS & 0x01 ) // italic
2050 rDFA.meItalic = ITALIC_NORMAL;
2051 //if( nFSS & 0x20 ) // bold
2052 // rDFA.meWeight = WEIGHT_BOLD;
2053 if( nFSS & 0x40 ) // regular
2055 rDFA.meWeight = WEIGHT_NORMAL;
2056 rDFA.meItalic = ITALIC_NONE;
2059 // byte offsets 0x4D7/0x4D8: wingdi's FW_WEIGHT
2060 int nWinWeight = (aBuffer[0x4D7] & 0xFF) + ((aBuffer[0x4D8] & 0xFF) << 8);
2061 rDFA.meWeight = ImplWeightToSal( nWinWeight );
2063 rDFA.mbSymbolFlag = false; // TODO
2064 rDFA.mePitch = PITCH_DONTKNOW; // TODO
2066 // byte offset 0x4DE: pitch&family
2067 rDFA.meFamily = ImplFamilyToSal( aBuffer[0x4DE] );
2069 // byte offsets 0x4C8/0x4C9: emunits
2070 // byte offsets 0x4CE/0x4CF: winascent
2071 // byte offsets 0x4D0/0x4D1: winascent+windescent-emunits
2072 // byte offsets 0x4DF/0x4E0: avgwidth
2073 //...
2075 return true;
2078 // -----------------------------------------------------------------------
2080 bool WinSalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
2081 const String& rFontFileURL, const String& rFontName )
2083 RTL_LOGFILE_TRACE1( "WinSalGraphics::AddTempDevFont(): %s", rtl::OUStringToOString( rFontFileURL, RTL_TEXTENCODING_UTF8 ).getStr() );
2085 ImplDevFontAttributes aDFA;
2086 aDFA.maName = rFontName;
2087 aDFA.mnQuality = 1000;
2088 aDFA.mbDevice = true;
2090 // Search Font Name in Cache
2091 if( !rFontName.Len() && mpFontAttrCache )
2092 aDFA = mpFontAttrCache->GetFontAttr( rFontFileURL );
2094 // Retrieve font name from font resource
2095 if( !aDFA.maName.Len() )
2097 ImplGetFontAttrFromFile( rFontFileURL, aDFA );
2098 if( mpFontAttrCache && aDFA.maName.Len() )
2099 mpFontAttrCache->AddFontAttr( rFontFileURL, aDFA );
2102 if ( !aDFA.maName.Len() )
2103 return false;
2105 // remember temp font for cleanup later
2106 if( !ImplAddTempFont( *GetSalData(), rFontFileURL ) )
2107 return false;
2109 UINT nPreferedCharSet = DEFAULT_CHARSET;
2110 if ( !aSalShlData.mbWNT )
2112 // for W98 guess charset preference from active codepage
2113 CHARSETINFO aCharSetInfo;
2114 DWORD nCP = GetACP();
2115 if ( TranslateCharsetInfo( (DWORD*)nCP, &aCharSetInfo, TCI_SRCCODEPAGE ) )
2116 nPreferedCharSet = aCharSetInfo.ciCharset;
2119 // create matching FontData struct
2120 aDFA.mbSymbolFlag = false; // TODO: how to know it without accessing the font?
2121 aDFA.meFamily = FAMILY_DONTKNOW;
2122 aDFA.meWidthType = WIDTH_DONTKNOW;
2123 aDFA.meWeight = WEIGHT_DONTKNOW;
2124 aDFA.meItalic = ITALIC_DONTKNOW;
2125 aDFA.mePitch = PITCH_DONTKNOW;;
2126 aDFA.mbSubsettable= true;
2127 aDFA.mbEmbeddable = false;
2128 aDFA.meEmbeddedBitmap = EMBEDDEDBITMAP_DONTKNOW;
2129 aDFA.meAntiAlias = ANTIALIAS_DONTKNOW;
2132 // TODO: improve ImplDevFontAttributes using the "font resource file"
2133 aDFS.maName = // using "FONTRES:" from file
2134 if( rFontName != aDFS.maName )
2135 aDFS.maMapName = aFontName;
2138 ImplWinFontData* pFontData = new ImplWinFontData( aDFA, 0,
2139 sal::static_int_cast<WIN_BYTE>(nPreferedCharSet),
2140 sal::static_int_cast<WIN_BYTE>(TMPF_VECTOR|TMPF_TRUETYPE) );
2141 pFontData->SetFontId( reinterpret_cast<sal_IntPtr>(pFontData) );
2142 pFontList->Add( pFontData );
2143 return true;
2146 // -----------------------------------------------------------------------
2148 void WinSalGraphics::GetDevFontList( ImplDevFontList* pFontList )
2150 // make sure all fonts are registered at least temporarily
2151 static bool bOnce = true;
2152 if( bOnce )
2154 bOnce = false;
2156 // determine font path
2157 // since we are only interested in fonts that could not be
2158 // registered before because of missing administration rights
2159 // only the font path of the user installation is needed
2160 ::rtl::OUString aPath;
2161 osl_getExecutableFile( &aPath.pData );
2162 ::rtl::OUString aExecutableFile( aPath );
2163 aPath = aPath.copy( 0, aPath.lastIndexOf('/') );
2164 String aFontDirUrl = aPath.copy( 0, aPath.lastIndexOf('/') );
2165 aFontDirUrl += String( RTL_CONSTASCII_USTRINGPARAM("/share/fonts/truetype") );
2167 // collect fonts in font path that could not be registered
2168 osl::Directory aFontDir( aFontDirUrl );
2169 osl::FileBase::RC rcOSL = aFontDir.open();
2170 if( rcOSL == osl::FileBase::E_None )
2172 osl::DirectoryItem aDirItem;
2173 String aEmptyString;
2175 ::rtl::OUString aBootStrap;
2176 rtl::Bootstrap::get( String( RTL_CONSTASCII_USTRINGPARAM( "BRAND_BASE_DIR" ) ), aBootStrap );
2177 aBootStrap += String( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
2178 rtl::Bootstrap aBootstrap( aBootStrap );
2179 ::rtl::OUString aUserPath;
2180 aBootstrap.getFrom( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserInstallation" ) ), aUserPath );
2181 aUserPath += String( RTL_CONSTASCII_USTRINGPARAM("/user/config/fontnames.dat") );
2182 String aBaseURL = aPath.copy( 0, aPath.lastIndexOf('/')+1 );
2183 mpFontAttrCache = new ImplFontAttrCache( aUserPath, aBaseURL );
2185 while( aFontDir.getNextItem( aDirItem, 10 ) == osl::FileBase::E_None )
2187 osl::FileStatus aFileStatus( FileStatusMask_FileURL );
2188 rcOSL = aDirItem.getFileStatus( aFileStatus );
2189 if ( rcOSL == osl::FileBase::E_None )
2190 AddTempDevFont( pFontList, aFileStatus.getFileURL(), aEmptyString );
2193 delete mpFontAttrCache; // destructor rewrites the cache file if needed
2194 mpFontAttrCache = NULL;
2198 ImplEnumInfo aInfo;
2199 aInfo.mhDC = mhDC;
2200 aInfo.mpList = pFontList;
2201 aInfo.mpName = NULL;
2202 aInfo.mpLogFontA = NULL;
2203 aInfo.mpLogFontW = NULL;
2204 aInfo.mbCourier = false;
2205 aInfo.mbPrinter = mbPrinter;
2206 aInfo.mnFontCount = 0;
2207 if ( !mbPrinter )
2209 aInfo.mbImplSalCourierScalable = false;
2210 aInfo.mbImplSalCourierNew = false;
2212 else
2214 aInfo.mbImplSalCourierScalable = true;
2215 aInfo.mbImplSalCourierNew = true;
2218 aInfo.mnPreferedCharSet = DEFAULT_CHARSET;
2219 DWORD nCP = GetACP();
2220 CHARSETINFO aCharSetInfo;
2221 if ( TranslateCharsetInfo( (DWORD*)nCP, &aCharSetInfo, TCI_SRCCODEPAGE ) )
2222 aInfo.mnPreferedCharSet = aCharSetInfo.ciCharset;
2224 if ( aSalShlData.mbWNT )
2226 LOGFONTW aLogFont;
2227 memset( &aLogFont, 0, sizeof( aLogFont ) );
2228 aLogFont.lfCharSet = DEFAULT_CHARSET;
2229 aInfo.mpLogFontW = &aLogFont;
2230 EnumFontFamiliesExW( mhDC, &aLogFont,
2231 (FONTENUMPROCW)SalEnumFontsProcExW, (LPARAM)(void*)&aInfo, 0 );
2233 else
2235 LOGFONTA aLogFont;
2236 memset( &aLogFont, 0, sizeof( aLogFont ) );
2237 aLogFont.lfCharSet = DEFAULT_CHARSET;
2238 aInfo.mpLogFontA = &aLogFont;
2239 EnumFontFamiliesExA( mhDC, &aLogFont,
2240 (FONTENUMPROCA)SalEnumFontsProcExA, (LPARAM)(void*)&aInfo, 0 );
2243 // Feststellen, was es fuer Courier-Schriften auf dem Bildschirm gibt,
2244 // um in SetFont() evt. Courier auf Courier New zu mappen
2245 if ( !mbPrinter )
2247 bImplSalCourierScalable = aInfo.mbImplSalCourierScalable;
2248 bImplSalCourierNew = aInfo.mbImplSalCourierNew;
2252 // ----------------------------------------------------------------------------
2254 void WinSalGraphics::GetDevFontSubstList( OutputDevice* )
2257 // -----------------------------------------------------------------------
2259 BOOL WinSalGraphics::GetGlyphBoundRect( long nIndex, Rectangle& rRect )
2261 HDC hDC = mhDC;
2263 // use unity matrix
2264 MAT2 aMat;
2265 aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
2266 aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
2268 UINT nGGOFlags = GGO_METRICS;
2269 if( !(nIndex & GF_ISCHAR) )
2270 nGGOFlags |= GGO_GLYPH_INDEX;
2271 nIndex &= GF_IDXMASK;
2273 GLYPHMETRICS aGM;
2274 aGM.gmptGlyphOrigin.x = aGM.gmptGlyphOrigin.y = 0;
2275 aGM.gmBlackBoxX = aGM.gmBlackBoxY = 0;
2276 DWORD nSize = GDI_ERROR;
2277 if ( aSalShlData.mbWNT )
2278 nSize = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags, &aGM, 0, NULL, &aMat );
2279 else if( (nGGOFlags & GGO_GLYPH_INDEX) || (nIndex <= 255) )
2280 nSize = ::GetGlyphOutlineA( hDC, nIndex, nGGOFlags, &aGM, 0, NULL, &aMat );
2282 if( nSize == GDI_ERROR )
2283 return false;
2285 rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
2286 Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
2287 rRect.Left() = static_cast<int>( mfFontScale * rRect.Left() );
2288 rRect.Right() = static_cast<int>( mfFontScale * rRect.Right() );
2289 rRect.Top() = static_cast<int>( mfFontScale * rRect.Top() );
2290 rRect.Bottom() = static_cast<int>( mfFontScale * rRect.Bottom() );
2291 return true;
2294 // -----------------------------------------------------------------------
2296 BOOL WinSalGraphics::GetGlyphOutline( long nIndex,
2297 ::basegfx::B2DPolyPolygon& rB2DPolyPoly )
2299 rB2DPolyPoly.clear();
2301 BOOL bRet = FALSE;
2302 HDC hDC = mhDC;
2304 // use unity matrix
2305 MAT2 aMat;
2306 aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
2307 aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
2309 UINT nGGOFlags = GGO_NATIVE;
2310 if( !(nIndex & GF_ISCHAR) )
2311 nGGOFlags |= GGO_GLYPH_INDEX;
2312 nIndex &= GF_IDXMASK;
2314 GLYPHMETRICS aGlyphMetrics;
2315 DWORD nSize1 = GDI_ERROR;
2316 if ( aSalShlData.mbWNT )
2317 nSize1 = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
2318 else if( (nGGOFlags & GGO_GLYPH_INDEX) || (nIndex <= 255) )
2319 nSize1 = ::GetGlyphOutlineA( hDC, nIndex, nGGOFlags, &aGlyphMetrics, 0, NULL, &aMat );
2321 if( !nSize1 ) // blank glyphs are ok
2322 bRet = TRUE;
2323 else if( nSize1 != GDI_ERROR )
2325 BYTE* pData = new BYTE[ nSize1 ];
2326 DWORD nSize2;
2327 if ( aSalShlData.mbWNT )
2328 nSize2 = ::GetGlyphOutlineW( hDC, nIndex, nGGOFlags,
2329 &aGlyphMetrics, nSize1, pData, &aMat );
2330 else
2331 nSize2 = ::GetGlyphOutlineA( hDC, nIndex, nGGOFlags,
2332 &aGlyphMetrics, nSize1, pData, &aMat );
2334 if( nSize1 == nSize2 )
2336 bRet = TRUE;
2338 int nPtSize = 512;
2339 Point* pPoints = new Point[ nPtSize ];
2340 BYTE* pFlags = new BYTE[ nPtSize ];
2342 TTPOLYGONHEADER* pHeader = (TTPOLYGONHEADER*)pData;
2343 while( (BYTE*)pHeader < pData+nSize2 )
2345 // only outline data is interesting
2346 if( pHeader->dwType != TT_POLYGON_TYPE )
2347 break;
2349 // get start point; next start points are end points
2350 // of previous segment
2351 USHORT nPnt = 0;
2353 long nX = IntTimes256FromFixed( pHeader->pfxStart.x );
2354 long nY = IntTimes256FromFixed( pHeader->pfxStart.y );
2355 pPoints[ nPnt ] = Point( nX, nY );
2356 pFlags[ nPnt++ ] = POLY_NORMAL;
2358 bool bHasOfflinePoints = false;
2359 TTPOLYCURVE* pCurve = (TTPOLYCURVE*)( pHeader + 1 );
2360 pHeader = (TTPOLYGONHEADER*)( (BYTE*)pHeader + pHeader->cb );
2361 while( (BYTE*)pCurve < (BYTE*)pHeader )
2363 int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx;
2364 if( nPtSize < nNeededSize )
2366 Point* pOldPoints = pPoints;
2367 BYTE* pOldFlags = pFlags;
2368 nPtSize = 2 * nNeededSize;
2369 pPoints = new Point[ nPtSize ];
2370 pFlags = new BYTE[ nPtSize ];
2371 for( USHORT i = 0; i < nPnt; ++i )
2373 pPoints[ i ] = pOldPoints[ i ];
2374 pFlags[ i ] = pOldFlags[ i ];
2376 delete[] pOldPoints;
2377 delete[] pOldFlags;
2380 int i = 0;
2381 if( TT_PRIM_LINE == pCurve->wType )
2383 while( i < pCurve->cpfx )
2385 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2386 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2387 ++i;
2388 pPoints[ nPnt ] = Point( nX, nY );
2389 pFlags[ nPnt ] = POLY_NORMAL;
2390 ++nPnt;
2393 else if( TT_PRIM_QSPLINE == pCurve->wType )
2395 bHasOfflinePoints = true;
2396 while( i < pCurve->cpfx )
2398 // get control point of quadratic bezier spline
2399 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2400 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2401 ++i;
2402 Point aControlP( nX, nY );
2404 // calculate first cubic control point
2405 // P0 = 1/3 * (PBeg + 2 * PQControl)
2406 nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X();
2407 nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y();
2408 pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
2409 pFlags[ nPnt+0 ] = POLY_CONTROL;
2411 // calculate endpoint of segment
2412 nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
2413 nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
2415 if ( i+1 >= pCurve->cpfx )
2417 // endpoint is either last point in segment => advance
2418 ++i;
2420 else
2422 // or endpoint is the middle of two control points
2423 nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x );
2424 nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y );
2425 nX = (nX + 1) / 2;
2426 nY = (nY + 1) / 2;
2427 // no need to advance, because the current point
2428 // is the control point in next bezier spline
2431 pPoints[ nPnt+2 ] = Point( nX, nY );
2432 pFlags[ nPnt+2 ] = POLY_NORMAL;
2434 // calculate second cubic control point
2435 // P1 = 1/3 * (PEnd + 2 * PQControl)
2436 nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X();
2437 nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y();
2438 pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
2439 pFlags[ nPnt+1 ] = POLY_CONTROL;
2441 nPnt += 3;
2445 // next curve segment
2446 pCurve = (TTPOLYCURVE*)&pCurve->apfx[ i ];
2449 // end point is start point for closed contour
2450 // disabled, because Polygon class closes the contour itself
2451 // pPoints[nPnt++] = pPoints[0];
2452 // #i35928#
2453 // Added again, but add only when not yet closed
2454 if(pPoints[nPnt - 1] != pPoints[0])
2456 if( bHasOfflinePoints )
2457 pFlags[nPnt] = pFlags[0];
2459 pPoints[nPnt++] = pPoints[0];
2462 // convert y-coordinates W32 -> VCL
2463 for( int i = 0; i < nPnt; ++i )
2464 pPoints[i].Y() = -pPoints[i].Y();
2466 // insert into polypolygon
2467 Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : NULL) );
2468 // convert to B2DPolyPolygon
2469 // TODO: get rid of the intermediate PolyPolygon
2470 rB2DPolyPoly.append( aPoly.getB2DPolygon() );
2473 delete[] pPoints;
2474 delete[] pFlags;
2477 delete[] pData;
2480 // rescaling needed for the PolyPolygon conversion
2481 if( rB2DPolyPoly.count() )
2483 ::basegfx::B2DHomMatrix aMatrix;
2484 aMatrix.scale( mfFontScale/256, mfFontScale/256 );
2485 rB2DPolyPoly.transform( aMatrix );
2488 return bRet;
2491 // -----------------------------------------------------------------------
2493 class ScopedFont
2495 public:
2496 explicit ScopedFont(WinSalGraphics & rData);
2498 ~ScopedFont();
2500 private:
2501 WinSalGraphics & m_rData;
2502 HFONT m_hOrigFont;
2505 ScopedFont::ScopedFont(WinSalGraphics & rData): m_rData(rData)
2507 m_hOrigFont = m_rData.mhFonts[0];
2508 m_rData.mhFonts[0] = 0; // avoid deletion of current font
2511 ScopedFont::~ScopedFont()
2513 if( m_hOrigFont )
2515 // restore original font, destroy temporary font
2516 HFONT hTempFont = m_rData.mhFonts[0];
2517 m_rData.mhFonts[0] = m_hOrigFont;
2518 SelectObject( m_rData.mhDC, m_hOrigFont );
2519 DeleteObject( hTempFont );
2523 class ScopedTrueTypeFont
2525 public:
2526 inline ScopedTrueTypeFont(): m_pFont(0) {}
2528 ~ScopedTrueTypeFont();
2530 int open(void * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum);
2532 inline TrueTypeFont * get() const { return m_pFont; }
2534 private:
2535 TrueTypeFont * m_pFont;
2538 ScopedTrueTypeFont::~ScopedTrueTypeFont()
2540 if (m_pFont != 0)
2541 CloseTTFont(m_pFont);
2544 int ScopedTrueTypeFont::open(void * pBuffer, sal_uInt32 nLen,
2545 sal_uInt32 nFaceNum)
2547 OSL_ENSURE(m_pFont == 0, "already open");
2548 return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont);
2551 BOOL WinSalGraphics::CreateFontSubset( const rtl::OUString& rToFile,
2552 const ImplFontData* pFont, long* pGlyphIDs, sal_uInt8* pEncoding,
2553 sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
2555 // TODO: use more of the central font-subsetting code, move stuff there if needed
2557 // create matching ImplFontSelectData
2558 // we need just enough to get to the font file data
2559 // use height=1000 for easier debugging (to match psprint's font units)
2560 ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2562 // TODO: much better solution: move SetFont and restoration of old font to caller
2563 ScopedFont aOldFont(*this);
2564 float fScale = 1.0;
2565 HFONT hOldFont = 0;
2566 ImplDoSetFont( &aIFSD, fScale, hOldFont );
2568 ImplWinFontData* pWinFontData = (ImplWinFontData*)aIFSD.mpFontData;
2569 pWinFontData->UpdateFromHDC( mhDC );
2570 /*const*/ ImplFontCharMap* pImplFontCharMap = pWinFontData->GetImplFontCharMap();
2572 #if OSL_DEBUG_LEVEL > 1
2573 // get font metrics
2574 TEXTMETRICA aWinMetric;
2575 if( !::GetTextMetricsA( mhDC, &aWinMetric ) )
2576 return FALSE;
2578 DBG_ASSERT( !(aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "cannot subset device font" );
2579 DBG_ASSERT( aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE, "can only subset TT font" );
2580 #endif
2582 rtl::OUString aSysPath;
2583 if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
2584 return FALSE;
2585 const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
2586 const ByteString aToFile( aSysPath.getStr(), (xub_StrLen)aSysPath.getLength(), aThreadEncoding );
2588 // check if the font has a CFF-table
2589 const DWORD nCffTag = CalcTag( "CFF " );
2590 const RawFontData aRawCffData( mhDC, nCffTag );
2591 if( aRawCffData.get() )
2593 long nRealGlyphIds[ 256 ];
2594 for( int i = 0; i < nGlyphCount; ++i )
2596 // TODO: remap notdef glyph if needed
2597 // TODO: use GDI's GetGlyphIndices instead? Does it handle GSUB properly?
2598 sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
2599 if( pGlyphIDs[i] & GF_ISCHAR ) // remaining pseudo-glyphs need to be translated
2600 nGlyphIdx = pImplFontCharMap->GetGlyphIndex( nGlyphIdx );
2601 if( (pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0) // TODO: vertical substitution
2602 {/*####*/}
2604 nRealGlyphIds[i] = nGlyphIdx;
2607 // provide a font subset from the CFF-table
2608 FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
2609 rInfo.LoadFont( FontSubsetInfo::CFF_FONT, aRawCffData.get(), aRawCffData.size() );
2610 bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL,
2611 nRealGlyphIds, pEncoding, nGlyphCount, pGlyphWidths );
2612 fclose( pOutFile );
2613 return bRC;
2616 // get raw font file data
2617 const RawFontData xRawFontData( mhDC, NULL );
2618 if( !xRawFontData.get() )
2619 return FALSE;
2621 // open font file
2622 sal_uInt32 nFaceNum = 0;
2623 if( !*xRawFontData.get() ) // TTC candidate
2624 nFaceNum = ~0U; // indicate "TTC font extracts only"
2626 ScopedTrueTypeFont aSftTTF;
2627 int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
2628 if( nRC != SF_OK )
2629 return FALSE;
2631 TTGlobalFontInfo aTTInfo;
2632 ::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
2633 rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF;
2634 rInfo.m_aPSName = ImplSalGetUniString( aTTInfo.psname );
2635 rInfo.m_nAscent = +aTTInfo.winAscent;
2636 rInfo.m_nDescent = -aTTInfo.winDescent;
2637 rInfo.m_aFontBBox = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ),
2638 Point( aTTInfo.xMax, aTTInfo.yMax ) );
2639 rInfo.m_nCapHeight = aTTInfo.yMax; // Well ...
2641 // subset TTF-glyphs and get their properties
2642 // take care that subset fonts require the NotDef glyph in pos 0
2643 int nOrigCount = nGlyphCount;
2644 USHORT aShortIDs[ 256 ];
2645 sal_uInt8 aTempEncs[ 256 ];
2647 int nNotDef=-1, i;
2648 for( i = 0; i < nGlyphCount; ++i )
2650 aTempEncs[i] = pEncoding[i];
2651 sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK;
2652 if( pGlyphIDs[i] & GF_ISCHAR )
2654 sal_Unicode cChar = static_cast<sal_Unicode>(nGlyphIdx); // TODO: sal_UCS4
2655 const bool bVertical = ((pGlyphIDs[i] & (GF_ROTMASK|GF_GSUB)) != 0);
2656 nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical );
2657 if( (nGlyphIdx == 0) && pFont->IsSymbolFont() )
2659 // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
2660 cChar = (cChar & 0xF000) ? (cChar & 0x00FF) : (cChar | 0xF000);
2661 nGlyphIdx = ::MapChar( aSftTTF.get(), cChar, bVertical );
2664 aShortIDs[i] = static_cast<USHORT>( nGlyphIdx );
2665 if( !nGlyphIdx )
2666 if( nNotDef < 0 )
2667 nNotDef = i; // first NotDef glyph found
2670 if( nNotDef != 0 )
2672 // add fake NotDef glyph if needed
2673 if( nNotDef < 0 )
2674 nNotDef = nGlyphCount++;
2676 // NotDef glyph must be in pos 0 => swap glyphids
2677 aShortIDs[ nNotDef ] = aShortIDs[0];
2678 aTempEncs[ nNotDef ] = aTempEncs[0];
2679 aShortIDs[0] = 0;
2680 aTempEncs[0] = 0;
2682 DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" );
2684 // fill pWidth array
2685 TTSimpleGlyphMetrics* pMetrics =
2686 ::GetTTSimpleGlyphMetrics( aSftTTF.get(), aShortIDs, nGlyphCount, aIFSD.mbVertical );
2687 if( !pMetrics )
2688 return FALSE;
2689 sal_uInt16 nNotDefAdv = pMetrics[0].adv;
2690 pMetrics[0].adv = pMetrics[nNotDef].adv;
2691 pMetrics[nNotDef].adv = nNotDefAdv;
2692 for( i = 0; i < nOrigCount; ++i )
2693 pGlyphWidths[i] = pMetrics[i].adv;
2694 free( pMetrics );
2696 // write subset into destination file
2697 nRC = ::CreateTTFromTTGlyphs( aSftTTF.get(), aToFile.GetBuffer(), aShortIDs,
2698 aTempEncs, nGlyphCount, 0, NULL, 0 );
2699 return (nRC == SF_OK);
2702 //--------------------------------------------------------------------------
2704 const void* WinSalGraphics::GetEmbedFontData( const ImplFontData* pFont,
2705 const sal_Unicode* pUnicodes, sal_Int32* pCharWidths,
2706 FontSubsetInfo& rInfo, long* pDataLen )
2708 // create matching ImplFontSelectData
2709 // we need just enough to get to the font file data
2710 ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2712 // TODO: much better solution: move SetFont and restoration of old font to caller
2713 ScopedFont aOldFont(*this);
2714 SetFont( &aIFSD, 0 );
2716 // get the raw font file data
2717 RawFontData aRawFontData( mhDC );
2718 *pDataLen = aRawFontData.size();
2719 if( !aRawFontData.get() )
2720 return NULL;
2722 // get important font properties
2723 TEXTMETRICA aTm;
2724 if( !::GetTextMetricsA( mhDC, &aTm ) )
2725 *pDataLen = 0;
2726 rInfo.m_nFontType = FontSubsetInfo::ANY_TYPE1;
2727 WCHAR aFaceName[64];
2728 int nFNLen = ::GetTextFaceW( mhDC, 64, aFaceName );
2729 // #i59854# strip eventual null byte
2730 while( nFNLen > 0 && aFaceName[nFNLen-1] == 0 )
2731 nFNLen--;
2732 if( nFNLen == 0 )
2733 *pDataLen = 0;
2734 rInfo.m_aPSName = String( reinterpret_cast<const sal_Unicode*>(aFaceName), sal::static_int_cast<USHORT>(nFNLen) );
2735 rInfo.m_nAscent = +aTm.tmAscent;
2736 rInfo.m_nDescent = -aTm.tmDescent;
2737 rInfo.m_aFontBBox = Rectangle( Point( -aTm.tmOverhang, -aTm.tmDescent ),
2738 Point( aTm.tmMaxCharWidth, aTm.tmAscent+aTm.tmExternalLeading ) );
2739 rInfo.m_nCapHeight = aTm.tmAscent; // Well ...
2741 // get individual character widths
2742 for( int i = 0; i < 256; ++i )
2744 int nCharWidth = 0;
2745 const sal_Unicode cChar = pUnicodes[i];
2746 if( !::GetCharWidth32W( mhDC, cChar, cChar, &nCharWidth ) )
2747 *pDataLen = 0;
2748 pCharWidths[i] = nCharWidth;
2751 if( !*pDataLen )
2752 return NULL;
2754 const unsigned char* pData = aRawFontData.steal();
2755 return (void*)pData;
2758 //--------------------------------------------------------------------------
2760 void WinSalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ )
2762 delete[] reinterpret_cast<char*>(const_cast<void*>(pData));
2765 //--------------------------------------------------------------------------
2767 const Ucs2SIntMap* WinSalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
2769 // TODO: even for builtin fonts we get here... why?
2770 if( !pFont->IsEmbeddable() )
2771 return NULL;
2773 // fill the encoding vector
2774 // currently no nonencoded vector
2775 if( pNonEncoded )
2776 *pNonEncoded = NULL;
2778 const ImplWinFontData* pWinFontData = static_cast<const ImplWinFontData*>(pFont);
2779 const Ucs2SIntMap* pEncoding = pWinFontData->GetEncodingVector();
2780 if( pEncoding == NULL )
2782 Ucs2SIntMap* pNewEncoding = new Ucs2SIntMap;
2783 #if 0
2784 // TODO: get correct encoding vector
2785 GLYPHSET aGlyphSet;
2786 aGlyphSet.cbThis = sizeof(aGlyphSet);
2787 DWORD aW = ::GetFontUnicodeRanges( mhDC, &aGlyphSet);
2788 #else
2789 for( sal_Unicode i = 32; i < 256; ++i )
2790 (*pNewEncoding)[i] = i;
2791 #endif
2792 pWinFontData->SetEncodingVector( pNewEncoding );
2793 pEncoding = pNewEncoding;
2796 return pEncoding;
2799 //--------------------------------------------------------------------------
2801 void WinSalGraphics::GetGlyphWidths( const ImplFontData* pFont,
2802 bool bVertical,
2803 Int32Vector& rWidths,
2804 Ucs2UIntMap& rUnicodeEnc )
2806 // create matching ImplFontSelectData
2807 // we need just enough to get to the font file data
2808 ImplFontSelectData aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
2810 // TODO: much better solution: move SetFont and restoration of old font to caller
2811 ScopedFont aOldFont(*this);
2813 float fScale = 0.0;
2814 HFONT hOldFont = 0;
2815 ImplDoSetFont( &aIFSD, fScale, hOldFont );
2817 if( pFont->IsSubsettable() )
2819 // get raw font file data
2820 const RawFontData xRawFontData( mhDC );
2821 if( !xRawFontData.get() )
2822 return;
2824 // open font file
2825 sal_uInt32 nFaceNum = 0;
2826 if( !*xRawFontData.get() ) // TTC candidate
2827 nFaceNum = ~0U; // indicate "TTC font extracts only"
2829 ScopedTrueTypeFont aSftTTF;
2830 int nRC = aSftTTF.open( (void*)xRawFontData.get(), xRawFontData.size(), nFaceNum );
2831 if( nRC != SF_OK )
2832 return;
2834 int nGlyphs = GetTTGlyphCount( aSftTTF.get() );
2835 if( nGlyphs > 0 )
2837 rWidths.resize(nGlyphs);
2838 std::vector<sal_uInt16> aGlyphIds(nGlyphs);
2839 for( int i = 0; i < nGlyphs; i++ )
2840 aGlyphIds[i] = sal_uInt16(i);
2841 TTSimpleGlyphMetrics* pMetrics = ::GetTTSimpleGlyphMetrics( aSftTTF.get(),
2842 &aGlyphIds[0],
2843 nGlyphs,
2844 bVertical ? 1 : 0 );
2845 if( pMetrics )
2847 for( int i = 0; i< nGlyphs; i++ )
2848 rWidths[i] = pMetrics[i].adv;
2849 free( pMetrics );
2850 rUnicodeEnc.clear();
2852 const ImplWinFontData* pWinFont = static_cast<const ImplWinFontData*>(pFont);
2853 ImplFontCharMap* pMap = pWinFont->GetImplFontCharMap();
2854 DBG_ASSERT( pMap && pMap->GetCharCount(), "no map" );
2856 int nCharCount = pMap->GetCharCount();
2857 sal_uInt32 nChar = pMap->GetFirstChar();
2858 for( int i = 0; i < nCharCount; i++ )
2860 if( nChar < 0x00010000 )
2862 sal_uInt16 nGlyph = ::MapChar( aSftTTF.get(),
2863 static_cast<sal_Ucs>(nChar),
2864 bVertical ? 1 : 0 );
2865 if( nGlyph )
2866 rUnicodeEnc[ static_cast<sal_Unicode>(nChar) ] = nGlyph;
2868 nChar = pMap->GetNextChar( nChar );
2872 else if( pFont->IsEmbeddable() )
2874 // get individual character widths
2875 rWidths.clear();
2876 rUnicodeEnc.clear();
2877 rWidths.reserve( 224 );
2878 for( sal_Unicode i = 32; i < 256; ++i )
2880 int nCharWidth = 0;
2881 if( ::GetCharWidth32W( mhDC, i, i, &nCharWidth ) )
2883 rUnicodeEnc[ i ] = rWidths.size();
2884 rWidths.push_back( nCharWidth );
2890 //--------------------------------------------------------------------------
2892 void WinSalGraphics::DrawServerFontLayout( const ServerFontLayout& )
2895 //--------------------------------------------------------------------------
2897 SystemFontData WinSalGraphics::GetSysFontData( int nFallbacklevel ) const
2899 SystemFontData aSysFontData;
2901 if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
2902 if (nFallbacklevel < 0 ) nFallbacklevel = 0;
2904 aSysFontData.nSize = sizeof( SystemFontData );
2905 aSysFontData.hFont = mhFonts[nFallbacklevel];
2906 aSysFontData.bFakeBold = false;
2907 aSysFontData.bFakeItalic = false;
2908 aSysFontData.bAntialias = true;
2909 aSysFontData.bVerticalCharacterType = false;
2911 OSL_TRACE("\r\n:WinSalGraphics::GetSysFontData(): FontID: %p, Fallback level: %d",
2912 aSysFontData.hFont,
2913 nFallbacklevel);
2915 return aSysFontData;
2918 //--------------------------------------------------------------------------