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"
34 #include <tools/prewin.h>
36 #include <tools/postwin.h>
37 #include <vcl/sysdata.hxx>
38 #include "tools/svwin.h"
40 #include "wincomp.hxx"
41 #include "saldata.hxx"
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"
75 #ifdef ENABLE_GRAPHITE
76 #include <graphite/GrClient.h>
77 #include <graphite/WinFont.h>
87 static const int MAXFONTHEIGHT
= 2048;
93 inline FIXED
FixedFromDouble( double d
)
95 const long l
= (long) ( d
* 65536. );
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
124 FontAttrMap aFontAttributes
;
125 rtl::OUString aCacheFileName
;
130 String
OptimizeURL( const String
& rURL
) const;
132 enum{ MAGIC
= 0x12349876 }; // change if fontattrcache format changes
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
)
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() )
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
;
164 aCacheFile
.ReadByteString( aFontFileURL
, RTL_TEXTENCODING_UTF8
);
165 if( !aFontFileURL
.Len() )
167 aCacheFile
.ReadByteString( aDFA
.maName
, RTL_TEXTENCODING_UTF8
);
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()
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
);
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() )
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
) );
250 // =======================================================================
252 // raw font data with a scoped lifetime
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
; }
263 unsigned char* mpRawBytes
;
267 RawFontData::RawFontData( HDC hDC
, DWORD nTableTag
)
271 // get required size in bytes
272 mnByteCount
= ::GetFontData( hDC
, nTableTag
, 0, NULL
, 0 );
273 if( mnByteCount
== GDI_ERROR
)
275 else if( !mnByteCount
)
278 // allocate the array
279 mpRawBytes
= new unsigned char[ mnByteCount
];
281 // get raw data in chunks small enough for GetFontData()
283 DWORD nMaxChunkSize
= 0x100000;
286 // calculate remaining raw data to get
287 DWORD nFDGet
= mnByteCount
- nRawDataOfs
;
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
);
297 else if( nFDGot
!= GDI_ERROR
)
298 nRawDataOfs
+= nFDGot
;
301 // was the chunk too big? reduce it
303 if( nMaxChunkSize
< 0x10000 )
308 // cleanup if the raw data is incomplete
309 if( nRawDataOfs
!= mnByteCount
)
316 // =======================================================================
321 ImplDevFontList
* mpList
;
323 LOGFONTA
* mpLogFontA
;
324 LOGFONTW
* mpLogFontW
;
325 UINT mnPreferedCharSet
;
327 bool mbImplSalCourierScalable
;
328 bool mbImplSalCourierNew
;
333 // =======================================================================
335 static CharSet
ImplCharSetToSal( BYTE nCharSet
)
337 rtl_TextEncoding eTextEncoding
;
339 if ( nCharSet
== OEM_CHARSET
)
341 UINT nCP
= (USHORT
)GetOEMCP();
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;
349 eTextEncoding
= rtl_getTextEncodingFromWindowsCodePage(nCP
);
356 eTextEncoding
= rtl_getTextEncodingFromWindowsCharset( nCharSet
);
358 eTextEncoding
= RTL_TEXTENCODING_UNICODE
;
361 return eTextEncoding
;
364 // -----------------------------------------------------------------------
366 static FontFamily
ImplFamilyToSal( BYTE nFamily
)
368 switch ( nFamily
& 0xF0 )
371 return FAMILY_DECORATIVE
;
374 return FAMILY_MODERN
;
380 return FAMILY_SCRIPT
;
389 return FAMILY_DONTKNOW
;
392 // -----------------------------------------------------------------------
394 static BYTE
ImplFamilyToWin( FontFamily eFamily
)
398 case FAMILY_DECORATIVE
:
399 return FF_DECORATIVE
;
423 // -----------------------------------------------------------------------
425 static FontWeight
ImplWeightToSal( int nWeight
)
427 if ( nWeight
<= FW_THIN
)
429 else if ( nWeight
<= FW_ULTRALIGHT
)
430 return WEIGHT_ULTRALIGHT
;
431 else if ( nWeight
<= FW_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
)
441 else if ( nWeight
<= FW_ULTRABOLD
)
442 return WEIGHT_ULTRABOLD
;
447 // -----------------------------------------------------------------------
449 static int ImplWeightToWin( FontWeight eWeight
)
456 case WEIGHT_ULTRALIGHT
:
457 return FW_ULTRALIGHT
;
462 case WEIGHT_SEMILIGHT
:
469 case WEIGHT_SEMIBOLD
:
475 case WEIGHT_ULTRABOLD
:
488 // -----------------------------------------------------------------------
490 inline FontPitch
ImplLogPitchToSal( BYTE nPitch
)
492 if ( nPitch
& FIXED_PITCH
)
495 return PITCH_VARIABLE
;
498 // -----------------------------------------------------------------------
500 inline FontPitch
ImplMetricPitchToSal( BYTE nPitch
)
502 // Sausaecke bei MS !! siehe NT Hilfe
503 if ( !(nPitch
& TMPF_FIXED_PITCH
) )
506 return PITCH_VARIABLE
;
509 // -----------------------------------------------------------------------
511 inline BYTE
ImplPitchToWin( FontPitch ePitch
)
513 if ( ePitch
== PITCH_FIXED
)
515 else if ( ePitch
== PITCH_VARIABLE
)
516 return VARIABLE_PITCH
;
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) )
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
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
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
)
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
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
678 // -----------------------------------------------------------------------
680 static ImplWinFontData
* ImplLogMetricToDevFontDataA( const ENUMLOGFONTEXA
* pLogFont
,
681 const NEWTEXTMETRICA
* pMetric
,
685 if ( nFontType
& RASTER_FONTTYPE
)
686 nHeight
= pMetric
->tmHeight
- pMetric
->tmInternalLeading
;
688 ImplWinFontData
* pData
= new ImplWinFontData(
689 WinFont2DevFontAttributes(*pLogFont
, *pMetric
, nFontType
),
691 pLogFont
->elfLogFont
.lfCharSet
,
692 pMetric
->tmPitchAndFamily
);
697 // -----------------------------------------------------------------------
699 static ImplWinFontData
* ImplLogMetricToDevFontDataW( const ENUMLOGFONTEXW
* pLogFont
,
700 const NEWTEXTMETRICW
* pMetric
,
704 if ( nFontType
& RASTER_FONTTYPE
)
705 nHeight
= pMetric
->tmHeight
- pMetric
->tmInternalLeading
;
707 ImplWinFontData
* pData
= new ImplWinFontData(
708 WinFont2DevFontAttributes(*pLogFont
, *pMetric
, nFontType
),
710 pLogFont
->elfLogFont
.lfCharSet
,
711 pMetric
->tmPitchAndFamily
);
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
);
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
);
743 rFont
.SetItalic( ITALIC_NONE
);
744 if ( rLogFont
.lfUnderline
)
745 rFont
.SetUnderline( UNDERLINE_SINGLE
);
747 rFont
.SetUnderline( UNDERLINE_NONE
);
748 if ( rLogFont
.lfStrikeOut
)
749 rFont
.SetStrikeout( STRIKEOUT_SINGLE
);
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
);
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
);
782 rFont
.SetItalic( ITALIC_NONE
);
783 if ( rLogFont
.lfUnderline
)
784 rFont
.SetUnderline( UNDERLINE_SINGLE
);
786 rFont
.SetUnderline( UNDERLINE_NONE
);
787 if ( rLogFont
.lfStrikeOut
)
788 rFont
.SetStrikeout( STRIKEOUT_SINGLE
);
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
),
804 mbDisableGlyphApi( false ),
805 mbHasKoreanRange( false ),
806 mbHasCJKSupport( false ),
807 #ifdef ENABLE_GRAPHITE
808 mbHasGraphiteSupport( false ),
810 mbHasArabicSupport ( false ),
811 mbAliasSymbolsLow( false ),
812 mbAliasSymbolsHigh( false ),
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
;
847 mpUnicodeMap
->DeReference();
848 delete mpEncodingVector
;
851 // -----------------------------------------------------------------------
853 sal_IntPtr
ImplWinFontData::GetFontId() const
858 // -----------------------------------------------------------------------
860 void ImplWinFontData::UpdateFromHDC( HDC hDC
) const
862 // short circuit if already initialized
863 if( mpUnicodeMap
!= NULL
)
866 ReadCmapTable( 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
);
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;
885 // #110548# more important than #107885# => TODO: better solution
886 DWORD nFLI
= GetFontLanguageInfo( hDC
);
887 if( 0 == (nFLI
& GCP_GLYPHSHAPE
) )
888 mbDisableGlyphApi
= true;
892 // -----------------------------------------------------------------------
894 bool ImplWinFontData::HasGSUBstitutions( HDC hDC
) const
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();
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
)
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 );
940 sal_uInt32 ulUnicodeRange3
= GetUInt( pOS2map
+ 50 );
941 sal_uInt32 ulUnicodeRange4
= GetUInt( pOS2map
+ 54 );
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
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
)
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() )
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
);
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
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
)
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() ) {
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
);
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
) );
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;
1052 // -----------------------------------------------------------------------
1054 int CALLBACK
SalEnumQueryFontProcExA( const ENUMLOGFONTEXA
*,
1055 const NEWTEXTMETRICEXA
*,
1056 DWORD
, LPARAM lParam
)
1058 *((bool*)(void*)lParam
) = true;
1062 // -----------------------------------------------------------------------
1064 bool ImplIsFontAvailable( HDC hDC
, const UniString
& rName
)
1066 bool bAvailable
= false;
1068 if ( aSalShlData
.mbWNT
)
1070 // Test, if Font available
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 );
1086 ByteString aTemp
= ImplSalGetWinAnsiString( rName
);
1088 // Test, if Font available
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 );
1106 // -----------------------------------------------------------------------
1108 void ImplGetLogFontFromFontSelect( HDC hDC
,
1109 const ImplFontSelectData
* pFont
,
1111 bool /*bTestVerticalAvail*/ )
1114 if ( pFont
->mpFontData
)
1115 aName
= pFont
->mpFontData
->maName
;
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
);
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 );
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
,
1184 bool /*bTestVerticalAvail*/ )
1187 if( pFont
->mpFontData
)
1188 aName
= ImplSalGetWinAnsiString( pFont
->mpFontData
->maName
);
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
);
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 );
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
)
1261 // only required for virtual devices, see below for details
1262 hdcScreen
= GetDC(0);
1264 if( aSalShlData
.mbWNT
)
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
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
)
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
);
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
;
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
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
)
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
);
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
;
1374 ::ReleaseDC( NULL
, hdcScreen
);
1379 USHORT
WinSalGraphics::SetFont( ImplFontSelectData
* pFont
, int nFallbackLevel
)
1381 // return early if there is no new font
1384 // deselect still active font
1386 ::SelectFont( mhDC
, mhDefFont
);
1387 // release no longer referenced font handles
1388 for( int i
= nFallbackLevel
; i
< MAX_FALLBACK
; ++i
)
1391 ::DeleteFont( mhFonts
[i
] );
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
);
1403 HFONT hNewFont
= ImplDoSetFont( pFont
, mfFontScale
, hOldFont
);
1407 // keep default font
1408 mhDefFont
= hOldFont
;
1412 // release no longer referenced font handles
1413 for( int i
= nFallbackLevel
; i
< MAX_FALLBACK
; ++i
)
1417 ::DeleteFont( mhFonts
[i
] );
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
1446 return SAL_SETFONT_USEDRAWTEXTARRAY
;
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
);
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
) )
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);
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
)
1549 pData
->mpFontCharSets
[pData
->mnFontCharSetCount
] = pLogFont
->elfLogFont
.lfCharSet
;
1550 pData
->mnFontCharSetCount
++;
1554 // -----------------------------------------------------------------------
1556 static void ImplGetAllFontCharSets( WinSalGraphics
* pData
)
1558 if ( !pData
->mpFontCharSets
)
1559 pData
->mpFontCharSets
= new BYTE
[256];
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
);
1578 if ( !TranslateCharsetInfo( (DWORD
*)(ULONG
)GetTextCharset( pData
->mhDC
), &aInfo
, TCI_SRCCHARSET
) )
1581 if ( !pData
->mpFontKernPairs
)
1582 pData
->mpFontKernPairs
= new KERNINGPAIR
[nPairs
];
1585 KERNINGPAIR
* pOldPairs
= pData
->mpFontKernPairs
;
1586 pData
->mpFontKernPairs
= new KERNINGPAIR
[nPairs
+pData
->mnFontKernPairCount
];
1587 memcpy( pData
->mpFontKernPairs
, pOldPairs
,
1588 pData
->mnFontKernPairCount
*sizeof( KERNINGPAIR
) );
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];
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
;
1613 aBuf
[0] = (unsigned char)(pTempPair
->wFirst
>> 8);
1614 aBuf
[1] = (unsigned char)(pTempPair
->wFirst
& 0xFF);
1617 if ( MultiByteToWideChar( nCP
, MB_PRECOMPOSED
| MB_USEGLYPHCHARS
,
1618 (const char*)aBuf
, nLen
, &nChar
, 1 ) )
1619 pTempPair
->wFirst
= nChar
;
1623 if ( (pTempPair
->wSecond
> 125) || (pTempPair
->wSecond
== 92) )
1625 if ( pTempPair
->wSecond
< 256 )
1627 aBuf
[0] = (unsigned char)pTempPair
->wSecond
;
1632 aBuf
[0] = (unsigned char)(pTempPair
->wSecond
>> 8);
1633 aBuf
[1] = (unsigned char)(pTempPair
->wSecond
& 0xFF);
1636 if ( MultiByteToWideChar( nCP
, MB_PRECOMPOSED
| MB_USEGLYPHCHARS
,
1637 (const char*)aBuf
, nLen
, &nChar
, 1 ) )
1638 pTempPair
->wSecond
= nChar
;
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
) )
1658 KERNINGPAIR
* pDestPair
= pData
->mpFontKernPairs
+pData
->mnFontKernPairCount
;
1659 if ( pDestPair
!= pTempPair
)
1660 memcpy( pDestPair
, pTempPair
, sizeof( KERNINGPAIR
) );
1661 pData
->mnFontKernPairCount
++;
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
);
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
);
1700 #endif // GCP_KERN_HACK
1705 if ( !mnFontCharSetCount
)
1706 ImplGetAllFontCharSets( this );
1708 if ( mnFontCharSetCount
<= 1 )
1709 ImplAddKerningPairs( this );
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
);
1731 return mnFontKernPairCount
;
1732 else if( mpFontKernPairs
)
1734 if ( nPairs
< mnFontKernPairCount
)
1735 nPairs
= mnFontKernPairCount
;
1736 memcpy( pKernPairs
, mpFontKernPairs
,
1737 nPairs
*sizeof( ImplKernPairData
) );
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;
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
;
1785 // ignore non-scalable non-device font on printer
1786 if( pInfo
->mbPrinter
)
1787 if( (nFontType
& RASTER_FONTTYPE
) && !(nFontType
& DEVICE_FONTTYPE
) )
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
);
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;
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
;
1841 // ignore non-scalable non-device font on printer
1842 if( pInfo
->mbPrinter
)
1843 if( (nFontType
& RASTER_FONTTYPE
) && !(nFontType
& DEVICE_FONTTYPE
) )
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
);
1859 // -----------------------------------------------------------------------
1863 ::rtl::OUString maFontFilePath
;
1864 ::rtl::OString maResourcePath
;
1865 TempFontItem
* mpNextItem
;
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" );
1880 pFunc
= reinterpret_cast<AddFontResourceExW_FUNC
>( GetProcAddress( hmGDI
, "AddFontResourceExW" ) );
1884 return pFunc( lpszfileName
, fl
, pdv
);
1887 SetLastError( ERROR_CALL_NOT_IMPLEMENTED
);
1893 bool ImplAddTempFont( SalData
& rSalData
, const String
& rFontFileURL
)
1896 ::rtl::OUString aUSytemPath
;
1897 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL
, aUSytemPath
) );
1900 nRet
= __AddFontResourceExW( reinterpret_cast<LPCWSTR
>(aUSytemPath
.getStr()), FR_PRIVATE
, NULL
);
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
) )
1924 nRet
= ::AddFontResourceA( aResourceName
);
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
;
1938 // -----------------------------------------------------------------------
1940 void ImplReleaseTempFonts( SalData
& rSalData
)
1943 while( TempFontItem
* p
= rSalData
.mpTempFontItem
)
1946 if( p
->maResourcePath
.getLength() )
1948 const char* pResourcePath
= p
->maResourcePath
.getStr();
1949 ::RemoveFontResourceA( pResourcePath
);
1950 ::DeleteFileA( pResourcePath
);
1954 if( aSalShlData
.mbWNT
)
1955 ::RemoveFontResourceW( reinterpret_cast<LPCWSTR
>(p
->maFontFilePath
.getStr()) );
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
];
1964 ::RemoveFontResourceA( pNameA
);
1969 rSalData
.mpTempFontItem
= p
->mpNextItem
;
1974 // notify every other application
1975 // unless the temp fonts were installed as private fonts
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
)
2024 sal_uInt64 nBytesRead
= 0;
2026 aFotFile
.read( aBuffer
, sizeof( aBuffer
), nBytesRead
);
2027 // clean up temporary resource file
2029 ::DeleteFileA( aResourceName
);
2031 // retrieve font family name from byte offset 0x4F6
2034 while( (i
< nBytesRead
) && (aBuffer
[i
++] != 0) );
2036 while( (i
< nBytesRead
) && (aBuffer
[i
++] != 0) );
2037 // retrieve font style name
2039 while( (i
< nBytesRead
) && (aBuffer
[i
++] != 0) );
2040 if( i
>= nBytesRead
)
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
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() )
2105 // remember temp font for cleanup later
2106 if( !ImplAddTempFont( *GetSalData(), rFontFileURL
) )
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
);
2146 // -----------------------------------------------------------------------
2148 void WinSalGraphics::GetDevFontList( ImplDevFontList
* pFontList
)
2150 // make sure all fonts are registered at least temporarily
2151 static bool bOnce
= true;
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
;
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;
2209 aInfo
.mbImplSalCourierScalable
= false;
2210 aInfo
.mbImplSalCourierNew
= false;
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
)
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 );
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
2247 bImplSalCourierScalable
= aInfo
.mbImplSalCourierScalable
;
2248 bImplSalCourierNew
= aInfo
.mbImplSalCourierNew
;
2252 // ----------------------------------------------------------------------------
2254 void WinSalGraphics::GetDevFontSubstList( OutputDevice
* )
2257 // -----------------------------------------------------------------------
2259 BOOL
WinSalGraphics::GetGlyphBoundRect( long nIndex
, Rectangle
& rRect
)
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
;
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
)
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() );
2294 // -----------------------------------------------------------------------
2296 BOOL
WinSalGraphics::GetGlyphOutline( long nIndex
,
2297 ::basegfx::B2DPolyPolygon
& rB2DPolyPoly
)
2299 rB2DPolyPoly
.clear();
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
2323 else if( nSize1
!= GDI_ERROR
)
2325 BYTE
* pData
= new BYTE
[ nSize1
];
2327 if ( aSalShlData
.mbWNT
)
2328 nSize2
= ::GetGlyphOutlineW( hDC
, nIndex
, nGGOFlags
,
2329 &aGlyphMetrics
, nSize1
, pData
, &aMat
);
2331 nSize2
= ::GetGlyphOutlineA( hDC
, nIndex
, nGGOFlags
,
2332 &aGlyphMetrics
, nSize1
, pData
, &aMat
);
2334 if( nSize1
== nSize2
)
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
)
2349 // get start point; next start points are end points
2350 // of previous segment
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
;
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
);
2388 pPoints
[ nPnt
] = Point( nX
, nY
);
2389 pFlags
[ nPnt
] = POLY_NORMAL
;
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
);
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
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
);
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
;
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];
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() );
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
);
2491 // -----------------------------------------------------------------------
2496 explicit ScopedFont(WinSalGraphics
& rData
);
2501 WinSalGraphics
& m_rData
;
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()
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
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
; }
2535 TrueTypeFont
* m_pFont
;
2538 ScopedTrueTypeFont::~ScopedTrueTypeFont()
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);
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
2574 TEXTMETRICA aWinMetric
;
2575 if( !::GetTextMetricsA( mhDC
, &aWinMetric
) )
2578 DBG_ASSERT( !(aWinMetric
.tmPitchAndFamily
& TMPF_DEVICE
), "cannot subset device font" );
2579 DBG_ASSERT( aWinMetric
.tmPitchAndFamily
& TMPF_TRUETYPE
, "can only subset TT font" );
2582 rtl::OUString aSysPath
;
2583 if( osl_File_E_None
!= osl_getSystemPathFromFileURL( rToFile
.pData
, &aSysPath
.pData
) )
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
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
);
2616 // get raw font file data
2617 const RawFontData
xRawFontData( mhDC
, NULL
);
2618 if( !xRawFontData
.get() )
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
);
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 ];
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
);
2667 nNotDef
= i
; // first NotDef glyph found
2672 // add fake NotDef glyph if needed
2674 nNotDef
= nGlyphCount
++;
2676 // NotDef glyph must be in pos 0 => swap glyphids
2677 aShortIDs
[ nNotDef
] = aShortIDs
[0];
2678 aTempEncs
[ nNotDef
] = aTempEncs
[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
);
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
;
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() )
2722 // get important font properties
2724 if( !::GetTextMetricsA( mhDC
, &aTm
) )
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 )
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
)
2745 const sal_Unicode cChar
= pUnicodes
[i
];
2746 if( !::GetCharWidth32W( mhDC
, cChar
, cChar
, &nCharWidth
) )
2748 pCharWidths
[i
] = nCharWidth
;
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() )
2773 // fill the encoding vector
2774 // currently no nonencoded vector
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
;
2784 // TODO: get correct encoding vector
2786 aGlyphSet
.cbThis
= sizeof(aGlyphSet
);
2787 DWORD aW
= ::GetFontUnicodeRanges( mhDC
, &aGlyphSet
);
2789 for( sal_Unicode i
= 32; i
< 256; ++i
)
2790 (*pNewEncoding
)[i
] = i
;
2792 pWinFontData
->SetEncodingVector( pNewEncoding
);
2793 pEncoding
= pNewEncoding
;
2799 //--------------------------------------------------------------------------
2801 void WinSalGraphics::GetGlyphWidths( const ImplFontData
* pFont
,
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);
2815 ImplDoSetFont( &aIFSD
, fScale
, hOldFont
);
2817 if( pFont
->IsSubsettable() )
2819 // get raw font file data
2820 const RawFontData
xRawFontData( mhDC
);
2821 if( !xRawFontData
.get() )
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
);
2834 int nGlyphs
= GetTTGlyphCount( aSftTTF
.get() );
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(),
2844 bVertical
? 1 : 0 );
2847 for( int i
= 0; i
< nGlyphs
; i
++ )
2848 rWidths
[i
] = pMetrics
[i
].adv
;
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 );
2866 rUnicodeEnc
[ static_cast<sal_Unicode
>(nChar
) ] = nGlyph
;
2868 nChar
= pMap
->GetNextChar( nChar
);
2872 else if( pFont
->IsEmbeddable() )
2874 // get individual character widths
2876 rUnicodeEnc
.clear();
2877 rWidths
.reserve( 224 );
2878 for( sal_Unicode i
= 32; i
< 256; ++i
)
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",
2915 return aSysFontData
;
2918 //--------------------------------------------------------------------------