1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/types.h>
21 #include <config_folders.h>
30 #include <basegfx/matrix/b2dhommatrixtools.hxx>
31 #include <basegfx/polygon/b2dpolygon.hxx>
32 #include <i18nlangtag/mslangid.hxx>
33 #include <osl/file.hxx>
34 #include <osl/process.h>
35 #include <rtl/bootstrap.hxx>
36 #include <tools/helpers.hxx>
37 #include <tools/stream.hxx>
38 #include <unotools/fontcfg.hxx>
39 #include <vcl/settings.hxx>
40 #include <vcl/sysdata.hxx>
41 #include <vcl/metric.hxx>
42 #include <vcl/fontcharmap.hxx>
43 #include <vcl/opengl/OpenGLWrapper.hxx>
45 #include "fontsubset.hxx"
47 #include "PhysicalFontCollection.hxx"
48 #include "PhysicalFontFace.hxx"
50 #include "win/saldata.hxx"
51 #include "win/salgdi.h"
52 #include "impfontcharmap.hxx"
53 #include "impfontmetricdata.hxx"
57 static const int MAXFONTHEIGHT
= 2048;
60 inline FIXED
FixedFromDouble( double d
)
62 const long l
= (long) ( d
* 65536. );
63 return *reinterpret_cast<FIXED
const *>(&l
);
66 inline int IntTimes256FromFixed(FIXED f
)
68 int nFixedTimes256
= (f
.value
<< 8) + ((f
.fract
+0x80) >> 8);
69 return nFixedTimes256
;
72 // raw font data with a scoped lifetime
76 explicit RawFontData( HDC
, DWORD nTableTag
=0 );
77 ~RawFontData() { delete[] mpRawBytes
; }
78 const unsigned char* get() const { return mpRawBytes
; }
79 const unsigned char* steal() { unsigned char* p
= mpRawBytes
; mpRawBytes
= nullptr; return p
; }
80 int size() const { return mnByteCount
; }
83 unsigned char* mpRawBytes
;
87 RawFontData::RawFontData( HDC hDC
, DWORD nTableTag
)
88 : mpRawBytes( nullptr )
91 // get required size in bytes
92 mnByteCount
= ::GetFontData( hDC
, nTableTag
, 0, nullptr, 0 );
93 if (mnByteCount
== GDI_ERROR
)
99 mpRawBytes
= new unsigned char[ mnByteCount
];
101 // get raw data in chunks small enough for GetFontData()
102 unsigned nRawDataOfs
= 0;
103 DWORD nMaxChunkSize
= 0x100000;
106 // calculate remaining raw data to get
107 DWORD nFDGet
= mnByteCount
- nRawDataOfs
;
110 // #i56745# limit GetFontData requests
111 if( nFDGet
> nMaxChunkSize
)
112 nFDGet
= nMaxChunkSize
;
113 const DWORD nFDGot
= ::GetFontData( hDC
, nTableTag
, nRawDataOfs
,
114 mpRawBytes
+ nRawDataOfs
, nFDGet
);
117 else if( nFDGot
!= GDI_ERROR
)
118 nRawDataOfs
+= nFDGot
;
121 // was the chunk too big? reduce it
123 if( nMaxChunkSize
< 0x10000 )
128 // cleanup if the raw data is incomplete
129 if( nRawDataOfs
!= mnByteCount
)
132 mpRawBytes
= nullptr;
136 // platform specific font substitution hooks for glyph fallback enhancement
138 class WinPreMatchFontSubstititution
139 : public ImplPreMatchFontSubstitution
142 bool FindFontSubstitute(FontSelectPattern
&) const override
;
145 class WinGlyphFallbackSubstititution
146 : public ImplGlyphFallbackFontSubstitution
149 explicit WinGlyphFallbackSubstititution()
151 mhDC
= GetDC(nullptr);
154 ~WinGlyphFallbackSubstititution() override
156 ReleaseDC(nullptr, mhDC
);
159 bool FindFontSubstitute( FontSelectPattern
&, OUString
& rMissingChars
) const override
;
162 bool HasMissingChars(PhysicalFontFace
*, OUString
& rMissingChars
) const;
165 // does a font face hold the given missing characters?
166 bool WinGlyphFallbackSubstititution::HasMissingChars(PhysicalFontFace
* pFace
, OUString
& rMissingChars
) const
168 WinFontFace
* pWinFont
= static_cast< WinFontFace
* >(pFace
);
169 FontCharMapRef xFontCharMap
= pWinFont
->GetFontCharMap();
170 if( !xFontCharMap
.Is() )
172 // construct a Size structure as the parameter of constructor of class FontSelectPattern
173 const Size
aSize( pFace
->GetWidth(), pFace
->GetHeight() );
174 // create a FontSelectPattern object for getting s LOGFONT
175 const FontSelectPattern
aFSD( *pFace
, aSize
, (float)aSize
.Height(), 0, false );
176 // construct log font
178 ImplGetLogFontFromFontSelect( mhDC
, &aFSD
, aLogFont
, true );
180 // create HFONT from log font
181 HFONT hNewFont
= ::CreateFontIndirectW( &aLogFont
);
182 // select the new font into device
183 HFONT hOldFont
= ::SelectFont( mhDC
, hNewFont
);
185 // read CMAP table to update their xFontCharMap
186 pWinFont
->UpdateFromHDC( mhDC
);
188 // cleanup temporary font
189 ::SelectFont( mhDC
, hOldFont
);
190 ::DeleteFont( hNewFont
);
192 // get the new charmap
193 xFontCharMap
= pWinFont
->GetFontCharMap();
196 // avoid fonts with unknown CMAP subtables for glyph fallback
197 if( !xFontCharMap
.Is() || xFontCharMap
->IsDefaultMap() )
201 std::vector
<sal_UCS4
> rRemainingCodes
;
202 const sal_Int32 nStrLen
= rMissingChars
.getLength();
203 sal_Int32 nStrIdx
= 0;
204 while (nStrIdx
< nStrLen
)
206 const sal_UCS4 uChar
= rMissingChars
.iterateCodePoints( &nStrIdx
);
207 if (xFontCharMap
->HasChar(uChar
))
210 rRemainingCodes
.push_back(uChar
);
213 xFontCharMap
= nullptr;
216 rMissingChars
= OUString(rRemainingCodes
.data(), rRemainingCodes
.size());
218 return nMatchCount
> 0;
223 //used by 2-level font fallback
224 PhysicalFontFamily
* findDevFontListByLocale(const PhysicalFontCollection
&rFontCollection
,
225 const LanguageTag
& rLanguageTag
)
227 // get the default font for a specified locale
228 const utl::DefaultFontConfiguration
& rDefaults
= utl::DefaultFontConfiguration::get();
229 const OUString aDefault
= rDefaults
.getUserInterfaceFont(rLanguageTag
);
230 return rFontCollection
.FindFontFamilyByTokenNames(aDefault
);
234 // These are Win 3.1 bitmap fonts using "FON" font format
235 // which is not supported with "Direct Write" so let's substitute them
236 // with a font that is supported and always available.
238 // https://dxr.mozilla.org/mozilla-esr10/source/gfx/thebes/gfxDWriteFontList.cpp#1057
239 static const std::map
<OUString
, OUString
> aBitmapFontSubs
=
241 { "MS Sans Serif", "Microsoft Sans Serif" },
242 { "MS Serif", "Times New Roman" },
243 { "Small Fonts", "Arial" },
244 { "Courier", "Courier New" },
245 { "Roman", "Times New Roman" },
246 { "Script", "Mistral" }
249 // TODO: See if Windows have API that we can use here to improve font fallback.
250 bool WinPreMatchFontSubstititution::FindFontSubstitute(FontSelectPattern
& rFontSelData
) const
252 if (rFontSelData
.IsSymbolFont() || IsStarSymbol(rFontSelData
.maSearchName
))
255 for (const auto& aSub
: aBitmapFontSubs
)
257 if (rFontSelData
.maSearchName
== GetEnglishSearchFontName(aSub
.first
))
259 rFontSelData
.maSearchName
= aSub
.second
;
267 // find a fallback font for missing characters
268 // TODO: should stylistic matches be searched and preferred?
269 bool WinGlyphFallbackSubstititution::FindFontSubstitute( FontSelectPattern
& rFontSelData
, OUString
& rMissingChars
) const
271 // guess a locale matching to the missing chars
272 LanguageType eLang
= rFontSelData
.meLanguage
;
273 LanguageTag
aLanguageTag( eLang
);
275 // fall back to default UI locale if the font language is inconclusive
276 if( eLang
== LANGUAGE_DONTKNOW
)
277 aLanguageTag
= Application::GetSettings().GetUILanguageTag();
279 // first level fallback:
280 // try use the locale specific default fonts defined in VCL.xcu
281 const PhysicalFontCollection
* pFontCollection
= ImplGetSVData()->maGDIData
.mpScreenFontList
;
282 PhysicalFontFamily
* pFontFamily
= findDevFontListByLocale(*pFontCollection
, aLanguageTag
);
285 PhysicalFontFace
* pFace
= pFontFamily
->FindBestFontFace( rFontSelData
);
286 if( HasMissingChars( pFace
, rMissingChars
) )
288 rFontSelData
.maSearchName
= pFontFamily
->GetSearchName();
293 // are the missing characters symbols?
294 pFontFamily
= pFontCollection
->FindFontFamilyByAttributes( ImplFontAttrs::Symbol
,
295 rFontSelData
.GetWeight(),
296 rFontSelData
.GetWidthType(),
297 rFontSelData
.GetItalic(),
298 rFontSelData
.maSearchName
);
301 PhysicalFontFace
* pFace
= pFontFamily
->FindBestFontFace( rFontSelData
);
302 if( HasMissingChars( pFace
, rMissingChars
) )
304 rFontSelData
.maSearchName
= pFontFamily
->GetSearchName();
309 // last level fallback, check each font type face one by one
310 ImplDeviceFontList
* pTestFontList
= pFontCollection
->GetDeviceFontList();
311 // limit the count of fonts to be checked to prevent hangs
312 static const int MAX_GFBFONT_COUNT
= 600;
313 int nTestFontCount
= pTestFontList
->Count();
314 if( nTestFontCount
> MAX_GFBFONT_COUNT
)
315 nTestFontCount
= MAX_GFBFONT_COUNT
;
318 for( int i
= 0; i
< nTestFontCount
; ++i
)
320 PhysicalFontFace
* pFace
= pTestFontList
->Get( i
);
321 bFound
= HasMissingChars( pFace
, rMissingChars
);
324 rFontSelData
.maSearchName
= pFace
->GetFamilyName();
328 delete pTestFontList
;
336 PhysicalFontCollection
* mpList
;
338 LOGFONTA
* mpLogFontA
;
339 LOGFONTW
* mpLogFontW
;
340 UINT mnPreferredCharSet
;
345 static rtl_TextEncoding
ImplCharSetToSal( BYTE nCharSet
)
347 rtl_TextEncoding eTextEncoding
;
349 if ( nCharSet
== OEM_CHARSET
)
351 UINT nCP
= (sal_uInt16
)GetOEMCP();
354 // It is unclear why these two (undefined?) code page numbers are
355 // handled specially here:
356 case 1004: eTextEncoding
= RTL_TEXTENCODING_MS_1252
; break;
357 case 65400: eTextEncoding
= RTL_TEXTENCODING_SYMBOL
; break;
359 eTextEncoding
= rtl_getTextEncodingFromWindowsCodePage(nCP
);
366 eTextEncoding
= rtl_getTextEncodingFromWindowsCharset( nCharSet
);
368 eTextEncoding
= RTL_TEXTENCODING_UNICODE
;
371 return eTextEncoding
;
374 static FontFamily
ImplFamilyToSal( BYTE nFamily
)
376 switch ( nFamily
& 0xF0 )
379 return FAMILY_DECORATIVE
;
382 return FAMILY_MODERN
;
388 return FAMILY_SCRIPT
;
397 return FAMILY_DONTKNOW
;
400 static BYTE
ImplFamilyToWin( FontFamily eFamily
)
404 case FAMILY_DECORATIVE
:
405 return FF_DECORATIVE
;
429 static FontWeight
ImplWeightToSal( int nWeight
)
431 if ( nWeight
<= FW_THIN
)
433 else if ( nWeight
<= FW_ULTRALIGHT
)
434 return WEIGHT_ULTRALIGHT
;
435 else if ( nWeight
<= FW_LIGHT
)
437 else if ( nWeight
< FW_MEDIUM
)
438 return WEIGHT_NORMAL
;
439 else if ( nWeight
== FW_MEDIUM
)
440 return WEIGHT_MEDIUM
;
441 else if ( nWeight
<= FW_SEMIBOLD
)
442 return WEIGHT_SEMIBOLD
;
443 else if ( nWeight
<= FW_BOLD
)
445 else if ( nWeight
<= FW_ULTRABOLD
)
446 return WEIGHT_ULTRABOLD
;
451 static int ImplWeightToWin( FontWeight eWeight
)
458 case WEIGHT_ULTRALIGHT
:
459 return FW_ULTRALIGHT
;
464 case WEIGHT_SEMILIGHT
:
471 case WEIGHT_SEMIBOLD
:
477 case WEIGHT_ULTRABOLD
:
490 inline FontPitch
ImplLogPitchToSal( BYTE nPitch
)
492 if ( nPitch
& FIXED_PITCH
)
495 return PITCH_VARIABLE
;
498 inline FontPitch
ImplMetricPitchToSal( BYTE nPitch
)
500 // Grrrr! See NT help
501 if ( !(nPitch
& TMPF_FIXED_PITCH
) )
504 return PITCH_VARIABLE
;
507 inline BYTE
ImplPitchToWin( FontPitch ePitch
)
509 if ( ePitch
== PITCH_FIXED
)
511 else if ( ePitch
== PITCH_VARIABLE
)
512 return VARIABLE_PITCH
;
514 return DEFAULT_PITCH
;
517 static FontAttributes
WinFont2DevFontAttributes( const ENUMLOGFONTEXW
& rEnumFont
,
518 const NEWTEXTMETRICW
& rMetric
)
522 const LOGFONTW rLogFont
= rEnumFont
.elfLogFont
;
524 // get font face attributes
525 aDFA
.SetFamilyType(ImplFamilyToSal( rLogFont
.lfPitchAndFamily
));
526 aDFA
.SetWidthType(WIDTH_DONTKNOW
);
527 aDFA
.SetWeight(ImplWeightToSal( rLogFont
.lfWeight
));
528 aDFA
.SetItalic((rLogFont
.lfItalic
) ? ITALIC_NORMAL
: ITALIC_NONE
);
529 aDFA
.SetPitch(ImplLogPitchToSal( rLogFont
.lfPitchAndFamily
));
530 aDFA
.SetSymbolFlag(rLogFont
.lfCharSet
== SYMBOL_CHARSET
);
532 // get the font face name
533 aDFA
.SetFamilyName(OUString(reinterpret_cast<const sal_Unicode
*>(rLogFont
.lfFaceName
)));
535 // use the face's style name only if it looks reasonable
536 const wchar_t* pStyleName
= rEnumFont
.elfStyle
;
537 const wchar_t* pEnd
= pStyleName
+ sizeof(rEnumFont
.elfStyle
)/sizeof(*rEnumFont
.elfStyle
);
538 const wchar_t* p
= pStyleName
;
539 for(; *p
&& (p
< pEnd
); ++p
)
543 aDFA
.SetStyleName(OUString(reinterpret_cast<const sal_Unicode
*>(pStyleName
)));
545 // heuristics for font quality
546 // - opentypeTT > truetype
547 aDFA
.SetQuality( 0 );
548 if( rMetric
.tmPitchAndFamily
& TMPF_TRUETYPE
)
549 aDFA
.IncreaseQualityBy( 50 );
550 if( 0 != (rMetric
.ntmFlags
& (NTM_TT_OPENTYPE
| NTM_PS_OPENTYPE
)) )
551 aDFA
.IncreaseQualityBy( 10 );
553 // TODO: add alias names
558 static WinFontFace
* ImplLogMetricToDevFontDataW( const ENUMLOGFONTEXW
* pLogFont
,
559 const NEWTEXTMETRICW
* pMetric
,
563 if ( nFontType
& RASTER_FONTTYPE
)
564 nHeight
= pMetric
->tmHeight
- pMetric
->tmInternalLeading
;
566 WinFontFace
* pData
= new WinFontFace(
567 WinFont2DevFontAttributes(*pLogFont
, *pMetric
),
569 pLogFont
->elfLogFont
.lfCharSet
,
570 pMetric
->tmPitchAndFamily
);
575 void ImplSalLogFontToFontW( HDC hDC
, const LOGFONTW
& rLogFont
, Font
& rFont
)
577 OUString
aFontName( reinterpret_cast<const sal_Unicode
*>(rLogFont
.lfFaceName
) );
578 if (!aFontName
.isEmpty())
580 rFont
.SetFamilyName( aFontName
);
581 rFont
.SetCharSet( ImplCharSetToSal( rLogFont
.lfCharSet
) );
582 rFont
.SetFamily( ImplFamilyToSal( rLogFont
.lfPitchAndFamily
) );
583 rFont
.SetPitch( ImplLogPitchToSal( rLogFont
.lfPitchAndFamily
) );
584 rFont
.SetWeight( ImplWeightToSal( rLogFont
.lfWeight
) );
586 long nFontHeight
= rLogFont
.lfHeight
;
587 if ( nFontHeight
< 0 )
588 nFontHeight
= -nFontHeight
;
589 long nDPIY
= GetDeviceCaps( hDC
, LOGPIXELSY
);
593 nFontHeight
+= nDPIY
/2;
594 nFontHeight
/= nDPIY
;
595 rFont
.SetFontSize( Size( 0, nFontHeight
) );
596 rFont
.SetOrientation( (short)rLogFont
.lfEscapement
);
597 if ( rLogFont
.lfItalic
)
598 rFont
.SetItalic( ITALIC_NORMAL
);
600 rFont
.SetItalic( ITALIC_NONE
);
601 if ( rLogFont
.lfUnderline
)
602 rFont
.SetUnderline( LINESTYLE_SINGLE
);
604 rFont
.SetUnderline( LINESTYLE_NONE
);
605 if ( rLogFont
.lfStrikeOut
)
606 rFont
.SetStrikeout( STRIKEOUT_SINGLE
);
608 rFont
.SetStrikeout( STRIKEOUT_NONE
);
612 WinFontFace::WinFontFace( const FontAttributes
& rDFS
,
613 int nHeight
, BYTE eWinCharSet
, BYTE nPitchAndFamily
)
614 : PhysicalFontFace( rDFS
),
616 mbHasCJKSupport( false ),
617 mbHasArabicSupport ( false ),
618 mbFontCapabilitiesRead( false ),
619 mxUnicodeMap( nullptr ),
620 mpEncodingVector( nullptr ),
621 meWinCharSet( eWinCharSet
),
622 mnPitchAndFamily( nPitchAndFamily
),
623 mbAliasSymbolsHigh( false ),
624 mbAliasSymbolsLow( false ),
628 SetBitmapSize( 0, nHeight
);
630 if( eWinCharSet
== SYMBOL_CHARSET
)
632 if( (nPitchAndFamily
& TMPF_TRUETYPE
) != 0 )
634 // truetype fonts need their symbols as U+F0xx
635 mbAliasSymbolsHigh
= true;
637 else if( (nPitchAndFamily
& (TMPF_VECTOR
|TMPF_DEVICE
))
638 == (TMPF_VECTOR
|TMPF_DEVICE
) )
640 // scalable device fonts (e.g. builtin printer fonts)
641 // need their symbols as U+00xx
642 mbAliasSymbolsLow
= true;
644 else if( (nPitchAndFamily
& (TMPF_VECTOR
|TMPF_TRUETYPE
)) == 0 )
646 // bitmap fonts need their symbols as U+F0xx
647 mbAliasSymbolsHigh
= true;
651 fprintf(grLog(), "WinFontFace::WinFontFace() %lx\n", (unsigned long)this);
655 WinFontFace::~WinFontFace()
657 if( mxUnicodeMap
.Is() )
658 mxUnicodeMap
= nullptr;
660 delete mpEncodingVector
;
663 hb_font_destroy( mpHbFont
);
666 sal_IntPtr
WinFontFace::GetFontId() const
671 static unsigned GetUInt( const unsigned char* p
) { return((p
[0]<<24)+(p
[1]<<16)+(p
[2]<<8)+p
[3]);}
672 static inline DWORD
CalcTag( const char p
[5]) { return (p
[0]+(p
[1]<<8)+(p
[2]<<16)+(p
[3]<<24)); }
674 void WinFontFace::UpdateFromHDC( HDC hDC
) const
676 // short circuit if already initialized
677 if( mxUnicodeMap
.Is() )
680 ReadCmapTable( hDC
);
681 GetFontCapabilities( hDC
);
684 bool WinFontFace::HasGSUBstitutions( HDC hDC
) const
687 ReadGsubTable( hDC
);
688 return !maGsubTable
.empty();
691 bool WinFontFace::IsGSUBstituted( sal_UCS4 cChar
) const
693 return( maGsubTable
.find( cChar
) != maGsubTable
.end() );
696 FontCharMapRef
WinFontFace::GetFontCharMap() const
701 bool WinFontFace::GetFontCapabilities(vcl::FontCapabilities
&rFontCapabilities
) const
703 rFontCapabilities
= maFontCapabilities
;
704 return rFontCapabilities
.oUnicodeRange
|| rFontCapabilities
.oCodePageRange
;
707 void WinFontFace::ReadGsubTable( HDC hDC
) const
711 // check the existence of a GSUB table
712 const DWORD GsubTag
= CalcTag( "GSUB" );
713 DWORD nRC
= ::GetFontData( hDC
, GsubTag
, 0, nullptr, 0 );
714 if( (nRC
== GDI_ERROR
) || !nRC
)
717 // parse the GSUB table through sft
718 // TODO: parse it directly
720 // sft needs the full font file data => get it
721 const RawFontData
aRawFontData( hDC
);
722 if( !aRawFontData
.get() )
726 sal_uInt32 nFaceNum
= 0;
727 if( !*aRawFontData
.get() ) // TTC candidate
728 nFaceNum
= ~0U; // indicate "TTC font extracts only"
730 TrueTypeFont
* pTTFont
= nullptr;
731 ::OpenTTFontBuffer( aRawFontData
.get(), aRawFontData
.size(), nFaceNum
, &pTTFont
);
735 // add vertically substituted characters to list
736 static const sal_Unicode aGSUBCandidates
[] = {
737 0x0020, 0x0080, // ASCII
738 0x2000, 0x2600, // misc
739 0x3000, 0x3100, // CJK punctutation
740 0x3300, 0x3400, // squared words
741 0xFF00, 0xFFF0, // halfwidth|fullwidth forms
744 for( const sal_Unicode
* pPair
= aGSUBCandidates
; *pPair
; pPair
+= 2 )
745 for( sal_Unicode cChar
= pPair
[0]; cChar
< pPair
[1]; ++cChar
)
746 if( ::MapChar( pTTFont
, cChar
, false ) != ::MapChar( pTTFont
, cChar
, true ) )
747 maGsubTable
.insert( cChar
); // insert GSUBbed unicodes
749 CloseTTFont( pTTFont
);
752 void WinFontFace::ReadCmapTable( HDC hDC
) const
754 if( mxUnicodeMap
.Is() )
757 bool bIsSymbolFont
= (meWinCharSet
== SYMBOL_CHARSET
);
758 // get the CMAP table from the font which is selected into the DC
759 const DWORD nCmapTag
= CalcTag( "cmap" );
760 const RawFontData
aRawFontData( hDC
, nCmapTag
);
761 // parse the CMAP table if available
762 if( aRawFontData
.get() ) {
764 ParseCMAP( aRawFontData
.get(), aRawFontData
.size(), aResult
);
765 aResult
.mbSymbolic
= bIsSymbolFont
;
766 if( aResult
.mnRangeCount
> 0 )
768 FontCharMapRef
pUnicodeMap(new FontCharMap(aResult
));
769 mxUnicodeMap
= pUnicodeMap
;
773 if( !mxUnicodeMap
.Is() )
775 mxUnicodeMap
= FontCharMap::GetDefaultMap( bIsSymbolFont
);
779 void WinFontFace::GetFontCapabilities( HDC hDC
) const
781 // read this only once per font
782 if( mbFontCapabilitiesRead
)
785 mbFontCapabilitiesRead
= true;
789 const DWORD GsubTag
= CalcTag( "GSUB" );
790 nLength
= ::GetFontData( hDC
, GsubTag
, 0, nullptr, 0 );
791 if( (nLength
!= GDI_ERROR
) && nLength
)
793 std::vector
<unsigned char> aTable( nLength
);
794 unsigned char* pTable
= &aTable
[0];
795 ::GetFontData( hDC
, GsubTag
, 0, pTable
, nLength
);
796 vcl::getTTScripts(maFontCapabilities
.maGSUBScriptTags
, pTable
, nLength
);
800 const DWORD OS2Tag
= CalcTag( "OS/2" );
801 nLength
= ::GetFontData( hDC
, OS2Tag
, 0, nullptr, 0 );
802 if( (nLength
!= GDI_ERROR
) && nLength
)
804 std::vector
<unsigned char> aTable( nLength
);
805 unsigned char* pTable
= &aTable
[0];
806 ::GetFontData( hDC
, OS2Tag
, 0, pTable
, nLength
);
807 if (vcl::getTTCoverage(maFontCapabilities
.oUnicodeRange
, maFontCapabilities
.oCodePageRange
, pTable
, nLength
))
809 // Check for CJK capabilities of the current font
810 // TODO, we have this info already from getTT, decode bits to
812 sal_uInt32 ulUnicodeRange1
= GetUInt( pTable
+ 42 );
813 sal_uInt32 ulUnicodeRange2
= GetUInt( pTable
+ 46 );
815 mbHasCJKSupport
= (ulUnicodeRange2
& 0x2DF00000);
816 mbHasArabicSupport
= (ulUnicodeRange1
& 0x00002000);
821 void WinSalGraphics::SetTextColor( SalColor nSalColor
)
823 COLORREF aCol
= PALETTERGB( SALCOLOR_RED( nSalColor
),
824 SALCOLOR_GREEN( nSalColor
),
825 SALCOLOR_BLUE( nSalColor
) );
828 GetSalData()->mhDitherPal
&&
829 ImplIsSysColorEntry( nSalColor
) )
831 aCol
= PALRGB_TO_RGB( aCol
);
834 ::SetTextColor( getHDC(), aCol
);
837 int CALLBACK
SalEnumQueryFontProcExW( const LOGFONTW
*,
839 DWORD
, LPARAM lParam
)
841 *reinterpret_cast<bool*>(lParam
) = true;
845 void ImplGetLogFontFromFontSelect( HDC hDC
,
846 const FontSelectPattern
* pFont
,
848 bool /*bTestVerticalAvail*/ )
851 if ( pFont
->mpFontData
)
852 aName
= pFont
->mpFontData
->GetFamilyName();
854 aName
= pFont
->GetFamilyName().getToken( 0, ';' );
856 UINT nNameLen
= aName
.getLength();
857 if ( nNameLen
> (sizeof( rLogFont
.lfFaceName
)/sizeof( wchar_t ))-1 )
858 nNameLen
= (sizeof( rLogFont
.lfFaceName
)/sizeof( wchar_t ))-1;
859 memcpy( rLogFont
.lfFaceName
, aName
.getStr(), nNameLen
*sizeof( wchar_t ) );
860 rLogFont
.lfFaceName
[nNameLen
] = 0;
862 if( !pFont
->mpFontData
)
864 rLogFont
.lfCharSet
= pFont
->IsSymbolFont() ? SYMBOL_CHARSET
: DEFAULT_CHARSET
;
865 rLogFont
.lfPitchAndFamily
= ImplPitchToWin( pFont
->GetPitch() )
866 | ImplFamilyToWin( pFont
->GetFamilyType() );
870 const WinFontFace
* pWinFontData
= static_cast<const WinFontFace
*>( pFont
->mpFontData
);
871 rLogFont
.lfCharSet
= pWinFontData
->GetCharSet();
872 rLogFont
.lfPitchAndFamily
= pWinFontData
->GetPitchAndFamily();
875 static BYTE nDefaultQuality
= NONANTIALIASED_QUALITY
;
876 if (nDefaultQuality
== NONANTIALIASED_QUALITY
)
878 if (OpenGLWrapper::isVCLOpenGLEnabled())
879 nDefaultQuality
= ANTIALIASED_QUALITY
;
881 nDefaultQuality
= DEFAULT_QUALITY
;
884 rLogFont
.lfWeight
= ImplWeightToWin( pFont
->GetWeight() );
885 rLogFont
.lfHeight
= (LONG
)-pFont
->mnHeight
;
886 rLogFont
.lfWidth
= (LONG
)pFont
->mnWidth
;
887 rLogFont
.lfUnderline
= 0;
888 rLogFont
.lfStrikeOut
= 0;
889 rLogFont
.lfItalic
= BYTE(pFont
->GetItalic() != ITALIC_NONE
);
890 rLogFont
.lfEscapement
= pFont
->mnOrientation
;
891 rLogFont
.lfOrientation
= rLogFont
.lfEscapement
;
892 rLogFont
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
893 rLogFont
.lfQuality
= nDefaultQuality
;
894 rLogFont
.lfOutPrecision
= OUT_TT_PRECIS
;
895 if ( pFont
->mnOrientation
)
896 rLogFont
.lfClipPrecision
|= CLIP_LH_ANGLES
;
898 // disable antialiasing if requested
899 if ( pFont
->mbNonAntialiased
)
900 rLogFont
.lfQuality
= NONANTIALIASED_QUALITY
;
902 // select vertical mode if requested and available
903 if ( pFont
->mbVertical
&& nNameLen
)
905 // vertical fonts start with an '@'
906 memmove( &rLogFont
.lfFaceName
[1], &rLogFont
.lfFaceName
[0],
907 sizeof(rLogFont
.lfFaceName
)-sizeof(rLogFont
.lfFaceName
[0]) );
908 rLogFont
.lfFaceName
[0] = '@';
910 // check availability of vertical mode for this font
911 bool bAvailable
= false;
912 EnumFontFamiliesExW( hDC
, &rLogFont
, SalEnumQueryFontProcExW
,
913 reinterpret_cast<LPARAM
>(&bAvailable
), 0 );
917 // restore non-vertical name if not vertical mode isn't available
918 memcpy( &rLogFont
.lfFaceName
[0], aName
.getStr(), nNameLen
*sizeof(wchar_t) );
919 if( nNameLen
< LF_FACESIZE
)
920 rLogFont
.lfFaceName
[nNameLen
] = '\0';
925 HFONT
WinSalGraphics::ImplDoSetFont( FontSelectPattern
* i_pFont
, float& o_rFontScale
, HFONT
& o_rOldFont
)
927 HFONT hNewFont
= nullptr;
929 HDC hdcScreen
= nullptr;
931 // only required for virtual devices, see below for details
932 hdcScreen
= GetDC(nullptr);
935 ImplGetLogFontFromFontSelect( getHDC(), i_pFont
, aLogFont
, true );
937 // #i47675# limit font requests to MAXFONTHEIGHT
938 // TODO: share MAXFONTHEIGHT font instance
939 if( (-aLogFont
.lfHeight
<= MAXFONTHEIGHT
)
940 && (+aLogFont
.lfWidth
<= MAXFONTHEIGHT
) )
944 else if( -aLogFont
.lfHeight
>= +aLogFont
.lfWidth
)
946 o_rFontScale
= -aLogFont
.lfHeight
/ (float)MAXFONTHEIGHT
;
947 aLogFont
.lfHeight
= -MAXFONTHEIGHT
;
948 aLogFont
.lfWidth
= FRound( aLogFont
.lfWidth
/ o_rFontScale
);
950 else // #i95867# also limit font widths
952 o_rFontScale
= +aLogFont
.lfWidth
/ (float)MAXFONTHEIGHT
;
953 aLogFont
.lfWidth
= +MAXFONTHEIGHT
;
954 aLogFont
.lfHeight
= FRound( aLogFont
.lfHeight
/ o_rFontScale
);
957 hNewFont
= ::CreateFontIndirectW( &aLogFont
);
960 // select font into screen hdc first to get an antialiased font
961 // see knowledge base article 305290:
962 // "PRB: Fonts Not Drawn Antialiased on Device Context for DirectDraw Surface"
963 SelectFont( hdcScreen
, SelectFont( hdcScreen
, hNewFont
) );
965 o_rOldFont
= ::SelectFont( getHDC(), hNewFont
);
967 TEXTMETRICW aTextMetricW
;
968 if( !::GetTextMetricsW( getHDC(), &aTextMetricW
) )
970 // the selected font doesn't work => try a replacement
971 // TODO: use its font fallback instead
972 lstrcpynW( aLogFont
.lfFaceName
, L
"Courier New", 12 );
973 aLogFont
.lfPitchAndFamily
= FIXED_PITCH
;
974 HFONT hNewFont2
= CreateFontIndirectW( &aLogFont
);
975 SelectFont( getHDC(), hNewFont2
);
976 DeleteFont( hNewFont
);
977 hNewFont
= hNewFont2
;
981 ::ReleaseDC( nullptr, hdcScreen
);
986 void WinSalGraphics::SetFont( FontSelectPattern
* pFont
, int nFallbackLevel
)
988 // return early if there is no new font
991 // deselect still active font
993 ::SelectFont( getHDC(), mhDefFont
);
994 mfCurrentFontScale
= mfFontScale
[nFallbackLevel
];
995 // release no longer referenced font handles
996 for( int i
= nFallbackLevel
; i
< MAX_FALLBACK
; ++i
)
999 ::DeleteFont( mhFonts
[i
] );
1000 mhFonts
[ i
] = nullptr;
1001 if (mpWinFontEntry
[i
])
1003 GetWinFontEntry(i
)->mpFontCache
->Release(GetWinFontEntry(i
));
1005 mpWinFontEntry
[i
] = nullptr;
1006 mpWinFontData
[i
] = nullptr;
1008 mhDefFont
= nullptr;
1012 assert(pFont
->mpFontData
);
1013 if (mpWinFontEntry
[nFallbackLevel
])
1015 GetWinFontEntry(nFallbackLevel
)->mpFontCache
->Release(GetWinFontEntry(nFallbackLevel
));
1017 // WinSalGraphics::GetEmbedFontData does not set mpFontInstance
1018 // since it is interested in font file data only.
1019 if (pFont
->mpFontInstance
)
1021 pFont
->mpFontInstance
->mpFontCache
->Acquire(pFont
->mpFontInstance
);
1023 mpWinFontEntry
[ nFallbackLevel
] = reinterpret_cast<WinFontInstance
*>( pFont
->mpFontInstance
);
1024 mpWinFontData
[ nFallbackLevel
] = static_cast<const WinFontFace
*>( pFont
->mpFontData
);
1026 HFONT hOldFont
= nullptr;
1027 HFONT hNewFont
= ImplDoSetFont( pFont
, mfFontScale
[ nFallbackLevel
], hOldFont
);
1028 mfCurrentFontScale
= mfFontScale
[nFallbackLevel
];
1032 // keep default font
1033 mhDefFont
= hOldFont
;
1037 // release no longer referenced font handles
1038 for( int i
= nFallbackLevel
; i
< MAX_FALLBACK
; ++i
)
1042 ::DeleteFont( mhFonts
[i
] );
1043 mhFonts
[i
] = nullptr;
1045 // note: removing mpWinFontEntry[i] here has obviously bad effects
1049 // store new font in correct layer
1050 mhFonts
[ nFallbackLevel
] = hNewFont
;
1051 // now the font is live => update font face
1052 if( mpWinFontData
[ nFallbackLevel
] )
1053 mpWinFontData
[ nFallbackLevel
]->UpdateFromHDC( getHDC() );
1055 if( !nFallbackLevel
)
1057 mbFontKernInit
= TRUE
;
1058 if ( mpFontKernPairs
)
1060 delete[] mpFontKernPairs
;
1061 mpFontKernPairs
= nullptr;
1063 mnFontKernPairCount
= 0;
1067 void WinSalGraphics::GetFontMetric( ImplFontMetricDataRef
& rxFontMetric
, int nFallbackLevel
)
1069 // temporarily change the HDC to the font in the fallback level
1070 HFONT hOldFont
= SelectFont( getHDC(), mhFonts
[nFallbackLevel
] );
1072 wchar_t aFaceName
[LF_FACESIZE
+60];
1073 if( ::GetTextFaceW( getHDC(), sizeof(aFaceName
)/sizeof(wchar_t), aFaceName
) )
1074 rxFontMetric
->SetFamilyName(OUString(reinterpret_cast<const sal_Unicode
*>(aFaceName
)));
1076 const DWORD nHheaTag
= CalcTag("hhea");
1077 const DWORD nOS2Tag
= CalcTag("OS/2");
1078 const RawFontData
aHheaRawData(getHDC(), nHheaTag
);
1079 const RawFontData
aOS2RawData(getHDC(), nOS2Tag
);
1081 // get the font metric
1082 OUTLINETEXTMETRICW aOutlineMetric
;
1083 TEXTMETRICW aWinMetric
;
1084 bool bOK
= GetOutlineTextMetricsW(getHDC(), sizeof(OUTLINETEXTMETRICW
), &aOutlineMetric
);
1086 aWinMetric
= aOutlineMetric
.otmTextMetrics
;
1088 bOK
= GetTextMetricsW(getHDC(), &aWinMetric
);
1089 // restore the HDC to the font in the base level
1090 SelectFont( getHDC(), hOldFont
);
1094 // device independent font attributes
1095 rxFontMetric
->SetFamilyType(ImplFamilyToSal( aWinMetric
.tmPitchAndFamily
));
1096 rxFontMetric
->SetSymbolFlag(aWinMetric
.tmCharSet
== SYMBOL_CHARSET
);
1097 rxFontMetric
->SetWeight(ImplWeightToSal( aWinMetric
.tmWeight
));
1098 rxFontMetric
->SetPitch(ImplMetricPitchToSal( aWinMetric
.tmPitchAndFamily
));
1099 rxFontMetric
->SetItalic(aWinMetric
.tmItalic
? ITALIC_NORMAL
: ITALIC_NONE
);
1100 rxFontMetric
->SetSlant( 0 );
1102 // transformation dependent font metrics
1103 rxFontMetric
->SetWidth( static_cast<int>( mfFontScale
[nFallbackLevel
] * aWinMetric
.tmAveCharWidth
) );
1105 if (aHheaRawData
.size() > 0 || aOS2RawData
.size() > 0)
1107 const std::vector
<uint8_t> rHhea(aHheaRawData
.get(), aHheaRawData
.get() + aHheaRawData
.size());
1108 const std::vector
<uint8_t> rOS2(aOS2RawData
.get(), aOS2RawData
.get() + aOS2RawData
.size());
1109 rxFontMetric
->ImplCalcLineSpacing(rHhea
, rOS2
, aOutlineMetric
.otmEMSquare
);
1113 // Falback to GDI code, can only happen with non-SFNT fonts
1114 rxFontMetric
->SetInternalLeading( static_cast<int>( mfFontScale
[nFallbackLevel
] * aWinMetric
.tmInternalLeading
) );
1115 rxFontMetric
->SetExternalLeading( static_cast<int>( mfFontScale
[nFallbackLevel
] * aWinMetric
.tmExternalLeading
) );
1116 rxFontMetric
->SetAscent( static_cast<int>( mfFontScale
[nFallbackLevel
] * aWinMetric
.tmAscent
) );
1117 rxFontMetric
->SetDescent( static_cast<int>( mfFontScale
[nFallbackLevel
] * aWinMetric
.tmDescent
) );
1118 // #107888# improved metric compatibility for Asian fonts...
1119 // TODO: assess workaround below for CWS >= extleading
1120 // TODO: evaluate use of aWinMetric.sTypo* members for CJK
1121 if( mpWinFontData
[nFallbackLevel
] && mpWinFontData
[nFallbackLevel
]->SupportsCJK() )
1123 rxFontMetric
->SetInternalLeading( rxFontMetric
->GetInternalLeading() + rxFontMetric
->GetExternalLeading() );
1125 // #109280# The line height for Asian fonts is too small.
1126 // Therefore we add half of the external leading to the
1127 // ascent, the other half is added to the descent.
1128 const long nHalfTmpExtLeading
= rxFontMetric
->GetExternalLeading() / 2;
1129 const long nOtherHalfTmpExtLeading
= rxFontMetric
->GetExternalLeading() - nHalfTmpExtLeading
;
1131 // #110641# external leading for Asian fonts.
1132 // The factor 0.3 has been confirmed with experiments.
1133 long nCJKExtLeading
= static_cast<long>(0.30 * (rxFontMetric
->GetAscent() + rxFontMetric
->GetDescent()));
1134 nCJKExtLeading
-= rxFontMetric
->GetExternalLeading();
1135 rxFontMetric
->SetExternalLeading( (nCJKExtLeading
> 0) ? nCJKExtLeading
: 0 );
1137 rxFontMetric
->SetAscent( rxFontMetric
->GetAscent() + nHalfTmpExtLeading
);
1138 rxFontMetric
->SetDescent( rxFontMetric
->GetDescent() + nOtherHalfTmpExtLeading
);
1142 rxFontMetric
->SetMinKashida( GetMinKashidaWidth() );
1145 sal_uLong
WinSalGraphics::GetKernPairs()
1147 if ( mbFontKernInit
)
1149 if( mpFontKernPairs
)
1151 delete[] mpFontKernPairs
;
1152 mpFontKernPairs
= nullptr;
1154 mnFontKernPairCount
= 0;
1156 KERNINGPAIR
* pPairs
= nullptr;
1157 int nCount
= ::GetKerningPairsW( getHDC(), 0, nullptr );
1160 pPairs
= new KERNINGPAIR
[ nCount
+1 ];
1161 mpFontKernPairs
= pPairs
;
1162 mnFontKernPairCount
= nCount
;
1163 ::GetKerningPairsW( getHDC(), nCount
, pPairs
);
1166 mbFontKernInit
= FALSE
;
1168 std::sort( mpFontKernPairs
, mpFontKernPairs
+ mnFontKernPairCount
, ImplCmpKernData
);
1171 return mnFontKernPairCount
;
1174 const FontCharMapRef
WinSalGraphics::GetFontCharMap() const
1176 if( !mpWinFontData
[0] )
1178 FontCharMapRef
xDefFontCharMap( new FontCharMap() );
1179 return xDefFontCharMap
;
1181 return mpWinFontData
[0]->GetFontCharMap();
1184 bool WinSalGraphics::GetFontCapabilities(vcl::FontCapabilities
&rFontCapabilities
) const
1186 if( !mpWinFontData
[0] )
1188 return mpWinFontData
[0]->GetFontCapabilities(rFontCapabilities
);
1191 int CALLBACK
SalEnumFontsProcExW( const LOGFONTW
* lpelfe
,
1192 const TEXTMETRICW
* lpntme
,
1193 DWORD nFontType
, LPARAM lParam
)
1195 ENUMLOGFONTEXW
const * pLogFont
1196 = reinterpret_cast<ENUMLOGFONTEXW
const *>(lpelfe
);
1197 NEWTEXTMETRICEXW
const * pMetric
1198 = reinterpret_cast<NEWTEXTMETRICEXW
const *>(lpntme
);
1199 ImplEnumInfo
* pInfo
= reinterpret_cast<ImplEnumInfo
*>(lParam
);
1200 if ( !pInfo
->mpName
)
1202 // Ignore vertical fonts
1203 if ( pLogFont
->elfLogFont
.lfFaceName
[0] != '@' )
1205 OUString aName
= OUString(reinterpret_cast<const sal_Unicode
*>(pLogFont
->elfLogFont
.lfFaceName
));
1206 pInfo
->mpName
= &aName
;
1207 memcpy( pInfo
->mpLogFontW
->lfFaceName
, pLogFont
->elfLogFont
.lfFaceName
, (aName
.getLength()+1)*sizeof( wchar_t ) );
1208 pInfo
->mpLogFontW
->lfCharSet
= pLogFont
->elfLogFont
.lfCharSet
;
1209 EnumFontFamiliesExW( pInfo
->mhDC
, pInfo
->mpLogFontW
, SalEnumFontsProcExW
,
1210 reinterpret_cast<LPARAM
>(pInfo
), 0 );
1211 pInfo
->mpLogFontW
->lfFaceName
[0] = '\0';
1212 pInfo
->mpLogFontW
->lfCharSet
= DEFAULT_CHARSET
;
1213 pInfo
->mpName
= nullptr;
1218 // Ignore non-device font on printer.
1219 if (pInfo
->mbPrinter
)
1221 if ((nFontType
& RASTER_FONTTYPE
) && !(nFontType
& DEVICE_FONTTYPE
))
1223 SAL_INFO("vcl.gdi", "Unsupported printer font ignored: " << OUString(pLogFont
->elfLogFont
.lfFaceName
));
1227 // Only SFNT fonts are supported, ignore anything else.
1228 else if (SalLayout::UseCommonLayout() || OpenGLWrapper::isVCLOpenGLEnabled())
1230 if (!(nFontType
& TRUETYPE_FONTTYPE
) &&
1231 !(pMetric
->ntmTm
.ntmFlags
& NTM_PS_OPENTYPE
) &&
1232 !(pMetric
->ntmTm
.ntmFlags
& NTM_TT_OPENTYPE
))
1234 SAL_INFO("vcl.gdi", "Unsupported font ignored: " << OUString(pLogFont
->elfLogFont
.lfFaceName
));
1239 WinFontFace
* pData
= ImplLogMetricToDevFontDataW( pLogFont
, &(pMetric
->ntmTm
), nFontType
);
1240 pData
->SetFontId( sal_IntPtr( pInfo
->mnFontCount
++ ) );
1242 pInfo
->mpList
->Add( pData
);
1250 OUString maFontFilePath
;
1251 OString maResourcePath
;
1252 TempFontItem
* mpNextItem
;
1255 bool ImplAddTempFont( SalData
& rSalData
, const OUString
& rFontFileURL
)
1258 OUString aUSytemPath
;
1259 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL
, aUSytemPath
) );
1261 nRet
= AddFontResourceExW( reinterpret_cast<LPCWSTR
>(aUSytemPath
.getStr()), FR_PRIVATE
, nullptr );
1265 static int nCounter
= 0;
1266 char aFileName
[] = "soAA.fot";
1267 aFileName
[2] = sal::static_int_cast
<char>('A' + (15 & (nCounter
>>4)));
1268 aFileName
[3] = sal::static_int_cast
<char>('A' + (15 & nCounter
));
1269 char aResourceName
[512];
1270 int nMaxLen
= sizeof(aResourceName
)/sizeof(*aResourceName
) - 16;
1271 int nLen
= ::GetTempPathA( nMaxLen
, aResourceName
);
1272 ::strncpy( aResourceName
+ nLen
, aFileName
, sizeof( aResourceName
)- nLen
);
1273 // security: end buffer in any case
1274 aResourceName
[ (sizeof(aResourceName
)/sizeof(*aResourceName
))-1 ] = 0;
1275 ::DeleteFileA( aResourceName
);
1277 rtl_TextEncoding theEncoding
= osl_getThreadTextEncoding();
1278 OString aCFileName
= OUStringToOString( aUSytemPath
, theEncoding
);
1279 // TODO: font should be private => need to investigate why it doesn't work then
1280 if( !::CreateScalableFontResourceA( 0, aResourceName
, aCFileName
.getStr(), nullptr ) )
1284 nRet
= ::AddFontResourceA( aResourceName
);
1287 TempFontItem
* pNewItem
= new TempFontItem
;
1288 pNewItem
->maResourcePath
= OString( aResourceName
);
1289 pNewItem
->maFontFilePath
= aUSytemPath
.getStr();
1290 pNewItem
->mpNextItem
= rSalData
.mpTempFontItem
;
1291 rSalData
.mpTempFontItem
= pNewItem
;
1298 void ImplReleaseTempFonts( SalData
& rSalData
)
1301 while( TempFontItem
* p
= rSalData
.mpTempFontItem
)
1304 if( p
->maResourcePath
.getLength() )
1306 const char* pResourcePath
= p
->maResourcePath
.getStr();
1307 ::RemoveFontResourceA( pResourcePath
);
1308 ::DeleteFileA( pResourcePath
);
1312 ::RemoveFontResourceW( reinterpret_cast<LPCWSTR
>(p
->maFontFilePath
.getStr()) );
1315 rSalData
.mpTempFontItem
= p
->mpNextItem
;
1320 static bool ImplGetFontAttrFromFile( const OUString
& rFontFileURL
,
1321 FontAttributes
& rDFA
)
1323 OUString aUSytemPath
;
1324 OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL
, aUSytemPath
) );
1326 // get FontAttributes from a *fot file
1327 // TODO: use GetTTGlobalFontInfo() to access the font directly
1328 rDFA
.SetQuality( 1000 );
1329 rDFA
.SetFamilyType(FAMILY_DONTKNOW
);
1330 rDFA
.SetWidthType(WIDTH_DONTKNOW
);
1331 rDFA
.SetWeight(WEIGHT_DONTKNOW
);
1332 rDFA
.SetItalic(ITALIC_DONTKNOW
);
1333 rDFA
.SetPitch(PITCH_DONTKNOW
);
1335 // Create temporary file name
1336 char aFileName
[] = "soAAT.fot";
1337 char aResourceName
[512];
1338 int nMaxLen
= sizeof(aResourceName
)/sizeof(*aResourceName
) - 16;
1339 int nLen
= ::GetTempPathA( nMaxLen
, aResourceName
);
1340 ::strncpy( aResourceName
+ nLen
, aFileName
, std::max( 0, nMaxLen
- nLen
));
1341 ::DeleteFileA( aResourceName
);
1343 // Create font resource file (typically with a .fot file name extension).
1344 rtl_TextEncoding theEncoding
= osl_getThreadTextEncoding();
1345 OString aCFileName
= OUStringToOString( aUSytemPath
, theEncoding
);
1346 ::CreateScalableFontResourceA( 0, aResourceName
, aCFileName
.getStr(), nullptr );
1348 // Open and read the font resource file
1349 OUString aFotFileName
= OStringToOUString( aResourceName
, osl_getThreadTextEncoding() );
1350 osl::FileBase::getFileURLFromSystemPath( aFotFileName
, aFotFileName
);
1351 osl::File
aFotFile( aFotFileName
);
1352 osl::FileBase::RC aError
= aFotFile
.open( osl_File_OpenFlag_Read
);
1353 if( aError
!= osl::FileBase::E_None
)
1356 sal_uInt64 nBytesRead
= 0;
1358 aFotFile
.read( aBuffer
, sizeof( aBuffer
), nBytesRead
);
1359 // clean up temporary resource file
1361 ::DeleteFileA( aResourceName
);
1363 // retrieve font family name from byte offset 0x4F6
1364 sal_uInt64 i
= 0x4F6;
1365 sal_uInt64 nNameOfs
= i
;
1366 while( (i
< nBytesRead
) && (aBuffer
[i
++] != 0) );
1368 while( (i
< nBytesRead
) && (aBuffer
[i
++] != 0) );
1369 // retrieve font style name
1371 while( (i
< nBytesRead
) && (aBuffer
[i
++] != 0) );
1372 if( i
>= nBytesRead
)
1375 // convert byte strings to unicode
1376 char *pName
= aBuffer
+ nNameOfs
;
1377 rDFA
.SetFamilyName(OUString(pName
, strlen(pName
), osl_getThreadTextEncoding()));
1378 char *pStyle
= aBuffer
+ nStyleOfs
;
1379 rDFA
.SetStyleName(OUString(pStyle
, strlen(pStyle
), osl_getThreadTextEncoding() ));
1381 // byte offset 0x4C7: OS2_fsSelection
1382 const char nFSS
= aBuffer
[ 0x4C7 ];
1383 if( nFSS
& 0x01 ) // italic
1384 rDFA
.SetItalic(ITALIC_NORMAL
);
1385 //if( nFSS & 0x20 ) // bold
1386 // rDFA.meWeight = WEIGHT_BOLD;
1387 if( nFSS
& 0x40 ) // regular
1389 rDFA
.SetWeight(WEIGHT_NORMAL
);
1390 rDFA
.SetItalic(ITALIC_NONE
);
1393 // byte offsets 0x4D7/0x4D8: wingdi's FW_WEIGHT
1394 int nWinWeight
= (aBuffer
[0x4D7] & 0xFF) + ((aBuffer
[0x4D8] & 0xFF) << 8);
1395 rDFA
.SetWeight(ImplWeightToSal( nWinWeight
));
1397 rDFA
.SetSymbolFlag(false); // TODO
1398 rDFA
.SetPitch(PITCH_DONTKNOW
); // TODO
1400 // byte offset 0x4DE: pitch&family
1401 rDFA
.SetFamilyType(ImplFamilyToSal( aBuffer
[0x4DE] ));
1403 // byte offsets 0x4C8/0x4C9: emunits
1404 // byte offsets 0x4CE/0x4CF: winascent
1405 // byte offsets 0x4D0/0x4D1: winascent+windescent-emunits
1406 // byte offsets 0x4DF/0x4E0: avgwidth
1411 bool WinSalGraphics::AddTempDevFont( PhysicalFontCollection
* pFontCollection
,
1412 const OUString
& rFontFileURL
, const OUString
& rFontName
)
1414 SAL_INFO( "vcl.gdi", "WinSalGraphics::AddTempDevFont(): " << OUStringToOString( rFontFileURL
, RTL_TEXTENCODING_UTF8
).getStr() );
1416 FontAttributes aDFA
;
1417 aDFA
.SetFamilyName(rFontName
);
1418 aDFA
.SetQuality( 1000 );
1420 // Retrieve font name from font resource
1421 if( aDFA
.GetFamilyName().isEmpty() )
1423 ImplGetFontAttrFromFile( rFontFileURL
, aDFA
);
1426 if ( aDFA
.GetFamilyName().isEmpty() )
1429 // remember temp font for cleanup later
1430 if( !ImplAddTempFont( *GetSalData(), rFontFileURL
) )
1433 // create matching FontData struct
1434 aDFA
.SetSymbolFlag(false); // TODO: how to know it without accessing the font?
1435 aDFA
.SetFamilyType(FAMILY_DONTKNOW
);
1436 aDFA
.SetWidthType(WIDTH_DONTKNOW
);
1437 aDFA
.SetWeight(WEIGHT_DONTKNOW
);
1438 aDFA
.SetItalic(ITALIC_DONTKNOW
);
1439 aDFA
.SetPitch(PITCH_DONTKNOW
);
1442 // TODO: improve FontAttributes using the "font resource file"
1443 aDFS.maName = // using "FONTRES:" from file
1444 if( rFontName != aDFS.maName )
1445 aDFS.maMapName = aFontName;
1448 WinFontFace
* pFontData
= new WinFontFace( aDFA
, 0,
1449 sal::static_int_cast
<BYTE
>(DEFAULT_CHARSET
),
1450 sal::static_int_cast
<BYTE
>(TMPF_VECTOR
|TMPF_TRUETYPE
) );
1451 pFontData
->SetFontId( reinterpret_cast<sal_IntPtr
>(pFontData
) );
1452 pFontCollection
->Add( pFontData
);
1456 void WinSalGraphics::GetDevFontList( PhysicalFontCollection
* pFontCollection
)
1458 // make sure all fonts are registered at least temporarily
1459 static bool bOnce
= true;
1464 // determine font path
1465 // since we are only interested in fonts that could not be
1466 // registered before because of missing administration rights
1467 // only the font path of the user installation is needed
1469 osl_getExecutableFile( &aPath
.pData
);
1470 aPath
= aPath
.copy( 0, aPath
.lastIndexOf('/') );
1471 OUString aFontDirUrl
= aPath
.copy( 0, aPath
.lastIndexOf('/') );
1472 aFontDirUrl
+= "/" LIBO_SHARE_FOLDER
"/fonts/truetype";
1474 // collect fonts in font path that could not be registered
1475 osl::Directory
aFontDir( aFontDirUrl
);
1476 osl::FileBase::RC rcOSL
= aFontDir
.open();
1477 if( rcOSL
== osl::FileBase::E_None
)
1479 osl::DirectoryItem aDirItem
;
1480 OUString aEmptyString
;
1482 while( aFontDir
.getNextItem( aDirItem
, 10 ) == osl::FileBase::E_None
)
1484 osl::FileStatus
aFileStatus( osl_FileStatus_Mask_FileURL
);
1485 rcOSL
= aDirItem
.getFileStatus( aFileStatus
);
1486 if ( rcOSL
== osl::FileBase::E_None
)
1487 AddTempDevFont( pFontCollection
, aFileStatus
.getFileURL(), aEmptyString
);
1493 aInfo
.mhDC
= getHDC();
1494 aInfo
.mpList
= pFontCollection
;
1495 aInfo
.mpName
= nullptr;
1496 aInfo
.mpLogFontA
= nullptr;
1497 aInfo
.mpLogFontW
= nullptr;
1498 aInfo
.mbPrinter
= mbPrinter
;
1499 aInfo
.mnFontCount
= 0;
1501 aInfo
.mnPreferredCharSet
= DEFAULT_CHARSET
;
1502 DWORD nCP
= GetACP();
1503 CHARSETINFO aCharSetInfo
;
1504 if ( TranslateCharsetInfo( reinterpret_cast<DWORD
*>((sal_IntPtr
)nCP
), &aCharSetInfo
, TCI_SRCCODEPAGE
) )
1505 aInfo
.mnPreferredCharSet
= aCharSetInfo
.ciCharset
;
1508 memset( &aLogFont
, 0, sizeof( aLogFont
) );
1509 aLogFont
.lfCharSet
= DEFAULT_CHARSET
;
1510 aInfo
.mpLogFontW
= &aLogFont
;
1511 EnumFontFamiliesExW( getHDC(), &aLogFont
,
1512 SalEnumFontsProcExW
, reinterpret_cast<LPARAM
>(&aInfo
), 0 );
1514 // set glyph fallback hook
1515 static WinGlyphFallbackSubstititution aSubstFallback
;
1516 static WinPreMatchFontSubstititution aPreMatchFont
;
1517 pFontCollection
->SetFallbackHook( &aSubstFallback
);
1518 pFontCollection
->SetPreMatchHook(&aPreMatchFont
);
1521 void WinSalGraphics::ClearDevFontCache()
1523 //anything to do here ?
1526 bool WinSalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId
, Rectangle
& rRect
)
1532 aMat
.eM11
= aMat
.eM22
= FixedFromDouble( 1.0 );
1533 aMat
.eM12
= aMat
.eM21
= FixedFromDouble( 0.0 );
1535 UINT nGGOFlags
= GGO_METRICS
;
1536 if( !(aGlyphId
& GF_ISCHAR
) )
1537 nGGOFlags
|= GGO_GLYPH_INDEX
;
1538 aGlyphId
&= GF_IDXMASK
;
1541 aGM
.gmptGlyphOrigin
.x
= aGM
.gmptGlyphOrigin
.y
= 0;
1542 aGM
.gmBlackBoxX
= aGM
.gmBlackBoxY
= 0;
1543 DWORD nSize
= ::GetGlyphOutlineW( hDC
, aGlyphId
, nGGOFlags
, &aGM
, 0, nullptr, &aMat
);
1544 if( nSize
== GDI_ERROR
)
1547 rRect
= Rectangle( Point( +aGM
.gmptGlyphOrigin
.x
, -aGM
.gmptGlyphOrigin
.y
),
1548 Size( aGM
.gmBlackBoxX
, aGM
.gmBlackBoxY
) );
1549 rRect
.Left() = static_cast<int>( mfCurrentFontScale
* rRect
.Left() );
1550 rRect
.Right() = static_cast<int>( mfCurrentFontScale
* rRect
.Right() ) + 1;
1551 rRect
.Top() = static_cast<int>( mfCurrentFontScale
* rRect
.Top() );
1552 rRect
.Bottom() = static_cast<int>( mfCurrentFontScale
* rRect
.Bottom() ) + 1;
1556 bool WinSalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId
,
1557 basegfx::B2DPolyPolygon
& rB2DPolyPoly
)
1559 rB2DPolyPoly
.clear();
1565 aMat
.eM11
= aMat
.eM22
= FixedFromDouble( 1.0 );
1566 aMat
.eM12
= aMat
.eM21
= FixedFromDouble( 0.0 );
1568 UINT nGGOFlags
= GGO_NATIVE
;
1569 if( !(aGlyphId
& GF_ISCHAR
) )
1570 nGGOFlags
|= GGO_GLYPH_INDEX
;
1571 aGlyphId
&= GF_IDXMASK
;
1573 GLYPHMETRICS aGlyphMetrics
;
1574 const DWORD nSize1
= ::GetGlyphOutlineW( hDC
, aGlyphId
, nGGOFlags
, &aGlyphMetrics
, 0, nullptr, &aMat
);
1575 if( !nSize1
) // blank glyphs are ok
1577 else if( nSize1
== GDI_ERROR
)
1580 BYTE
* pData
= new BYTE
[ nSize1
];
1581 const DWORD nSize2
= ::GetGlyphOutlineW( hDC
, aGlyphId
, nGGOFlags
,
1582 &aGlyphMetrics
, nSize1
, pData
, &aMat
);
1584 if( nSize1
!= nSize2
)
1587 // TODO: avoid tools polygon by creating B2DPolygon directly
1589 Point
* pPoints
= new Point
[ nPtSize
];
1590 PolyFlags
* pFlags
= new PolyFlags
[ nPtSize
];
1592 TTPOLYGONHEADER
* pHeader
= reinterpret_cast<TTPOLYGONHEADER
*>(pData
);
1593 while( reinterpret_cast<BYTE
*>(pHeader
) < pData
+nSize2
)
1595 // only outline data is interesting
1596 if( pHeader
->dwType
!= TT_POLYGON_TYPE
)
1599 // get start point; next start points are end points
1600 // of previous segment
1601 sal_uInt16 nPnt
= 0;
1603 long nX
= IntTimes256FromFixed( pHeader
->pfxStart
.x
);
1604 long nY
= IntTimes256FromFixed( pHeader
->pfxStart
.y
);
1605 pPoints
[ nPnt
] = Point( nX
, nY
);
1606 pFlags
[ nPnt
++ ] = PolyFlags::Normal
;
1608 bool bHasOfflinePoints
= false;
1609 TTPOLYCURVE
* pCurve
= reinterpret_cast<TTPOLYCURVE
*>( pHeader
+ 1 );
1610 pHeader
= reinterpret_cast<TTPOLYGONHEADER
*>( reinterpret_cast<BYTE
*>(pHeader
) + pHeader
->cb
);
1611 while( reinterpret_cast<BYTE
*>(pCurve
) < reinterpret_cast<BYTE
*>(pHeader
) )
1613 int nNeededSize
= nPnt
+ 16 + 3 * pCurve
->cpfx
;
1614 if( nPtSize
< nNeededSize
)
1616 Point
* pOldPoints
= pPoints
;
1617 PolyFlags
* pOldFlags
= pFlags
;
1618 nPtSize
= 2 * nNeededSize
;
1619 pPoints
= new Point
[ nPtSize
];
1620 pFlags
= new PolyFlags
[ nPtSize
];
1621 for( sal_uInt16 i
= 0; i
< nPnt
; ++i
)
1623 pPoints
[ i
] = pOldPoints
[ i
];
1624 pFlags
[ i
] = pOldFlags
[ i
];
1626 delete[] pOldPoints
;
1631 if( TT_PRIM_LINE
== pCurve
->wType
)
1633 while( i
< pCurve
->cpfx
)
1635 nX
= IntTimes256FromFixed( pCurve
->apfx
[ i
].x
);
1636 nY
= IntTimes256FromFixed( pCurve
->apfx
[ i
].y
);
1638 pPoints
[ nPnt
] = Point( nX
, nY
);
1639 pFlags
[ nPnt
] = PolyFlags::Normal
;
1643 else if( TT_PRIM_QSPLINE
== pCurve
->wType
)
1645 bHasOfflinePoints
= true;
1646 while( i
< pCurve
->cpfx
)
1648 // get control point of quadratic bezier spline
1649 nX
= IntTimes256FromFixed( pCurve
->apfx
[ i
].x
);
1650 nY
= IntTimes256FromFixed( pCurve
->apfx
[ i
].y
);
1652 Point
aControlP( nX
, nY
);
1654 // calculate first cubic control point
1655 // P0 = 1/3 * (PBeg + 2 * PQControl)
1656 nX
= pPoints
[ nPnt
-1 ].X() + 2 * aControlP
.X();
1657 nY
= pPoints
[ nPnt
-1 ].Y() + 2 * aControlP
.Y();
1658 pPoints
[ nPnt
+0 ] = Point( (2*nX
+3)/6, (2*nY
+3)/6 );
1659 pFlags
[ nPnt
+0 ] = PolyFlags::Control
;
1661 // calculate endpoint of segment
1662 nX
= IntTimes256FromFixed( pCurve
->apfx
[ i
].x
);
1663 nY
= IntTimes256FromFixed( pCurve
->apfx
[ i
].y
);
1665 if ( i
+1 >= pCurve
->cpfx
)
1667 // endpoint is either last point in segment => advance
1672 // or endpoint is the middle of two control points
1673 nX
+= IntTimes256FromFixed( pCurve
->apfx
[ i
-1 ].x
);
1674 nY
+= IntTimes256FromFixed( pCurve
->apfx
[ i
-1 ].y
);
1677 // no need to advance, because the current point
1678 // is the control point in next bezier spline
1681 pPoints
[ nPnt
+2 ] = Point( nX
, nY
);
1682 pFlags
[ nPnt
+2 ] = PolyFlags::Normal
;
1684 // calculate second cubic control point
1685 // P1 = 1/3 * (PEnd + 2 * PQControl)
1686 nX
= pPoints
[ nPnt
+2 ].X() + 2 * aControlP
.X();
1687 nY
= pPoints
[ nPnt
+2 ].Y() + 2 * aControlP
.Y();
1688 pPoints
[ nPnt
+1 ] = Point( (2*nX
+3)/6, (2*nY
+3)/6 );
1689 pFlags
[ nPnt
+1 ] = PolyFlags::Control
;
1695 // next curve segment
1696 pCurve
= reinterpret_cast<TTPOLYCURVE
*>(&pCurve
->apfx
[ i
]);
1699 // end point is start point for closed contour
1700 // disabled, because Polygon class closes the contour itself
1701 // pPoints[nPnt++] = pPoints[0];
1703 // Added again, but add only when not yet closed
1704 if(pPoints
[nPnt
- 1] != pPoints
[0])
1706 if( bHasOfflinePoints
)
1707 pFlags
[nPnt
] = pFlags
[0];
1709 pPoints
[nPnt
++] = pPoints
[0];
1712 // convert y-coordinates W32 -> VCL
1713 for( int i
= 0; i
< nPnt
; ++i
)
1714 pPoints
[i
].Y() = -pPoints
[i
].Y();
1716 // insert into polypolygon
1717 tools::Polygon
aPoly( nPnt
, pPoints
, (bHasOfflinePoints
? pFlags
: nullptr) );
1718 // convert to B2DPolyPolygon
1719 // TODO: get rid of the intermediate PolyPolygon
1720 rB2DPolyPoly
.append( aPoly
.getB2DPolygon() );
1728 // rescaling needed for the tools::PolyPolygon conversion
1729 if( rB2DPolyPoly
.count() )
1731 const double fFactor(mfCurrentFontScale
/256);
1732 rB2DPolyPoly
.transform(basegfx::tools::createScaleB2DHomMatrix(fFactor
, fFactor
));
1741 explicit ScopedFont(WinSalGraphics
& rData
);
1746 WinSalGraphics
& m_rData
;
1750 ScopedFont::ScopedFont(WinSalGraphics
& rData
): m_rData(rData
)
1752 m_hOrigFont
= m_rData
.mhFonts
[0];
1753 m_rData
.mhFonts
[0] = nullptr; // avoid deletion of current font
1756 ScopedFont::~ScopedFont()
1760 // restore original font, destroy temporary font
1761 HFONT hTempFont
= m_rData
.mhFonts
[0];
1762 m_rData
.mhFonts
[0] = m_hOrigFont
;
1763 SelectObject( m_rData
.getHDC(), m_hOrigFont
);
1764 DeleteObject( hTempFont
);
1768 class ScopedTrueTypeFont
1771 inline ScopedTrueTypeFont(): m_pFont(nullptr) {}
1773 ~ScopedTrueTypeFont();
1775 int open(void const * pBuffer
, sal_uInt32 nLen
, sal_uInt32 nFaceNum
);
1777 inline TrueTypeFont
* get() const { return m_pFont
; }
1780 TrueTypeFont
* m_pFont
;
1783 ScopedTrueTypeFont::~ScopedTrueTypeFont()
1785 if (m_pFont
!= nullptr)
1786 CloseTTFont(m_pFont
);
1789 int ScopedTrueTypeFont::open(void const * pBuffer
, sal_uInt32 nLen
,
1790 sal_uInt32 nFaceNum
)
1792 OSL_ENSURE(m_pFont
== nullptr, "already open");
1793 return OpenTTFontBuffer(pBuffer
, nLen
, nFaceNum
, &m_pFont
);
1796 bool WinSalGraphics::CreateFontSubset( const OUString
& rToFile
,
1797 const PhysicalFontFace
* pFont
, const sal_GlyphId
* pGlyphIds
, const sal_uInt8
* pEncoding
,
1798 sal_Int32
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& rInfo
)
1800 // TODO: use more of the central font-subsetting code, move stuff there if needed
1802 // create matching FontSelectPattern
1803 // we need just enough to get to the font file data
1804 // use height=1000 for easier debugging (to match psprint's font units)
1805 FontSelectPattern
aIFSD( *pFont
, Size(0,1000), 1000.0, 0, false );
1807 // TODO: much better solution: move SetFont and restoration of old font to caller
1808 ScopedFont
aOldFont(*this);
1810 HFONT hOldFont
= nullptr;
1811 ImplDoSetFont( &aIFSD
, fScale
, hOldFont
);
1813 WinFontFace
const * pWinFontData
= static_cast<WinFontFace
const *>(aIFSD
.mpFontData
);
1815 #if OSL_DEBUG_LEVEL > 1
1817 TEXTMETRICA aWinMetric
;
1818 if( !::GetTextMetricsA( getHDC(), &aWinMetric
) )
1821 SAL_WARN_IF( (aWinMetric
.tmPitchAndFamily
& TMPF_DEVICE
), "vcl", "cannot subset device font" );
1822 SAL_WARN_IF( !aWinMetric
.tmPitchAndFamily
& TMPF_TRUETYPE
, "vcl", "can only subset TT font" );
1826 if( osl_File_E_None
!= osl_getSystemPathFromFileURL( rToFile
.pData
, &aSysPath
.pData
) )
1828 const rtl_TextEncoding aThreadEncoding
= osl_getThreadTextEncoding();
1829 const OString
aToFile(OUStringToOString(aSysPath
, aThreadEncoding
));
1831 // check if the font has a CFF-table
1832 const DWORD nCffTag
= CalcTag( "CFF " );
1833 const RawFontData
aRawCffData( getHDC(), nCffTag
);
1834 if( aRawCffData
.get() )
1836 pWinFontData
->UpdateFromHDC( getHDC() );
1837 FontCharMapRef xFontCharMap
= pWinFontData
->GetFontCharMap();
1839 sal_GlyphId aRealGlyphIds
[ 256 ];
1840 for( int i
= 0; i
< nGlyphCount
; ++i
)
1842 // TODO: remap notdef glyph if needed
1843 // TODO: use GDI's GetGlyphIndices instead? Does it handle GSUB properly?
1844 sal_GlyphId aGlyphId
= pGlyphIds
[i
] & GF_IDXMASK
;
1845 if( pGlyphIds
[i
] & GF_ISCHAR
) // remaining pseudo-glyphs need to be translated
1846 aGlyphId
= xFontCharMap
->GetGlyphIndex( aGlyphId
);
1847 if( (pGlyphIds
[i
] & (GF_ROTMASK
|GF_GSUB
)) != 0) // TODO: vertical substitution
1850 aRealGlyphIds
[i
] = aGlyphId
;
1853 xFontCharMap
= nullptr;
1855 // provide a font subset from the CFF-table
1856 FILE* pOutFile
= fopen( aToFile
.getStr(), "wb" );
1857 rInfo
.LoadFont( FontSubsetInfo::CFF_FONT
, aRawCffData
.get(), aRawCffData
.size() );
1858 bool bRC
= rInfo
.CreateFontSubset( FontSubsetInfo::TYPE1_PFB
, pOutFile
, nullptr,
1859 aRealGlyphIds
, pEncoding
, nGlyphCount
, pGlyphWidths
);
1864 // get raw font file data
1865 const RawFontData
xRawFontData( getHDC(), 0 );
1866 if( !xRawFontData
.get() )
1870 sal_uInt32 nFaceNum
= 0;
1871 if( !*xRawFontData
.get() ) // TTC candidate
1872 nFaceNum
= ~0U; // indicate "TTC font extracts only"
1874 ScopedTrueTypeFont aSftTTF
;
1875 int nRC
= aSftTTF
.open( xRawFontData
.get(), xRawFontData
.size(), nFaceNum
);
1879 TTGlobalFontInfo aTTInfo
;
1880 ::GetTTGlobalFontInfo( aSftTTF
.get(), &aTTInfo
);
1881 rInfo
.m_nFontType
= FontSubsetInfo::SFNT_TTF
;
1882 rInfo
.m_aPSName
= ImplSalGetUniString( aTTInfo
.psname
);
1883 rInfo
.m_nAscent
= aTTInfo
.winAscent
;
1884 rInfo
.m_nDescent
= aTTInfo
.winDescent
;
1885 rInfo
.m_aFontBBox
= Rectangle( Point( aTTInfo
.xMin
, aTTInfo
.yMin
),
1886 Point( aTTInfo
.xMax
, aTTInfo
.yMax
) );
1887 rInfo
.m_nCapHeight
= aTTInfo
.yMax
; // Well ...
1889 // subset TTF-glyphs and get their properties
1890 // take care that subset fonts require the NotDef glyph in pos 0
1891 int nOrigCount
= nGlyphCount
;
1892 sal_uInt16 aShortIDs
[ 256 ];
1893 sal_uInt8 aTempEncs
[ 256 ];
1896 for( i
= 0; i
< nGlyphCount
; ++i
)
1898 aTempEncs
[i
] = pEncoding
[i
];
1899 sal_GlyphId aGlyphId
= pGlyphIds
[i
] & GF_IDXMASK
;
1900 if( pGlyphIds
[i
] & GF_ISCHAR
)
1902 sal_Unicode cChar
= static_cast<sal_Unicode
>(aGlyphId
); // TODO: sal_UCS4
1903 const bool bVertical
= ((pGlyphIds
[i
] & (GF_ROTMASK
|GF_GSUB
)) != 0);
1904 aGlyphId
= ::MapChar( aSftTTF
.get(), cChar
, bVertical
);
1905 if( (aGlyphId
== 0) && pFont
->IsSymbolFont() )
1907 // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX
1908 cChar
= (cChar
& 0xF000) ? (cChar
& 0x00FF) : (cChar
| 0xF000);
1909 aGlyphId
= ::MapChar( aSftTTF
.get(), cChar
, bVertical
);
1912 aShortIDs
[i
] = static_cast<sal_uInt16
>( aGlyphId
);
1915 nNotDef
= i
; // first NotDef glyph found
1920 // add fake NotDef glyph if needed
1922 nNotDef
= nGlyphCount
++;
1924 // NotDef glyph must be in pos 0 => swap glyphids
1925 aShortIDs
[ nNotDef
] = aShortIDs
[0];
1926 aTempEncs
[ nNotDef
] = aTempEncs
[0];
1930 SAL_WARN_IF( nGlyphCount
>= 257, "vcl", "too many glyphs for subsetting" );
1932 // fill pWidth array
1933 TTSimpleGlyphMetrics
* pMetrics
=
1934 ::GetTTSimpleGlyphMetrics( aSftTTF
.get(), aShortIDs
, nGlyphCount
, aIFSD
.mbVertical
);
1937 sal_uInt16 nNotDefAdv
= pMetrics
[0].adv
;
1938 pMetrics
[0].adv
= pMetrics
[nNotDef
].adv
;
1939 pMetrics
[nNotDef
].adv
= nNotDefAdv
;
1940 for( i
= 0; i
< nOrigCount
; ++i
)
1941 pGlyphWidths
[i
] = pMetrics
[i
].adv
;
1944 // write subset into destination file
1945 nRC
= ::CreateTTFromTTGlyphs( aSftTTF
.get(), aToFile
.getStr(), aShortIDs
,
1946 aTempEncs
, nGlyphCount
, 0, nullptr, 0 );
1947 return (nRC
== SF_OK
);
1950 const void* WinSalGraphics::GetEmbedFontData( const PhysicalFontFace
* pFont
,
1951 const sal_Unicode
* pUnicodes
, sal_Int32
* pCharWidths
, size_t nLen
,
1952 FontSubsetInfo
& rInfo
, long* pDataLen
)
1954 // create matching FontSelectPattern
1955 // we need just enough to get to the font file data
1956 FontSelectPattern
aIFSD( *pFont
, Size(0,1000), 1000.0, 0, false );
1958 // TODO: much better solution: move SetFont and restoration of old font to caller
1959 ScopedFont
aOldFont(*this);
1960 SetFont( &aIFSD
, 0 );
1962 // get the raw font file data
1963 RawFontData
aRawFontData( getHDC() );
1964 *pDataLen
= aRawFontData
.size();
1965 if( !aRawFontData
.get() )
1968 // get important font properties
1970 if( !::GetTextMetricsA( getHDC(), &aTm
) )
1972 const bool bPFA
= (*aRawFontData
.get() < 0x80);
1973 rInfo
.m_nFontType
= bPFA
? FontSubsetInfo::TYPE1_PFA
: FontSubsetInfo::TYPE1_PFB
;
1974 WCHAR aFaceName
[64];
1975 sal_Int32 nFNLen
= ::GetTextFaceW( getHDC(), 64, aFaceName
);
1976 // #i59854# strip eventual null byte
1977 while( nFNLen
> 0 && aFaceName
[nFNLen
-1] == 0 )
1981 rInfo
.m_aPSName
= OUString(reinterpret_cast<const sal_Unicode
*>(aFaceName
), nFNLen
);
1982 rInfo
.m_nAscent
= +aTm
.tmAscent
;
1983 rInfo
.m_nDescent
= -aTm
.tmDescent
;
1984 rInfo
.m_aFontBBox
= Rectangle( Point( -aTm
.tmOverhang
, -aTm
.tmDescent
),
1985 Point( aTm
.tmMaxCharWidth
, aTm
.tmAscent
+aTm
.tmExternalLeading
) );
1986 rInfo
.m_nCapHeight
= aTm
.tmAscent
; // Well ...
1988 // get individual character widths
1989 for (size_t i
= 0; i
< nLen
; ++i
)
1992 const sal_Unicode cChar
= pUnicodes
[i
];
1993 if( !::GetCharWidth32W( getHDC(), cChar
, cChar
, &nCharWidth
) )
1995 pCharWidths
[i
] = nCharWidth
;
2001 const unsigned char* pData
= aRawFontData
.steal();
2005 void WinSalGraphics::FreeEmbedFontData( const void* pData
, long /*nLen*/ )
2007 delete[] static_cast<char const *>(pData
);
2010 const Ucs2SIntMap
* WinSalGraphics::GetFontEncodingVector(const PhysicalFontFace
*, const Ucs2OStrMap
**, std::set
<sal_Unicode
> const**)
2015 void WinSalGraphics::GetGlyphWidths( const PhysicalFontFace
* pFont
,
2017 std::vector
< sal_Int32
>& rWidths
,
2018 Ucs2UIntMap
& rUnicodeEnc
)
2020 // create matching FontSelectPattern
2021 // we need just enough to get to the font file data
2022 FontSelectPattern
aIFSD( *pFont
, Size(0,1000), 1000.0, 0, false );
2024 // TODO: much better solution: move SetFont and restoration of old font to caller
2025 ScopedFont
aOldFont(*this);
2028 HFONT hOldFont
= nullptr;
2029 ImplDoSetFont( &aIFSD
, fScale
, hOldFont
);
2031 // get raw font file data
2032 const RawFontData
xRawFontData( getHDC() );
2033 if( !xRawFontData
.get() )
2037 sal_uInt32 nFaceNum
= 0;
2038 if( !*xRawFontData
.get() ) // TTC candidate
2039 nFaceNum
= ~0U; // indicate "TTC font extracts only"
2041 ScopedTrueTypeFont aSftTTF
;
2042 int nRC
= aSftTTF
.open( xRawFontData
.get(), xRawFontData
.size(), nFaceNum
);
2046 int nGlyphs
= GetTTGlyphCount( aSftTTF
.get() );
2049 rWidths
.resize(nGlyphs
);
2050 std::vector
<sal_uInt16
> aGlyphIds(nGlyphs
);
2051 for( int i
= 0; i
< nGlyphs
; i
++ )
2052 aGlyphIds
[i
] = sal_uInt16(i
);
2053 TTSimpleGlyphMetrics
* pMetrics
= ::GetTTSimpleGlyphMetrics( aSftTTF
.get(),
2059 for( int i
= 0; i
< nGlyphs
; i
++ )
2060 rWidths
[i
] = pMetrics
[i
].adv
;
2062 rUnicodeEnc
.clear();
2064 const WinFontFace
* pWinFont
= static_cast<const WinFontFace
*>(pFont
);
2065 FontCharMapRef xFCMap
= pWinFont
->GetFontCharMap();
2066 SAL_WARN_IF( !xFCMap
.Is() || !xFCMap
->GetCharCount(), "vcl", "no map" );
2068 int nCharCount
= xFCMap
->GetCharCount();
2069 sal_uInt32 nChar
= xFCMap
->GetFirstChar();
2070 for( int i
= 0; i
< nCharCount
; i
++ )
2072 if( nChar
< 0x00010000 )
2074 sal_uInt16 nGlyph
= ::MapChar( aSftTTF
.get(),
2075 static_cast<sal_Ucs
>(nChar
),
2078 rUnicodeEnc
[ static_cast<sal_Unicode
>(nChar
) ] = nGlyph
;
2080 nChar
= xFCMap
->GetNextChar( nChar
);
2087 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */