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>
32 #include <o3tl/lru_map.hxx>
33 #include <basegfx/matrix/b2dhommatrixtools.hxx>
34 #include <basegfx/polygon/b2dpolygon.hxx>
35 #include <i18nlangtag/mslangid.hxx>
36 #include <osl/file.hxx>
37 #include <osl/process.h>
38 #include <rtl/bootstrap.hxx>
39 #include <rtl/tencinfo.h>
40 #include <sal/log.hxx>
41 #include <o3tl/char16_t2wchar_t.hxx>
42 #include <tools/helpers.hxx>
43 #include <tools/stream.hxx>
44 #include <tools/urlobj.hxx>
45 #include <unotools/fontcfg.hxx>
46 #include <vcl/settings.hxx>
47 #include <vcl/sysdata.hxx>
48 #include <vcl/metric.hxx>
49 #include <vcl/fontcharmap.hxx>
50 #include <vcl/opengl/OpenGLWrapper.hxx>
51 #include <comphelper/scopeguard.hxx>
53 #include <fontsubset.hxx>
55 #include <PhysicalFontCollection.hxx>
56 #include <PhysicalFontFace.hxx>
58 #include <win/saldata.hxx>
59 #include <win/salgdi.h>
60 #include <win/winlayout.hxx>
61 #include <win/wingdiimpl.hxx>
62 #include <impfontcharmap.hxx>
63 #include <impfontmetricdata.hxx>
64 #include <impglyphitem.hxx>
68 static FIXED
FixedFromDouble( double d
)
70 const tools::Long l
= static_cast<tools::Long
>( d
* 65536. );
71 return *reinterpret_cast<FIXED
const *>(&l
);
74 static int IntTimes256FromFixed(FIXED f
)
76 int nFixedTimes256
= (f
.value
<< 8) + ((f
.fract
+0x80) >> 8);
77 return nFixedTimes256
;
82 // raw font data with a scoped lifetime
86 explicit RawFontData( HDC
, DWORD nTableTag
=0 );
87 const unsigned char* get() const { return mpRawBytes
.get(); }
88 const unsigned char* steal() { return mpRawBytes
.release(); }
89 int size() const { return mnByteCount
; }
92 std::unique_ptr
<unsigned char[]> mpRawBytes
;
98 RawFontData::RawFontData( HDC hDC
, DWORD nTableTag
)
101 // get required size in bytes
102 mnByteCount
= ::GetFontData( hDC
, nTableTag
, 0, nullptr, 0 );
103 if (mnByteCount
== GDI_ERROR
)
108 // allocate the array
109 mpRawBytes
.reset(new unsigned char[ mnByteCount
]);
111 // get raw data in chunks small enough for GetFontData()
112 unsigned nRawDataOfs
= 0;
113 DWORD nMaxChunkSize
= 0x100000;
116 // calculate remaining raw data to get
117 DWORD nFDGet
= mnByteCount
- nRawDataOfs
;
120 // #i56745# limit GetFontData requests
121 if( nFDGet
> nMaxChunkSize
)
122 nFDGet
= nMaxChunkSize
;
123 const DWORD nFDGot
= ::GetFontData( hDC
, nTableTag
, nRawDataOfs
,
124 mpRawBytes
.get() + nRawDataOfs
, nFDGet
);
127 else if( nFDGot
!= GDI_ERROR
)
128 nRawDataOfs
+= nFDGot
;
131 // was the chunk too big? reduce it
133 if( nMaxChunkSize
< 0x10000 )
138 // cleanup if the raw data is incomplete
139 if( nRawDataOfs
!= mnByteCount
)
142 // mnByteCount must correspond to mpRawBytes length
143 SAL_WARN( "vcl", "Raw data of font is incomplete: " << nRawDataOfs
<< " byte(s) found whereas " << mnByteCount
<< " byte(s) expected!" );
148 // platform specific font substitution hooks for glyph fallback enhancement
152 class WinPreMatchFontSubstititution
153 : public ImplPreMatchFontSubstitution
156 bool FindFontSubstitute(FontSelectPattern
&) const override
;
159 class WinGlyphFallbackSubstititution
160 : public ImplGlyphFallbackFontSubstitution
163 explicit WinGlyphFallbackSubstititution()
164 : mhDC(GetDC(nullptr))
168 ~WinGlyphFallbackSubstititution() override
170 ReleaseDC(nullptr, mhDC
);
173 bool FindFontSubstitute(FontSelectPattern
&, LogicalFontInstance
* pLogicalFont
, OUString
& rMissingChars
) const override
;
176 bool HasMissingChars(PhysicalFontFace
*, OUString
& rMissingChars
) const;
181 // does a font face hold the given missing characters?
182 bool WinGlyphFallbackSubstititution::HasMissingChars(PhysicalFontFace
* pFace
, OUString
& rMissingChars
) const
184 WinFontFace
* pWinFont
= static_cast< WinFontFace
* >(pFace
);
185 FontCharMapRef xFontCharMap
= pWinFont
->GetFontCharMap();
186 if( !xFontCharMap
.is() )
188 // construct a Size structure as the parameter of constructor of class FontSelectPattern
189 const Size
aSize( pFace
->GetWidth(), pFace
->GetHeight() );
190 // create a FontSelectPattern object for getting s LOGFONT
191 const FontSelectPattern
aFSD( *pFace
, aSize
, static_cast<float>(aSize
.Height()), 0, false );
192 // construct log font
194 ImplGetLogFontFromFontSelect( mhDC
, aFSD
, pFace
, aLogFont
);
196 // create HFONT from log font
197 HFONT hNewFont
= ::CreateFontIndirectW( &aLogFont
);
198 // select the new font into device
199 HFONT hOldFont
= ::SelectFont( mhDC
, hNewFont
);
201 // read CMAP table to update their xFontCharMap
202 pWinFont
->UpdateFromHDC( mhDC
);
204 // cleanup temporary font
205 ::SelectFont( mhDC
, hOldFont
);
206 ::DeleteFont( hNewFont
);
208 // get the new charmap
209 xFontCharMap
= pWinFont
->GetFontCharMap();
212 // avoid fonts with unknown CMAP subtables for glyph fallback
213 if( !xFontCharMap
.is() || xFontCharMap
->IsDefaultMap() )
217 std::vector
<sal_UCS4
> rRemainingCodes
;
218 const sal_Int32 nStrLen
= rMissingChars
.getLength();
219 sal_Int32 nStrIdx
= 0;
220 while (nStrIdx
< nStrLen
)
222 const sal_UCS4 uChar
= rMissingChars
.iterateCodePoints( &nStrIdx
);
223 if (xFontCharMap
->HasChar(uChar
))
226 rRemainingCodes
.push_back(uChar
);
229 xFontCharMap
= nullptr;
232 rMissingChars
= OUString(rRemainingCodes
.data(), rRemainingCodes
.size());
234 return nMatchCount
> 0;
239 //used by 2-level font fallback
240 PhysicalFontFamily
* findDevFontListByLocale(const PhysicalFontCollection
&rFontCollection
,
241 const LanguageTag
& rLanguageTag
)
243 // get the default font for a specified locale
244 const utl::DefaultFontConfiguration
& rDefaults
= utl::DefaultFontConfiguration::get();
245 const OUString aDefault
= rDefaults
.getUserInterfaceFont(rLanguageTag
);
246 return rFontCollection
.FindFontFamilyByTokenNames(aDefault
);
250 // These are Win 3.1 bitmap fonts using "FON" font format
251 // which is not supported with DirectWrite so let's substitute them
252 // with a font that is supported and always available.
254 // https://dxr.mozilla.org/mozilla-esr10/source/gfx/thebes/gfxDWriteFontList.cpp#1057
255 const std::map
<OUString
, OUString
> aBitmapFontSubs
=
257 { "MS Sans Serif", "Microsoft Sans Serif" },
258 { "MS Serif", "Times New Roman" },
259 { "Small Fonts", "Arial" },
260 { "Courier", "Courier New" },
261 { "Roman", "Times New Roman" },
262 { "Script", "Mistral" }
265 // TODO: See if Windows have API that we can use here to improve font fallback.
266 bool WinPreMatchFontSubstititution::FindFontSubstitute(FontSelectPattern
& rFontSelData
) const
268 if (rFontSelData
.IsSymbolFont() || IsStarSymbol(rFontSelData
.maSearchName
))
271 for (const auto& aSub
: aBitmapFontSubs
)
273 if (rFontSelData
.maSearchName
== GetEnglishSearchFontName(aSub
.first
))
275 rFontSelData
.maSearchName
= aSub
.second
;
283 // find a fallback font for missing characters
284 // TODO: should stylistic matches be searched and preferred?
285 bool WinGlyphFallbackSubstititution::FindFontSubstitute(FontSelectPattern
& rFontSelData
, LogicalFontInstance
* /*pLogicalFont*/, OUString
& rMissingChars
) const
287 // guess a locale matching to the missing chars
288 LanguageType eLang
= rFontSelData
.meLanguage
;
289 LanguageTag
aLanguageTag( eLang
);
291 // fall back to default UI locale if the font language is inconclusive
292 if( eLang
== LANGUAGE_DONTKNOW
)
293 aLanguageTag
= Application::GetSettings().GetUILanguageTag();
295 // first level fallback:
296 // try use the locale specific default fonts defined in VCL.xcu
297 const PhysicalFontCollection
* pFontCollection
= ImplGetSVData()->maGDIData
.mxScreenFontList
.get();
298 PhysicalFontFamily
* pFontFamily
= findDevFontListByLocale(*pFontCollection
, aLanguageTag
);
301 PhysicalFontFace
* pFace
= pFontFamily
->FindBestFontFace( rFontSelData
);
302 if( HasMissingChars( pFace
, rMissingChars
) )
304 rFontSelData
.maSearchName
= pFontFamily
->GetSearchName();
309 // are the missing characters symbols?
310 pFontFamily
= pFontCollection
->FindFontFamilyByAttributes( ImplFontAttrs::Symbol
,
311 rFontSelData
.GetWeight(),
312 rFontSelData
.GetWidthType(),
313 rFontSelData
.GetItalic(),
314 rFontSelData
.maSearchName
);
317 PhysicalFontFace
* pFace
= pFontFamily
->FindBestFontFace( rFontSelData
);
318 if( HasMissingChars( pFace
, rMissingChars
) )
320 rFontSelData
.maSearchName
= pFontFamily
->GetSearchName();
325 // last level fallback, check each font type face one by one
326 std::unique_ptr
<ImplDeviceFontList
> pTestFontList
= pFontCollection
->GetDeviceFontList();
327 // limit the count of fonts to be checked to prevent hangs
328 static const int MAX_GFBFONT_COUNT
= 600;
329 int nTestFontCount
= pTestFontList
->Count();
330 if( nTestFontCount
> MAX_GFBFONT_COUNT
)
331 nTestFontCount
= MAX_GFBFONT_COUNT
;
334 for( int i
= 0; i
< nTestFontCount
; ++i
)
336 PhysicalFontFace
* pFace
= pTestFontList
->Get( i
);
337 bFound
= HasMissingChars( pFace
, rMissingChars
);
340 rFontSelData
.maSearchName
= pFace
->GetFamilyName();
352 PhysicalFontCollection
* mpList
;
361 static rtl_TextEncoding
ImplCharSetToSal( BYTE nCharSet
)
363 rtl_TextEncoding eTextEncoding
;
365 if ( nCharSet
== OEM_CHARSET
)
367 UINT nCP
= static_cast<sal_uInt16
>(GetOEMCP());
370 // It is unclear why these two (undefined?) code page numbers are
371 // handled specially here:
372 case 1004: eTextEncoding
= RTL_TEXTENCODING_MS_1252
; break;
373 case 65400: eTextEncoding
= RTL_TEXTENCODING_SYMBOL
; break;
375 eTextEncoding
= rtl_getTextEncodingFromWindowsCodePage(nCP
);
382 eTextEncoding
= rtl_getTextEncodingFromWindowsCharset( nCharSet
);
384 eTextEncoding
= RTL_TEXTENCODING_UNICODE
;
387 return eTextEncoding
;
390 static FontFamily
ImplFamilyToSal( BYTE nFamily
)
392 switch ( nFamily
& 0xF0 )
395 return FAMILY_DECORATIVE
;
398 return FAMILY_MODERN
;
404 return FAMILY_SCRIPT
;
413 return FAMILY_DONTKNOW
;
416 static BYTE
ImplFamilyToWin( FontFamily eFamily
)
420 case FAMILY_DECORATIVE
:
421 return FF_DECORATIVE
;
445 static FontWeight
ImplWeightToSal( int nWeight
)
447 if ( nWeight
<= FW_THIN
)
449 else if ( nWeight
<= FW_ULTRALIGHT
)
450 return WEIGHT_ULTRALIGHT
;
451 else if ( nWeight
<= FW_LIGHT
)
453 else if ( nWeight
< FW_MEDIUM
)
454 return WEIGHT_NORMAL
;
455 else if ( nWeight
== FW_MEDIUM
)
456 return WEIGHT_MEDIUM
;
457 else if ( nWeight
<= FW_SEMIBOLD
)
458 return WEIGHT_SEMIBOLD
;
459 else if ( nWeight
<= FW_BOLD
)
461 else if ( nWeight
<= FW_ULTRABOLD
)
462 return WEIGHT_ULTRABOLD
;
467 static int ImplWeightToWin( FontWeight eWeight
)
474 case WEIGHT_ULTRALIGHT
:
475 return FW_ULTRALIGHT
;
480 case WEIGHT_SEMILIGHT
:
487 case WEIGHT_SEMIBOLD
:
493 case WEIGHT_ULTRABOLD
:
506 static FontPitch
ImplLogPitchToSal( BYTE nPitch
)
508 if ( nPitch
& FIXED_PITCH
)
511 return PITCH_VARIABLE
;
514 static FontPitch
ImplMetricPitchToSal( BYTE nPitch
)
516 // Grrrr! See NT help
517 if ( !(nPitch
& TMPF_FIXED_PITCH
) )
520 return PITCH_VARIABLE
;
523 static BYTE
ImplPitchToWin( FontPitch ePitch
)
525 if ( ePitch
== PITCH_FIXED
)
527 else if ( ePitch
== PITCH_VARIABLE
)
528 return VARIABLE_PITCH
;
530 return DEFAULT_PITCH
;
533 static FontAttributes
WinFont2DevFontAttributes( const ENUMLOGFONTEXW
& rEnumFont
,
534 const NEWTEXTMETRICW
& rMetric
)
538 const LOGFONTW rLogFont
= rEnumFont
.elfLogFont
;
540 // get font face attributes
541 aDFA
.SetFamilyType(ImplFamilyToSal( rLogFont
.lfPitchAndFamily
));
542 aDFA
.SetWidthType(WIDTH_DONTKNOW
);
543 aDFA
.SetWeight(ImplWeightToSal( rLogFont
.lfWeight
));
544 aDFA
.SetItalic((rLogFont
.lfItalic
) ? ITALIC_NORMAL
: ITALIC_NONE
);
545 aDFA
.SetPitch(ImplLogPitchToSal( rLogFont
.lfPitchAndFamily
));
546 aDFA
.SetSymbolFlag(rLogFont
.lfCharSet
== SYMBOL_CHARSET
);
548 // get the font face name
549 aDFA
.SetFamilyName(OUString(o3tl::toU(rLogFont
.lfFaceName
)));
551 // use the face's style name only if it looks reasonable
552 const wchar_t* pStyleName
= rEnumFont
.elfStyle
;
553 const wchar_t* pEnd
= pStyleName
+ sizeof(rEnumFont
.elfStyle
)/sizeof(*rEnumFont
.elfStyle
);
554 const wchar_t* p
= pStyleName
;
555 for(; *p
&& (p
< pEnd
); ++p
)
559 aDFA
.SetStyleName(OUString(o3tl::toU(pStyleName
)));
561 // heuristics for font quality
562 // - opentypeTT > truetype
563 aDFA
.SetQuality( 0 );
564 if( rMetric
.tmPitchAndFamily
& TMPF_TRUETYPE
)
565 aDFA
.IncreaseQualityBy( 50 );
566 if( 0 != (rMetric
.ntmFlags
& (NTM_TT_OPENTYPE
| NTM_PS_OPENTYPE
)) )
567 aDFA
.IncreaseQualityBy( 10 );
569 // TODO: add alias names
574 static rtl::Reference
<WinFontFace
> ImplLogMetricToDevFontDataW( const ENUMLOGFONTEXW
* pLogFont
,
575 const NEWTEXTMETRICW
* pMetric
)
577 rtl::Reference
<WinFontFace
> pData
= new WinFontFace(
578 WinFont2DevFontAttributes(*pLogFont
, *pMetric
),
579 pLogFont
->elfLogFont
.lfCharSet
,
580 pMetric
->tmPitchAndFamily
);
585 void ImplSalLogFontToFontW( HDC hDC
, const LOGFONTW
& rLogFont
, Font
& rFont
)
587 OUString
aFontName( o3tl::toU(rLogFont
.lfFaceName
) );
588 if (!aFontName
.isEmpty())
590 rFont
.SetFamilyName( aFontName
);
591 rFont
.SetCharSet( ImplCharSetToSal( rLogFont
.lfCharSet
) );
592 rFont
.SetFamily( ImplFamilyToSal( rLogFont
.lfPitchAndFamily
) );
593 rFont
.SetPitch( ImplLogPitchToSal( rLogFont
.lfPitchAndFamily
) );
594 rFont
.SetWeight( ImplWeightToSal( rLogFont
.lfWeight
) );
596 tools::Long nFontHeight
= rLogFont
.lfHeight
;
597 if ( nFontHeight
< 0 )
598 nFontHeight
= -nFontHeight
;
599 tools::Long nDPIY
= GetDeviceCaps( hDC
, LOGPIXELSY
);
603 nFontHeight
+= nDPIY
/2;
604 nFontHeight
/= nDPIY
;
605 rFont
.SetFontSize( Size( 0, nFontHeight
) );
606 rFont
.SetOrientation( Degree10(static_cast<sal_Int16
>(rLogFont
.lfEscapement
)) );
607 if ( rLogFont
.lfItalic
)
608 rFont
.SetItalic( ITALIC_NORMAL
);
610 rFont
.SetItalic( ITALIC_NONE
);
611 if ( rLogFont
.lfUnderline
)
612 rFont
.SetUnderline( LINESTYLE_SINGLE
);
614 rFont
.SetUnderline( LINESTYLE_NONE
);
615 if ( rLogFont
.lfStrikeOut
)
616 rFont
.SetStrikeout( STRIKEOUT_SINGLE
);
618 rFont
.SetStrikeout( STRIKEOUT_NONE
);
622 WinFontFace::WinFontFace( const FontAttributes
& rDFS
,
623 BYTE eWinCharSet
, BYTE nPitchAndFamily
)
624 : PhysicalFontFace( rDFS
),
626 mbFontCapabilitiesRead( false ),
627 meWinCharSet( eWinCharSet
),
628 mnPitchAndFamily( nPitchAndFamily
),
629 mbAliasSymbolsHigh( false ),
630 mbAliasSymbolsLow( false )
632 if( eWinCharSet
== SYMBOL_CHARSET
)
634 if( (nPitchAndFamily
& TMPF_TRUETYPE
) != 0 )
636 // truetype fonts need their symbols as U+F0xx
637 mbAliasSymbolsHigh
= true;
639 else if( (nPitchAndFamily
& (TMPF_VECTOR
|TMPF_DEVICE
))
640 == (TMPF_VECTOR
|TMPF_DEVICE
) )
642 // scalable device fonts (e.g. builtin printer fonts)
643 // need their symbols as U+00xx
644 mbAliasSymbolsLow
= true;
646 else if( (nPitchAndFamily
& (TMPF_VECTOR
|TMPF_TRUETYPE
)) == 0 )
648 // bitmap fonts need their symbols as U+F0xx
649 mbAliasSymbolsHigh
= true;
654 WinFontFace::~WinFontFace()
656 mxUnicodeMap
.clear();
659 sal_IntPtr
WinFontFace::GetFontId() const
664 rtl::Reference
<LogicalFontInstance
> WinFontFace::CreateFontInstance(const FontSelectPattern
& rFSD
) const
666 return new WinFontInstance(*this, rFSD
);
669 static DWORD
CalcTag( const char p
[5]) { return (p
[0]+(p
[1]<<8)+(p
[2]<<16)+(p
[3]<<24)); }
671 void WinFontFace::UpdateFromHDC( HDC hDC
) const
673 // short circuit if already initialized
674 if( mxUnicodeMap
.is() )
677 ReadCmapTable( hDC
);
678 GetFontCapabilities( hDC
);
681 FontCharMapRef
WinFontFace::GetFontCharMap() const
686 bool WinFontFace::GetFontCapabilities(vcl::FontCapabilities
&rFontCapabilities
) const
688 rFontCapabilities
= maFontCapabilities
;
689 return rFontCapabilities
.oUnicodeRange
|| rFontCapabilities
.oCodePageRange
;
692 void WinFontFace::ReadCmapTable( HDC hDC
) const
694 if( mxUnicodeMap
.is() )
697 bool bIsSymbolFont
= (meWinCharSet
== SYMBOL_CHARSET
);
698 // get the CMAP table from the font which is selected into the DC
699 const DWORD nCmapTag
= CalcTag( "cmap" );
700 const RawFontData
aRawFontData( hDC
, nCmapTag
);
701 // parse the CMAP table if available
702 if( aRawFontData
.get() ) {
704 ParseCMAP( aRawFontData
.get(), aRawFontData
.size(), aResult
);
705 aResult
.mbSymbolic
= bIsSymbolFont
;
706 if( aResult
.mnRangeCount
> 0 )
708 FontCharMapRef
pUnicodeMap(new FontCharMap(aResult
));
709 mxUnicodeMap
= pUnicodeMap
;
713 if( !mxUnicodeMap
.is() )
715 mxUnicodeMap
= FontCharMap::GetDefaultMap( bIsSymbolFont
);
719 void WinFontFace::GetFontCapabilities( HDC hDC
) const
721 // read this only once per font
722 if( mbFontCapabilitiesRead
)
725 mbFontCapabilitiesRead
= true;
728 const DWORD OS2Tag
= CalcTag( "OS/2" );
729 DWORD nLength
= ::GetFontData( hDC
, OS2Tag
, 0, nullptr, 0 );
730 if( (nLength
!= GDI_ERROR
) && nLength
)
732 std::vector
<unsigned char> aTable( nLength
);
733 unsigned char* pTable
= aTable
.data();
734 ::GetFontData( hDC
, OS2Tag
, 0, pTable
, nLength
);
735 vcl::getTTCoverage(maFontCapabilities
.oUnicodeRange
, maFontCapabilities
.oCodePageRange
, pTable
, nLength
);
739 void WinSalGraphics::SetTextColor( Color nColor
)
741 COLORREF aCol
= PALETTERGB( nColor
.GetRed(),
746 GetSalData()->mhDitherPal
&&
747 ImplIsSysColorEntry( nColor
) )
749 aCol
= PALRGB_TO_RGB( aCol
);
752 ::SetTextColor( getHDC(), aCol
);
755 static int CALLBACK
SalEnumQueryFontProcExW( const LOGFONTW
*,
757 DWORD
, LPARAM lParam
)
759 *reinterpret_cast<bool*>(lParam
) = true;
763 void ImplGetLogFontFromFontSelect( HDC hDC
,
764 const FontSelectPattern
& rFont
,
765 const PhysicalFontFace
* pFontFace
,
770 aName
= pFontFace
->GetFamilyName();
772 aName
= rFont
.GetFamilyName().getToken( 0, ';' );
774 UINT nNameLen
= aName
.getLength();
775 if (nNameLen
>= LF_FACESIZE
)
776 nNameLen
= LF_FACESIZE
- 1;
777 memcpy( rLogFont
.lfFaceName
, aName
.getStr(), nNameLen
*sizeof( wchar_t ) );
778 rLogFont
.lfFaceName
[nNameLen
] = 0;
782 const WinFontFace
* pWinFontData
= static_cast<const WinFontFace
*>(pFontFace
);
783 rLogFont
.lfCharSet
= pWinFontData
->GetCharSet();
784 rLogFont
.lfPitchAndFamily
= pWinFontData
->GetPitchAndFamily();
788 rLogFont
.lfCharSet
= rFont
.IsSymbolFont() ? SYMBOL_CHARSET
: DEFAULT_CHARSET
;
789 rLogFont
.lfPitchAndFamily
= ImplPitchToWin( rFont
.GetPitch() )
790 | ImplFamilyToWin( rFont
.GetFamilyType() );
793 static BYTE nDefaultQuality
= NONANTIALIASED_QUALITY
;
794 if (nDefaultQuality
== NONANTIALIASED_QUALITY
)
796 if (OpenGLWrapper::isVCLOpenGLEnabled())
797 nDefaultQuality
= ANTIALIASED_QUALITY
;
799 nDefaultQuality
= DEFAULT_QUALITY
;
802 rLogFont
.lfWeight
= ImplWeightToWin( rFont
.GetWeight() );
803 rLogFont
.lfHeight
= static_cast<LONG
>(-rFont
.mnHeight
);
804 rLogFont
.lfWidth
= static_cast<LONG
>(rFont
.mnWidth
);
805 rLogFont
.lfUnderline
= 0;
806 rLogFont
.lfStrikeOut
= 0;
807 rLogFont
.lfItalic
= BYTE(rFont
.GetItalic() != ITALIC_NONE
);
808 rLogFont
.lfEscapement
= rFont
.mnOrientation
.get();
809 rLogFont
.lfOrientation
= rLogFont
.lfEscapement
;
810 rLogFont
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
811 rLogFont
.lfQuality
= nDefaultQuality
;
812 rLogFont
.lfOutPrecision
= OUT_TT_PRECIS
;
813 if ( rFont
.mnOrientation
)
814 rLogFont
.lfClipPrecision
|= CLIP_LH_ANGLES
;
816 // disable antialiasing if requested
817 if ( rFont
.mbNonAntialiased
)
818 rLogFont
.lfQuality
= NONANTIALIASED_QUALITY
;
820 // select vertical mode if requested and available
821 if ( rFont
.mbVertical
&& nNameLen
)
823 // vertical fonts start with an '@'
824 memmove( &rLogFont
.lfFaceName
[1], &rLogFont
.lfFaceName
[0],
825 sizeof(rLogFont
.lfFaceName
)-sizeof(rLogFont
.lfFaceName
[0]) );
826 rLogFont
.lfFaceName
[0] = '@';
828 // check availability of vertical mode for this font
829 bool bAvailable
= false;
830 EnumFontFamiliesExW( hDC
, &rLogFont
, SalEnumQueryFontProcExW
,
831 reinterpret_cast<LPARAM
>(&bAvailable
), 0 );
835 // restore non-vertical name if not vertical mode isn't available
836 memcpy( &rLogFont
.lfFaceName
[0], aName
.getStr(), nNameLen
*sizeof(wchar_t) );
837 rLogFont
.lfFaceName
[nNameLen
] = '\0';
838 // keep it upright and create the font for sideway glyphs later.
839 rLogFont
.lfEscapement
= rLogFont
.lfEscapement
- 2700;
840 rLogFont
.lfOrientation
= rLogFont
.lfEscapement
;
845 HFONT
WinSalGraphics::ImplDoSetFont(FontSelectPattern
const & i_rFont
,
846 const PhysicalFontFace
* i_pFontFace
,
849 HFONT hNewFont
= nullptr;
852 ImplGetLogFontFromFontSelect( getHDC(), i_rFont
, i_pFontFace
, aLogFont
);
854 hNewFont
= ::CreateFontIndirectW( &aLogFont
);
856 HDC hdcScreen
= nullptr;
858 // only required for virtual devices, see below for details
859 hdcScreen
= GetDC(nullptr);
862 // select font into screen hdc first to get an antialiased font
863 // and instantly restore the default font!
864 // see knowledge base article 305290:
865 // "PRB: Fonts Not Drawn Antialiased on Device Context for DirectDraw Surface"
866 SelectFont( hdcScreen
, SelectFont( hdcScreen
, hNewFont
) );
868 o_rOldFont
= ::SelectFont( getHDC(), hNewFont
);
870 TEXTMETRICW aTextMetricW
;
871 if( !::GetTextMetricsW( getHDC(), &aTextMetricW
) )
873 // the selected font doesn't work => try a replacement
874 // TODO: use its font fallback instead
875 lstrcpynW( aLogFont
.lfFaceName
, L
"Courier New", 12 );
876 aLogFont
.lfPitchAndFamily
= FIXED_PITCH
;
877 HFONT hNewFont2
= CreateFontIndirectW( &aLogFont
);
878 SelectFont( getHDC(), hNewFont2
);
879 DeleteFont( hNewFont
);
880 hNewFont
= hNewFont2
;
884 ::ReleaseDC( nullptr, hdcScreen
);
889 void WinSalGraphics::SetFont(LogicalFontInstance
* pFont
, int nFallbackLevel
)
891 // return early if there is no new font
894 if (!mpWinFontEntry
[nFallbackLevel
].is())
897 // select original DC font
899 ::SelectFont(getHDC(), mhDefFont
);
902 // release no longer referenced font handles
903 for( int i
= nFallbackLevel
; i
< MAX_FALLBACK
; ++i
)
904 mpWinFontEntry
[i
] = nullptr;
908 WinFontInstance
*pFontInstance
= static_cast<WinFontInstance
*>(pFont
);
909 mpWinFontEntry
[ nFallbackLevel
] = pFontInstance
;
911 HFONT hOldFont
= nullptr;
912 HFONT hNewFont
= pFontInstance
->GetHFONT();
915 pFontInstance
->SetGraphics(this);
916 hNewFont
= pFontInstance
->GetHFONT();
918 hOldFont
= ::SelectFont(getHDC(), hNewFont
);
922 mhDefFont
= hOldFont
;
925 // release no longer referenced font handles
926 for( int i
= nFallbackLevel
+ 1; i
< MAX_FALLBACK
&& mpWinFontEntry
[i
].is(); ++i
)
927 mpWinFontEntry
[i
] = nullptr;
930 // now the font is live => update font face
931 const WinFontFace
* pFontFace
= pFontInstance
->GetFontFace();
932 pFontFace
->UpdateFromHDC(getHDC());
935 void WinSalGraphics::GetFontMetric( ImplFontMetricDataRef
& rxFontMetric
, int nFallbackLevel
)
937 // temporarily change the HDC to the font in the fallback level
938 rtl::Reference
<WinFontInstance
> pFontInstance
= mpWinFontEntry
[nFallbackLevel
];
939 const HFONT hOldFont
= SelectFont(getHDC(), pFontInstance
->GetHFONT());
941 wchar_t aFaceName
[LF_FACESIZE
+60];
942 if( GetTextFaceW( getHDC(), SAL_N_ELEMENTS(aFaceName
), aFaceName
) )
943 rxFontMetric
->SetFamilyName(OUString(o3tl::toU(aFaceName
)));
945 rxFontMetric
->SetMinKashida(pFontInstance
->GetKashidaWidth());
946 rxFontMetric
->ImplCalcLineSpacing(pFontInstance
.get());
948 // get the font metric
949 OUTLINETEXTMETRICW aOutlineMetric
;
950 const bool bOK
= GetOutlineTextMetricsW(getHDC(), sizeof(aOutlineMetric
), &aOutlineMetric
);
951 // restore the HDC to the font in the base level
952 SelectFont( getHDC(), hOldFont
);
956 TEXTMETRICW aWinMetric
= aOutlineMetric
.otmTextMetrics
;
958 // device independent font attributes
959 rxFontMetric
->SetFamilyType(ImplFamilyToSal( aWinMetric
.tmPitchAndFamily
));
960 rxFontMetric
->SetSymbolFlag(aWinMetric
.tmCharSet
== SYMBOL_CHARSET
);
961 rxFontMetric
->SetWeight(ImplWeightToSal( aWinMetric
.tmWeight
));
962 rxFontMetric
->SetPitch(ImplMetricPitchToSal( aWinMetric
.tmPitchAndFamily
));
963 rxFontMetric
->SetItalic(aWinMetric
.tmItalic
? ITALIC_NORMAL
: ITALIC_NONE
);
964 rxFontMetric
->SetSlant( 0 );
966 // transformation dependent font metrics
967 rxFontMetric
->SetWidth(static_cast<int>(pFontInstance
->GetScale() * aWinMetric
.tmAveCharWidth
));
970 FontCharMapRef
WinSalGraphics::GetFontCharMap() const
972 if (!mpWinFontEntry
[0])
974 return FontCharMapRef( new FontCharMap() );
976 return mpWinFontEntry
[0]->GetFontFace()->GetFontCharMap();
979 bool WinSalGraphics::GetFontCapabilities(vcl::FontCapabilities
&rFontCapabilities
) const
981 if (!mpWinFontEntry
[0])
983 return mpWinFontEntry
[0]->GetFontFace()->GetFontCapabilities(rFontCapabilities
);
986 static int CALLBACK
SalEnumFontsProcExW( const LOGFONTW
* lpelfe
,
987 const TEXTMETRICW
* lpntme
,
988 DWORD nFontType
, LPARAM lParam
)
990 ENUMLOGFONTEXW
const * pLogFont
991 = reinterpret_cast<ENUMLOGFONTEXW
const *>(lpelfe
);
992 NEWTEXTMETRICEXW
const * pMetric
993 = reinterpret_cast<NEWTEXTMETRICEXW
const *>(lpntme
);
994 ImplEnumInfo
* pInfo
= reinterpret_cast<ImplEnumInfo
*>(lParam
);
995 if ( !pInfo
->mpName
)
997 // Ignore vertical fonts
998 if ( pLogFont
->elfLogFont
.lfFaceName
[0] != '@' )
1000 OUString
aName(o3tl::toU(pLogFont
->elfLogFont
.lfFaceName
));
1001 pInfo
->mpName
= &aName
;
1002 memcpy(pInfo
->mpLogFont
->lfFaceName
, pLogFont
->elfLogFont
.lfFaceName
, (aName
.getLength()+1)*sizeof(wchar_t));
1003 pInfo
->mpLogFont
->lfCharSet
= pLogFont
->elfLogFont
.lfCharSet
;
1004 EnumFontFamiliesExW(pInfo
->mhDC
, pInfo
->mpLogFont
, SalEnumFontsProcExW
,
1005 reinterpret_cast<LPARAM
>(pInfo
), 0);
1006 pInfo
->mpLogFont
->lfFaceName
[0] = '\0';
1007 pInfo
->mpLogFont
->lfCharSet
= DEFAULT_CHARSET
;
1008 pInfo
->mpName
= nullptr;
1013 // Ignore non-device fonts on printers.
1014 if (pInfo
->mbPrinter
)
1016 if ((nFontType
& RASTER_FONTTYPE
) && !(nFontType
& DEVICE_FONTTYPE
))
1018 SAL_INFO("vcl.fonts", "Unsupported printer font ignored: " << OUString(o3tl::toU(pLogFont
->elfLogFont
.lfFaceName
)));
1022 // Only SFNT fonts are supported, ignore anything else.
1023 else if (!(nFontType
& TRUETYPE_FONTTYPE
) &&
1024 !(pMetric
->ntmTm
.ntmFlags
& NTM_PS_OPENTYPE
) &&
1025 !(pMetric
->ntmTm
.ntmFlags
& NTM_TT_OPENTYPE
))
1027 SAL_INFO("vcl.fonts", "Unsupported font ignored: " << OUString(o3tl::toU(pLogFont
->elfLogFont
.lfFaceName
)));
1031 rtl::Reference
<WinFontFace
> pData
= ImplLogMetricToDevFontDataW(pLogFont
, &(pMetric
->ntmTm
));
1032 pData
->SetFontId( sal_IntPtr( pInfo
->mnFontCount
++ ) );
1034 pInfo
->mpList
->Add( pData
.get() );
1035 SAL_INFO("vcl.fonts", "SalEnumFontsProcExW: font added: " << pData
->GetFamilyName() << " " << pData
->GetStyleName());
1043 OUString maFontResourcePath
;
1044 TempFontItem
* mpNextItem
;
1047 static int lcl_AddFontResource(SalData
& rSalData
, const OUString
& rFontFileURL
, bool bShared
)
1049 OUString aFontSystemPath
;
1050 OSL_VERIFY(!osl::FileBase::getSystemPathFromFileURL(rFontFileURL
, aFontSystemPath
));
1052 int nRet
= AddFontResourceExW(o3tl::toW(aFontSystemPath
.getStr()), FR_PRIVATE
, nullptr);
1053 SAL_WARN_IF(nRet
<= 0, "vcl.fonts", "AddFontResourceExW failed for " << rFontFileURL
);
1056 TempFontItem
* pNewItem
= new TempFontItem
;
1057 pNewItem
->maFontResourcePath
= aFontSystemPath
;
1060 pNewItem
->mpNextItem
= rSalData
.mpSharedTempFontItem
;
1061 rSalData
.mpSharedTempFontItem
= pNewItem
;
1065 pNewItem
->mpNextItem
= rSalData
.mpOtherTempFontItem
;
1066 rSalData
.mpOtherTempFontItem
= pNewItem
;
1072 void ImplReleaseTempFonts(SalData
& rSalData
, bool bAll
)
1074 while (TempFontItem
* p
= rSalData
.mpOtherTempFontItem
)
1076 RemoveFontResourceExW(o3tl::toW(p
->maFontResourcePath
.getStr()), FR_PRIVATE
, nullptr);
1077 rSalData
.mpOtherTempFontItem
= p
->mpNextItem
;
1084 while (TempFontItem
* p
= rSalData
.mpSharedTempFontItem
)
1086 RemoveFontResourceExW(o3tl::toW(p
->maFontResourcePath
.getStr()), FR_PRIVATE
, nullptr);
1087 rSalData
.mpSharedTempFontItem
= p
->mpNextItem
;
1092 static OUString
lcl_GetFontFamilyName(const OUString
& rFontFileURL
)
1094 // Create temporary file name
1095 OUString aTempFileURL
;
1096 if (osl::File::E_None
!= osl::File::createTempFile(nullptr, nullptr, &aTempFileURL
))
1098 osl::File::remove(aTempFileURL
);
1099 OUString aResSystemPath
;
1100 osl::FileBase::getSystemPathFromFileURL(aTempFileURL
, aResSystemPath
);
1102 // Create font resource file (.fot)
1103 // There is a limit of 127 characters for the full path passed via lpszFile, so we have to
1104 // split the font URL and pass it as two parameters. As a result we can't use
1105 // CreateScalableFontResource for renaming, as it now expects the font in the system path.
1106 // But it's still good to use it for family name extraction, we're currently after.
1107 // BTW: it doesn't help to prefix the lpszFile with \\?\ to support larger paths.
1108 // TODO: use TTLoadEmbeddedFont (needs an EOT as input, so we have to add a header to the TTF)
1109 // TODO: forward the EOT from the AddTempDevFont call side, if VCL supports it
1110 INetURLObject
aTTFUrl(rFontFileURL
);
1111 // GetBase() strips the extension
1112 OUString aFilename
= aTTFUrl
.GetLastName(INetURLObject::DecodeMechanism::WithCharset
);
1113 if (!CreateScalableFontResourceW(0, o3tl::toW(aResSystemPath
.getStr()),
1114 o3tl::toW(aFilename
.getStr()), o3tl::toW(aTTFUrl
.GetPath().getStr())))
1116 sal_uInt32 nError
= GetLastError();
1117 SAL_WARN("vcl.fonts", "CreateScalableFontResource failed for " << aResSystemPath
<< " "
1118 << aFilename
<< " " << aTTFUrl
.GetPath() << " " << nError
);
1122 // Open and read the font resource file
1123 osl::File
aFotFile(aTempFileURL
);
1124 if (osl::FileBase::E_None
!= aFotFile
.open(osl_File_OpenFlag_Read
))
1127 sal_uInt64 nBytesRead
= 0;
1129 aFotFile
.read( aBuffer
, sizeof( aBuffer
), nBytesRead
);
1130 // clean up temporary resource file
1132 osl::File::remove(aTempFileURL
);
1134 // retrieve font family name from byte offset 0x4F6
1135 static const sal_uInt64 nNameOfs
= 0x4F6;
1136 sal_uInt64 nPos
= nNameOfs
;
1137 for (; (nPos
< nBytesRead
) && (aBuffer
[nPos
] != 0); nPos
++);
1138 if (nPos
>= nBytesRead
|| (nPos
== nNameOfs
))
1141 return OUString(aBuffer
+ nNameOfs
, nPos
- nNameOfs
, osl_getThreadTextEncoding());
1144 bool WinSalGraphics::AddTempDevFont(PhysicalFontCollection
* pFontCollection
,
1145 const OUString
& rFontFileURL
, const OUString
& rFontName
)
1147 OUString aFontFamily
= lcl_GetFontFamilyName(rFontFileURL
);
1148 if (aFontFamily
.isEmpty())
1150 SAL_WARN("vcl.fonts", "error extracting font family from " << rFontFileURL
);
1154 if (rFontName
!= aFontFamily
)
1156 SAL_WARN("vcl.fonts", "font family renaming not implemented; skipping embedded " << rFontName
);
1160 int nFonts
= lcl_AddFontResource(*GetSalData(), rFontFileURL
, false);
1165 aInfo
.mhDC
= getHDC();
1166 aInfo
.mpList
= pFontCollection
;
1167 aInfo
.mpName
= &aFontFamily
;
1168 aInfo
.mbPrinter
= mbPrinter
;
1169 aInfo
.mnFontCount
= pFontCollection
->Count();
1170 const int nExpectedFontCount
= aInfo
.mnFontCount
+ nFonts
;
1172 LOGFONTW aLogFont
= {};
1173 aLogFont
.lfCharSet
= DEFAULT_CHARSET
;
1174 aInfo
.mpLogFont
= &aLogFont
;
1176 // add the font to the PhysicalFontCollection
1177 EnumFontFamiliesExW(getHDC(), &aLogFont
,
1178 SalEnumFontsProcExW
, reinterpret_cast<LPARAM
>(&aInfo
), 0);
1180 SAL_WARN_IF(nExpectedFontCount
!= pFontCollection
->Count(), "vcl.fonts",
1181 "temp font was registered but is not in enumeration: " << rFontFileURL
);
1186 void WinSalGraphics::GetDevFontList( PhysicalFontCollection
* pFontCollection
)
1188 // make sure all LO shared fonts are registered temporarily
1189 static std::once_flag init
;
1190 std::call_once(init
, []()
1192 auto registerFontsIn
= [](const OUString
& dir
) {
1193 // collect fonts in font path that could not be registered
1194 osl::Directory
aFontDir(dir
);
1195 osl::FileBase::RC rcOSL
= aFontDir
.open();
1196 if (rcOSL
== osl::FileBase::E_None
)
1198 osl::DirectoryItem aDirItem
;
1199 SalData
* pSalData
= GetSalData();
1202 while (aFontDir
.getNextItem(aDirItem
, 10) == osl::FileBase::E_None
)
1204 osl::FileStatus
aFileStatus(osl_FileStatus_Mask_FileURL
);
1205 rcOSL
= aDirItem
.getFileStatus(aFileStatus
);
1206 if (rcOSL
== osl::FileBase::E_None
)
1207 lcl_AddFontResource(*pSalData
, aFileStatus
.getFileURL(), true);
1212 // determine font path
1213 // since we are only interested in fonts that could not be
1214 // registered before because of missing administration rights
1215 // only the font path of the user installation is needed
1216 OUString
aPath("$BRAND_BASE_DIR");
1217 rtl_bootstrap_expandMacros(&aPath
.pData
);
1219 // internal font resources, required for normal operation, like OpenSymbol
1220 registerFontsIn(aPath
+ "/" LIBO_SHARE_RESOURCE_FOLDER
"/common/fonts");
1222 // collect fonts in font path that could not be registered
1223 registerFontsIn(aPath
+ "/" LIBO_SHARE_FOLDER
"/fonts/truetype");
1229 aInfo
.mhDC
= getHDC();
1230 aInfo
.mpList
= pFontCollection
;
1231 aInfo
.mpName
= nullptr;
1232 aInfo
.mbPrinter
= mbPrinter
;
1233 aInfo
.mnFontCount
= 0;
1235 LOGFONTW aLogFont
= {};
1236 aLogFont
.lfCharSet
= DEFAULT_CHARSET
;
1237 aInfo
.mpLogFont
= &aLogFont
;
1239 // fill the PhysicalFontCollection
1240 EnumFontFamiliesExW( getHDC(), &aLogFont
,
1241 SalEnumFontsProcExW
, reinterpret_cast<LPARAM
>(&aInfo
), 0 );
1243 // set glyph fallback hook
1244 static WinGlyphFallbackSubstititution aSubstFallback
;
1245 static WinPreMatchFontSubstititution aPreMatchFont
;
1246 pFontCollection
->SetFallbackHook( &aSubstFallback
);
1247 pFontCollection
->SetPreMatchHook(&aPreMatchFont
);
1250 void WinSalGraphics::ClearDevFontCache()
1252 WinSalGraphicsImplBase
* pImpl
= dynamic_cast<WinSalGraphicsImplBase
*>(GetImpl());
1253 assert(pImpl
!= nullptr);
1254 pImpl
->ClearDevFontCache();
1255 ImplReleaseTempFonts(*GetSalData(), false);
1258 bool WinFontInstance::ImplGetGlyphBoundRect(sal_GlyphId nId
, tools::Rectangle
& rRect
, bool) const
1260 assert(m_pGraphics
);
1261 HDC hDC
= m_pGraphics
->getHDC();
1262 const HFONT hOrigFont
= static_cast<HFONT
>(GetCurrentObject(hDC
, OBJ_FONT
));
1263 const HFONT hFont
= GetHFONT();
1264 if (hFont
!= hOrigFont
)
1265 SelectObject(hDC
, hFont
);
1267 const ::comphelper::ScopeGuard
aFontRestoreScopeGuard([hFont
, hOrigFont
, hDC
]()
1268 { if (hFont
!= hOrigFont
) SelectObject(hDC
, hOrigFont
); });
1269 const float fFontScale
= GetScale();
1273 aMat
.eM11
= aMat
.eM22
= FixedFromDouble( 1.0 );
1274 aMat
.eM12
= aMat
.eM21
= FixedFromDouble( 0.0 );
1276 UINT nGGOFlags
= GGO_METRICS
;
1277 nGGOFlags
|= GGO_GLYPH_INDEX
;
1280 aGM
.gmptGlyphOrigin
.x
= aGM
.gmptGlyphOrigin
.y
= 0;
1281 aGM
.gmBlackBoxX
= aGM
.gmBlackBoxY
= 0;
1282 DWORD nSize
= ::GetGlyphOutlineW(hDC
, nId
, nGGOFlags
, &aGM
, 0, nullptr, &aMat
);
1283 if (nSize
== GDI_ERROR
)
1286 rRect
= tools::Rectangle( Point( +aGM
.gmptGlyphOrigin
.x
, -aGM
.gmptGlyphOrigin
.y
),
1287 Size( aGM
.gmBlackBoxX
, aGM
.gmBlackBoxY
) );
1288 rRect
.SetLeft(static_cast<int>( fFontScale
* rRect
.Left() ));
1289 rRect
.SetRight(static_cast<int>( fFontScale
* rRect
.Right() ) + 1);
1290 rRect
.SetTop(static_cast<int>( fFontScale
* rRect
.Top() ));
1291 rRect
.SetBottom(static_cast<int>( fFontScale
* rRect
.Bottom() ) + 1);
1295 bool WinFontInstance::GetGlyphOutline(sal_GlyphId nId
, basegfx::B2DPolyPolygon
& rB2DPolyPoly
, bool) const
1297 rB2DPolyPoly
.clear();
1299 assert(m_pGraphics
);
1300 HDC hDC
= m_pGraphics
->getHDC();
1301 const HFONT hOrigFont
= static_cast<HFONT
>(GetCurrentObject(hDC
, OBJ_FONT
));
1302 const HFONT hFont
= GetHFONT();
1303 if (hFont
!= hOrigFont
)
1304 SelectObject(hDC
, hFont
);
1306 const ::comphelper::ScopeGuard
aFontRestoreScopeGuard([hFont
, hOrigFont
, hDC
]()
1307 { if (hFont
!= hOrigFont
) SelectObject(hDC
, hOrigFont
); });
1311 aMat
.eM11
= aMat
.eM22
= FixedFromDouble( 1.0 );
1312 aMat
.eM12
= aMat
.eM21
= FixedFromDouble( 0.0 );
1314 UINT nGGOFlags
= GGO_NATIVE
;
1315 nGGOFlags
|= GGO_GLYPH_INDEX
;
1317 GLYPHMETRICS aGlyphMetrics
;
1318 const DWORD nSize1
= ::GetGlyphOutlineW(hDC
, nId
, nGGOFlags
, &aGlyphMetrics
, 0, nullptr, &aMat
);
1319 if( !nSize1
) // blank glyphs are ok
1321 else if( nSize1
== GDI_ERROR
)
1324 BYTE
* pData
= new BYTE
[ nSize1
];
1325 const DWORD nSize2
= ::GetGlyphOutlineW(hDC
, nId
, nGGOFlags
,
1326 &aGlyphMetrics
, nSize1
, pData
, &aMat
);
1328 if( nSize1
!= nSize2
)
1331 // TODO: avoid tools polygon by creating B2DPolygon directly
1333 Point
* pPoints
= new Point
[ nPtSize
];
1334 PolyFlags
* pFlags
= new PolyFlags
[ nPtSize
];
1336 TTPOLYGONHEADER
* pHeader
= reinterpret_cast<TTPOLYGONHEADER
*>(pData
);
1337 while( reinterpret_cast<BYTE
*>(pHeader
) < pData
+nSize2
)
1339 // only outline data is interesting
1340 if( pHeader
->dwType
!= TT_POLYGON_TYPE
)
1343 // get start point; next start points are end points
1344 // of previous segment
1345 sal_uInt16 nPnt
= 0;
1347 tools::Long nX
= IntTimes256FromFixed( pHeader
->pfxStart
.x
);
1348 tools::Long nY
= IntTimes256FromFixed( pHeader
->pfxStart
.y
);
1349 pPoints
[ nPnt
] = Point( nX
, nY
);
1350 pFlags
[ nPnt
++ ] = PolyFlags::Normal
;
1352 bool bHasOfflinePoints
= false;
1353 TTPOLYCURVE
* pCurve
= reinterpret_cast<TTPOLYCURVE
*>( pHeader
+ 1 );
1354 pHeader
= reinterpret_cast<TTPOLYGONHEADER
*>( reinterpret_cast<BYTE
*>(pHeader
) + pHeader
->cb
);
1355 while( reinterpret_cast<BYTE
*>(pCurve
) < reinterpret_cast<BYTE
*>(pHeader
) )
1357 int nNeededSize
= nPnt
+ 16 + 3 * pCurve
->cpfx
;
1358 if( nPtSize
< nNeededSize
)
1360 Point
* pOldPoints
= pPoints
;
1361 PolyFlags
* pOldFlags
= pFlags
;
1362 nPtSize
= 2 * nNeededSize
;
1363 pPoints
= new Point
[ nPtSize
];
1364 pFlags
= new PolyFlags
[ nPtSize
];
1365 for( sal_uInt16 i
= 0; i
< nPnt
; ++i
)
1367 pPoints
[ i
] = pOldPoints
[ i
];
1368 pFlags
[ i
] = pOldFlags
[ i
];
1370 delete[] pOldPoints
;
1375 if( TT_PRIM_LINE
== pCurve
->wType
)
1377 while( i
< pCurve
->cpfx
)
1379 nX
= IntTimes256FromFixed( pCurve
->apfx
[ i
].x
);
1380 nY
= IntTimes256FromFixed( pCurve
->apfx
[ i
].y
);
1382 pPoints
[ nPnt
] = Point( nX
, nY
);
1383 pFlags
[ nPnt
] = PolyFlags::Normal
;
1387 else if( TT_PRIM_QSPLINE
== pCurve
->wType
)
1389 bHasOfflinePoints
= true;
1390 while( i
< pCurve
->cpfx
)
1392 // get control point of quadratic bezier spline
1393 nX
= IntTimes256FromFixed( pCurve
->apfx
[ i
].x
);
1394 nY
= IntTimes256FromFixed( pCurve
->apfx
[ i
].y
);
1396 Point
aControlP( nX
, nY
);
1398 // calculate first cubic control point
1399 // P0 = 1/3 * (PBeg + 2 * PQControl)
1400 nX
= pPoints
[ nPnt
-1 ].X() + 2 * aControlP
.X();
1401 nY
= pPoints
[ nPnt
-1 ].Y() + 2 * aControlP
.Y();
1402 pPoints
[ nPnt
+0 ] = Point( (2*nX
+3)/6, (2*nY
+3)/6 );
1403 pFlags
[ nPnt
+0 ] = PolyFlags::Control
;
1405 // calculate endpoint of segment
1406 nX
= IntTimes256FromFixed( pCurve
->apfx
[ i
].x
);
1407 nY
= IntTimes256FromFixed( pCurve
->apfx
[ i
].y
);
1409 if ( i
+1 >= pCurve
->cpfx
)
1411 // endpoint is either last point in segment => advance
1416 // or endpoint is the middle of two control points
1417 nX
+= IntTimes256FromFixed( pCurve
->apfx
[ i
-1 ].x
);
1418 nY
+= IntTimes256FromFixed( pCurve
->apfx
[ i
-1 ].y
);
1421 // no need to advance, because the current point
1422 // is the control point in next bezier spline
1425 pPoints
[ nPnt
+2 ] = Point( nX
, nY
);
1426 pFlags
[ nPnt
+2 ] = PolyFlags::Normal
;
1428 // calculate second cubic control point
1429 // P1 = 1/3 * (PEnd + 2 * PQControl)
1430 nX
= pPoints
[ nPnt
+2 ].X() + 2 * aControlP
.X();
1431 nY
= pPoints
[ nPnt
+2 ].Y() + 2 * aControlP
.Y();
1432 pPoints
[ nPnt
+1 ] = Point( (2*nX
+3)/6, (2*nY
+3)/6 );
1433 pFlags
[ nPnt
+1 ] = PolyFlags::Control
;
1439 // next curve segment
1440 pCurve
= reinterpret_cast<TTPOLYCURVE
*>(&pCurve
->apfx
[ i
]);
1443 // end point is start point for closed contour
1444 // disabled, because Polygon class closes the contour itself
1445 // pPoints[nPnt++] = pPoints[0];
1447 // Added again, but add only when not yet closed
1448 if(pPoints
[nPnt
- 1] != pPoints
[0])
1450 if( bHasOfflinePoints
)
1451 pFlags
[nPnt
] = pFlags
[0];
1453 pPoints
[nPnt
++] = pPoints
[0];
1456 // convert y-coordinates W32 -> VCL
1457 for( int i
= 0; i
< nPnt
; ++i
)
1458 pPoints
[i
].setY(-pPoints
[i
].Y());
1460 // insert into polypolygon
1461 tools::Polygon
aPoly( nPnt
, pPoints
, (bHasOfflinePoints
? pFlags
: nullptr) );
1462 // convert to B2DPolyPolygon
1463 // TODO: get rid of the intermediate PolyPolygon
1464 rB2DPolyPoly
.append( aPoly
.getB2DPolygon() );
1472 // rescaling needed for the tools::PolyPolygon conversion
1473 if( rB2DPolyPoly
.count() )
1475 const double fFactor(GetScale()/256);
1476 rB2DPolyPoly
.transform(basegfx::utils::createScaleB2DHomMatrix(fFactor
, fFactor
));
1485 explicit ScopedFont(WinSalGraphics
& rData
);
1490 WinSalGraphics
& m_rData
;
1494 ScopedFont::ScopedFont(WinSalGraphics
& rData
): m_rData(rData
), m_hOrigFont(nullptr)
1496 if (m_rData
.mpWinFontEntry
[0])
1498 m_hOrigFont
= m_rData
.mpWinFontEntry
[0]->GetHFONT();
1499 m_rData
.mpWinFontEntry
[0]->SetHFONT(nullptr);
1503 ScopedFont::~ScopedFont()
1507 // restore original font, destroy temporary font
1508 HFONT hTempFont
= m_rData
.mpWinFontEntry
[0]->GetHFONT();
1509 m_rData
.mpWinFontEntry
[0]->SetHFONT(m_hOrigFont
);
1510 SelectObject( m_rData
.getHDC(), m_hOrigFont
);
1511 DeleteObject( hTempFont
);
1517 class ScopedTrueTypeFont
1520 ScopedTrueTypeFont(): m_pFont(nullptr) {}
1522 ~ScopedTrueTypeFont();
1524 SFErrCodes
open(void const * pBuffer
, sal_uInt32 nLen
, sal_uInt32 nFaceNum
, const FontCharMapRef xCharMap
= nullptr);
1526 TrueTypeFont
* get() const { return m_pFont
; }
1529 TrueTypeFont
* m_pFont
;
1534 ScopedTrueTypeFont::~ScopedTrueTypeFont()
1536 if (m_pFont
!= nullptr)
1537 CloseTTFont(m_pFont
);
1540 SFErrCodes
ScopedTrueTypeFont::open(void const * pBuffer
, sal_uInt32 nLen
,
1541 sal_uInt32 nFaceNum
, const FontCharMapRef xCharMap
)
1543 OSL_ENSURE(m_pFont
== nullptr, "already open");
1544 return OpenTTFontBuffer(pBuffer
, nLen
, nFaceNum
, &m_pFont
, xCharMap
);
1547 bool WinSalGraphics::CreateFontSubset( const OUString
& rToFile
,
1548 const PhysicalFontFace
* pFont
, const sal_GlyphId
* pGlyphIds
, const sal_uInt8
* pEncoding
,
1549 sal_Int32
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& rInfo
)
1551 // TODO: use more of the central font-subsetting code, move stuff there if needed
1553 // create matching FontSelectPattern
1554 // we need just enough to get to the font file data
1555 // use height=1000 for easier debugging (to match psprint's font units)
1556 FontSelectPattern
aIFSD( *pFont
, Size(0,1000), 1000.0, 0, false );
1558 // TODO: much better solution: move SetFont and restoration of old font to caller
1559 ScopedFont
aOldFont(*this);
1560 HFONT hOldFont
= nullptr;
1561 ImplDoSetFont(aIFSD
, pFont
, hOldFont
);
1563 WinFontFace
const * pWinFontData
= static_cast<WinFontFace
const *>(pFont
);
1565 #if OSL_DEBUG_LEVEL > 1
1567 TEXTMETRICW aWinMetric
;
1568 if( !::GetTextMetricsW( getHDC(), &aWinMetric
) )
1571 SAL_WARN_IF( (aWinMetric
.tmPitchAndFamily
& TMPF_DEVICE
), "vcl", "cannot subset device font" );
1572 SAL_WARN_IF( !(aWinMetric
.tmPitchAndFamily
& TMPF_TRUETYPE
), "vcl", "can only subset TT font" );
1576 if( osl_File_E_None
!= osl_getSystemPathFromFileURL( rToFile
.pData
, &aSysPath
.pData
) )
1578 const rtl_TextEncoding aThreadEncoding
= osl_getThreadTextEncoding();
1579 const OString
aToFile(OUStringToOString(aSysPath
, aThreadEncoding
));
1581 // check if the font has a CFF-table
1582 const DWORD nCffTag
= CalcTag( "CFF " );
1583 const RawFontData
aRawCffData( getHDC(), nCffTag
);
1584 if (aRawCffData
.get())
1586 pWinFontData
->UpdateFromHDC( getHDC() );
1587 return SalGraphics::CreateCFFfontSubset(aRawCffData
.get(), aRawCffData
.size(), aToFile
,
1588 pGlyphIds
, pEncoding
, pGlyphWidths
, nGlyphCount
,
1592 // get raw font file data
1593 const RawFontData
xRawFontData( getHDC(), 0 );
1594 if( !xRawFontData
.get() )
1598 sal_uInt32 nFaceNum
= 0;
1599 if( !*xRawFontData
.get() ) // TTC candidate
1600 nFaceNum
= ~0U; // indicate "TTC font extracts only"
1602 ScopedTrueTypeFont aSftTTF
;
1603 SFErrCodes nRC
= aSftTTF
.open( xRawFontData
.get(), xRawFontData
.size(), nFaceNum
, pFont
->GetFontCharMap());
1604 if( nRC
!= SFErrCodes::Ok
)
1607 TTGlobalFontInfo aTTInfo
;
1608 ::GetTTGlobalFontInfo( aSftTTF
.get(), &aTTInfo
);
1609 OUString aPSName
= ImplSalGetUniString(aTTInfo
.psname
);
1610 FillFontSubsetInfo(aTTInfo
, aPSName
, rInfo
);
1612 // write subset into destination file
1613 return SalGraphics::CreateTTFfontSubset(*aSftTTF
.get(), aToFile
, aIFSD
.mbVertical
, pGlyphIds
,
1614 pEncoding
, pGlyphWidths
, nGlyphCount
);
1617 const void* WinSalGraphics::GetEmbedFontData(const PhysicalFontFace
* pFont
, tools::Long
* pDataLen
)
1619 // create matching FontSelectPattern
1620 // we need just enough to get to the font file data
1621 FontSelectPattern
aIFSD( *pFont
, Size(0,1000), 1000.0, 0, false );
1623 ScopedFont
aOldFont(*this);
1625 HFONT hOldFont
= nullptr;
1626 ImplDoSetFont(aIFSD
, pFont
, hOldFont
);
1628 // get the raw font file data
1629 RawFontData
aRawFontData( getHDC() );
1630 *pDataLen
= aRawFontData
.size();
1631 if( !aRawFontData
.get() )
1634 const unsigned char* pData
= aRawFontData
.steal();
1638 void WinSalGraphics::FreeEmbedFontData( const void* pData
, tools::Long
/*nLen*/ )
1640 delete[] static_cast<char const *>(pData
);
1643 void WinSalGraphics::GetGlyphWidths( const PhysicalFontFace
* pFont
,
1645 std::vector
< sal_Int32
>& rWidths
,
1646 Ucs2UIntMap
& rUnicodeEnc
)
1648 // create matching FontSelectPattern
1649 // we need just enough to get to the font file data
1650 FontSelectPattern
aIFSD( *pFont
, Size(0,1000), 1000.0, 0, false );
1652 // TODO: much better solution: move SetFont and restoration of old font to caller
1653 ScopedFont
aOldFont(*this);
1655 HFONT hOldFont
= nullptr;
1656 ImplDoSetFont(aIFSD
, pFont
, hOldFont
);
1658 // get raw font file data
1659 const RawFontData
xRawFontData( getHDC() );
1660 if( !xRawFontData
.get() )
1664 sal_uInt32 nFaceNum
= 0;
1665 if( !*xRawFontData
.get() ) // TTC candidate
1666 nFaceNum
= ~0U; // indicate "TTC font extracts only"
1668 ScopedTrueTypeFont aSftTTF
;
1669 SFErrCodes nRC
= aSftTTF
.open(xRawFontData
.get(), xRawFontData
.size(), nFaceNum
, pFont
->GetFontCharMap());
1670 if( nRC
!= SFErrCodes::Ok
)
1673 SalGraphics::GetGlyphWidths(*aSftTTF
.get(), *pFont
, bVertical
, rWidths
, rUnicodeEnc
);
1676 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */