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/config.h>
22 #include <sal/types.h>
23 #include <config_folders.h>
31 #include <string_view>
36 #include <o3tl/lru_map.hxx>
37 #include <basegfx/matrix/b2dhommatrixtools.hxx>
38 #include <basegfx/polygon/b2dpolygon.hxx>
39 #include <i18nlangtag/mslangid.hxx>
40 #include <osl/diagnose.h>
41 #include <osl/file.hxx>
42 #include <osl/process.h>
43 #include <rtl/bootstrap.hxx>
44 #include <rtl/tencinfo.h>
45 #include <sal/log.hxx>
46 #include <o3tl/char16_t2wchar_t.hxx>
47 #include <tools/helpers.hxx>
48 #include <tools/stream.hxx>
49 #include <tools/urlobj.hxx>
50 #include <unotools/fontcfg.hxx>
51 #include <vcl/settings.hxx>
52 #include <vcl/sysdata.hxx>
53 #include <vcl/metric.hxx>
54 #include <vcl/fontcharmap.hxx>
55 #include <comphelper/scopeguard.hxx>
56 #include <comphelper/windowserrorstring.hxx>
58 #include <font/FontSelectPattern.hxx>
59 #include <font/PhysicalFontCollection.hxx>
60 #include <font/PhysicalFontFaceCollection.hxx>
61 #include <font/PhysicalFontFace.hxx>
62 #include <font/fontsubstitution.hxx>
64 #include <win/saldata.hxx>
65 #include <win/salgdi.h>
66 #include <win/winlayout.hxx>
67 #include <win/wingdiimpl.hxx>
68 #include <impfontcharmap.hxx>
69 #include <font/FontMetricData.hxx>
70 #include <impglyphitem.hxx>
73 #include <vcl/skia/SkiaHelper.hxx>
74 #include <skia/win/font.hxx>
79 static FIXED
FixedFromDouble( double d
)
81 const tools::Long l
= static_cast<tools::Long
>( d
* 65536. );
82 return *reinterpret_cast<FIXED
const *>(&l
);
85 static int IntTimes256FromFixed(FIXED f
)
87 int nFixedTimes256
= (f
.value
<< 8) + ((f
.fract
+0x80) >> 8);
88 return nFixedTimes256
;
91 // platform specific font substitution hooks for glyph fallback enhancement
95 class WinPreMatchFontSubstititution
96 : public vcl::font::PreMatchFontSubstitution
99 bool FindFontSubstitute(vcl::font::FontSelectPattern
&) const override
;
102 class WinGlyphFallbackSubstititution
103 : public vcl::font::GlyphFallbackFontSubstitution
106 bool FindFontSubstitute(vcl::font::FontSelectPattern
&, LogicalFontInstance
* pLogicalFont
, OUString
& rMissingChars
) const override
;
109 // does a font face hold the given missing characters?
110 bool HasMissingChars(vcl::font::PhysicalFontFace
* pFace
, OUString
& rMissingChars
)
112 FontCharMapRef xFontCharMap
= pFace
->GetFontCharMap();
114 // avoid fonts with unknown CMAP subtables for glyph fallback
115 if( !xFontCharMap
.is() || xFontCharMap
->IsDefaultMap() )
119 std::vector
<sal_UCS4
> rRemainingCodes
;
120 const sal_Int32 nStrLen
= rMissingChars
.getLength();
121 sal_Int32 nStrIdx
= 0;
122 while (nStrIdx
< nStrLen
)
124 const sal_UCS4 uChar
= rMissingChars
.iterateCodePoints( &nStrIdx
);
125 if (xFontCharMap
->HasChar(uChar
))
128 rRemainingCodes
.push_back(uChar
);
131 xFontCharMap
= nullptr;
134 rMissingChars
= OUString(rRemainingCodes
.data(), rRemainingCodes
.size());
136 return nMatchCount
> 0;
139 //used by 2-level font fallback
140 vcl::font::PhysicalFontFamily
* findDevFontListByLocale(const vcl::font::PhysicalFontCollection
&rFontCollection
,
141 const LanguageTag
& rLanguageTag
)
143 // get the default font for a specified locale
144 const utl::DefaultFontConfiguration
& rDefaults
= utl::DefaultFontConfiguration::get();
145 const OUString aDefault
= rDefaults
.getUserInterfaceFont(rLanguageTag
);
146 return rFontCollection
.FindFontFamilyByTokenNames(aDefault
);
150 // These are Win 3.1 bitmap fonts using "FON" font format
151 // which is not supported with DirectWrite so let's substitute them
152 // with a font that is supported and always available.
154 // https://dxr.mozilla.org/mozilla-esr10/source/gfx/thebes/gfxDWriteFontList.cpp#1057
155 const std::map
<OUString
, OUString
> aBitmapFontSubs
=
157 { "MS Sans Serif", "Microsoft Sans Serif" },
158 { "MS Serif", "Times New Roman" },
159 { "Small Fonts", "Arial" },
160 { "Courier", "Courier New" },
161 { "Roman", "Times New Roman" },
162 { "Script", "Mistral" }
165 // TODO: See if Windows have API that we can use here to improve font fallback.
166 bool WinPreMatchFontSubstititution::FindFontSubstitute(vcl::font::FontSelectPattern
& rFontSelData
) const
168 if (rFontSelData
.IsMicrosoftSymbolEncoded() || IsOpenSymbol(rFontSelData
.maSearchName
))
171 for (const auto& aSub
: aBitmapFontSubs
)
173 if (rFontSelData
.maSearchName
== GetEnglishSearchFontName(aSub
.first
))
175 rFontSelData
.maSearchName
= aSub
.second
;
183 // find a fallback font for missing characters
184 // TODO: should stylistic matches be searched and preferred?
185 bool WinGlyphFallbackSubstititution::FindFontSubstitute(vcl::font::FontSelectPattern
& rFontSelData
, LogicalFontInstance
* /*pLogicalFont*/, OUString
& rMissingChars
) const
187 // guess a locale matching to the missing chars
188 LanguageType eLang
= rFontSelData
.meLanguage
;
189 LanguageTag
aLanguageTag( eLang
);
191 // fall back to default UI locale if the font language is inconclusive
192 if( eLang
== LANGUAGE_DONTKNOW
)
193 aLanguageTag
= Application::GetSettings().GetUILanguageTag();
195 // first level fallback:
196 // try use the locale specific default fonts defined in VCL.xcu
197 const vcl::font::PhysicalFontCollection
* pFontCollection
= ImplGetSVData()->maGDIData
.mxScreenFontList
.get();
198 vcl::font::PhysicalFontFamily
* pFontFamily
= findDevFontListByLocale(*pFontCollection
, aLanguageTag
);
201 vcl::font::PhysicalFontFace
* pFace
= pFontFamily
->FindBestFontFace( rFontSelData
);
202 if( HasMissingChars( pFace
, rMissingChars
) )
204 rFontSelData
.maSearchName
= pFontFamily
->GetSearchName();
209 // are the missing characters symbols?
210 pFontFamily
= pFontCollection
->FindFontFamilyByAttributes( ImplFontAttrs::Symbol
,
211 rFontSelData
.GetWeight(),
212 rFontSelData
.GetWidthType(),
213 rFontSelData
.GetItalic(),
214 rFontSelData
.maSearchName
);
217 vcl::font::PhysicalFontFace
* pFace
= pFontFamily
->FindBestFontFace( rFontSelData
);
218 if( HasMissingChars( pFace
, rMissingChars
) )
220 rFontSelData
.maSearchName
= pFontFamily
->GetSearchName();
225 // last level fallback, check each font type face one by one
226 std::unique_ptr
<vcl::font::PhysicalFontFaceCollection
> pTestFontList
= pFontCollection
->GetFontFaceCollection();
227 // limit the count of fonts to be checked to prevent hangs
228 static const int MAX_GFBFONT_COUNT
= 600;
229 int nTestFontCount
= pTestFontList
->Count();
230 if( nTestFontCount
> MAX_GFBFONT_COUNT
)
231 nTestFontCount
= MAX_GFBFONT_COUNT
;
234 for( int i
= 0; i
< nTestFontCount
; ++i
)
236 vcl::font::PhysicalFontFace
* pFace
= pTestFontList
->Get( i
);
237 bFound
= HasMissingChars( pFace
, rMissingChars
);
240 rFontSelData
.maSearchName
= pFace
->GetFamilyName();
252 vcl::font::PhysicalFontCollection
* mpList
;
261 static rtl_TextEncoding
ImplCharSetToSal( BYTE nCharSet
)
263 rtl_TextEncoding eTextEncoding
;
265 if ( nCharSet
== OEM_CHARSET
)
267 UINT nCP
= static_cast<sal_uInt16
>(GetOEMCP());
270 // It is unclear why these two (undefined?) code page numbers are
271 // handled specially here:
272 case 1004: eTextEncoding
= RTL_TEXTENCODING_MS_1252
; break;
273 case 65400: eTextEncoding
= RTL_TEXTENCODING_SYMBOL
; break;
275 eTextEncoding
= rtl_getTextEncodingFromWindowsCodePage(nCP
);
282 eTextEncoding
= rtl_getTextEncodingFromWindowsCharset( nCharSet
);
284 eTextEncoding
= RTL_TEXTENCODING_UNICODE
;
287 return eTextEncoding
;
290 static FontFamily
ImplFamilyToSal( BYTE nFamily
)
292 switch ( nFamily
& 0xF0 )
295 return FAMILY_DECORATIVE
;
298 return FAMILY_MODERN
;
304 return FAMILY_SCRIPT
;
313 return FAMILY_DONTKNOW
;
316 static BYTE
ImplFamilyToWin( FontFamily eFamily
)
320 case FAMILY_DECORATIVE
:
321 return FF_DECORATIVE
;
345 static FontWeight
ImplWeightToSal( int nWeight
)
347 if ( nWeight
<= FW_THIN
)
349 else if ( nWeight
<= FW_ULTRALIGHT
)
350 return WEIGHT_ULTRALIGHT
;
351 else if ( nWeight
<= FW_LIGHT
)
353 else if ( nWeight
< FW_MEDIUM
)
354 return WEIGHT_NORMAL
;
355 else if ( nWeight
== FW_MEDIUM
)
356 return WEIGHT_MEDIUM
;
357 else if ( nWeight
<= FW_SEMIBOLD
)
358 return WEIGHT_SEMIBOLD
;
359 else if ( nWeight
<= FW_BOLD
)
361 else if ( nWeight
<= FW_ULTRABOLD
)
362 return WEIGHT_ULTRABOLD
;
367 static int ImplWeightToWin( FontWeight eWeight
)
374 case WEIGHT_ULTRALIGHT
:
375 return FW_ULTRALIGHT
;
380 case WEIGHT_SEMILIGHT
:
387 case WEIGHT_SEMIBOLD
:
393 case WEIGHT_ULTRABOLD
:
406 static FontPitch
ImplLogPitchToSal( BYTE nPitch
)
408 if ( nPitch
& FIXED_PITCH
)
411 return PITCH_VARIABLE
;
414 static FontPitch
ImplMetricPitchToSal( BYTE nPitch
)
416 // Grrrr! See NT help
417 if ( !(nPitch
& TMPF_FIXED_PITCH
) )
420 return PITCH_VARIABLE
;
423 static BYTE
ImplPitchToWin( FontPitch ePitch
)
425 if ( ePitch
== PITCH_FIXED
)
427 else if ( ePitch
== PITCH_VARIABLE
)
428 return VARIABLE_PITCH
;
430 return DEFAULT_PITCH
;
433 static FontAttributes
WinFont2DevFontAttributes( const ENUMLOGFONTEXW
& rEnumFont
,
434 const NEWTEXTMETRICW
& rMetric
)
438 const LOGFONTW rLogFont
= rEnumFont
.elfLogFont
;
440 // get font face attributes
441 aDFA
.SetFamilyType(ImplFamilyToSal( rLogFont
.lfPitchAndFamily
));
442 aDFA
.SetWidthType(WIDTH_DONTKNOW
);
443 aDFA
.SetWeight(ImplWeightToSal( rLogFont
.lfWeight
));
444 aDFA
.SetItalic((rLogFont
.lfItalic
) ? ITALIC_NORMAL
: ITALIC_NONE
);
445 aDFA
.SetPitch(ImplLogPitchToSal( rLogFont
.lfPitchAndFamily
));
446 aDFA
.SetMicrosoftSymbolEncoded(rLogFont
.lfCharSet
== SYMBOL_CHARSET
);
448 // get the font face name
449 aDFA
.SetFamilyName(OUString(o3tl::toU(rLogFont
.lfFaceName
)));
451 // use the face's style name only if it looks reasonable
452 const wchar_t* pStyleName
= rEnumFont
.elfStyle
;
453 const wchar_t* pEnd
= pStyleName
+ sizeof(rEnumFont
.elfStyle
)/sizeof(*rEnumFont
.elfStyle
);
454 const wchar_t* p
= pStyleName
;
455 for(; *p
&& (p
< pEnd
); ++p
)
459 aDFA
.SetStyleName(OUString(o3tl::toU(pStyleName
)));
461 // heuristics for font quality
462 // - opentypeTT > truetype
463 aDFA
.SetQuality( 0 );
464 if( rMetric
.tmPitchAndFamily
& TMPF_TRUETYPE
)
465 aDFA
.IncreaseQualityBy( 50 );
466 if( 0 != (rMetric
.ntmFlags
& (NTM_TT_OPENTYPE
| NTM_PS_OPENTYPE
)) )
467 aDFA
.IncreaseQualityBy( 10 );
469 // TODO: add alias names
473 void ImplSalLogFontToFontW( HDC hDC
, const LOGFONTW
& rLogFont
, Font
& rFont
)
475 OUString
aFontName( o3tl::toU(rLogFont
.lfFaceName
) );
476 if (!aFontName
.isEmpty())
478 rFont
.SetFamilyName( aFontName
);
479 rFont
.SetCharSet( ImplCharSetToSal( rLogFont
.lfCharSet
) );
480 rFont
.SetFamily( ImplFamilyToSal( rLogFont
.lfPitchAndFamily
) );
481 rFont
.SetPitch( ImplLogPitchToSal( rLogFont
.lfPitchAndFamily
) );
482 rFont
.SetWeight( ImplWeightToSal( rLogFont
.lfWeight
) );
484 tools::Long nFontHeight
= rLogFont
.lfHeight
;
485 if ( nFontHeight
< 0 )
486 nFontHeight
= -nFontHeight
;
487 tools::Long nDPIY
= GetDeviceCaps( hDC
, LOGPIXELSY
);
491 nFontHeight
+= nDPIY
/2;
492 nFontHeight
/= nDPIY
;
493 rFont
.SetFontSize( Size( 0, nFontHeight
) );
494 rFont
.SetOrientation( Degree10(static_cast<sal_Int16
>(rLogFont
.lfEscapement
)) );
495 if ( rLogFont
.lfItalic
)
496 rFont
.SetItalic( ITALIC_NORMAL
);
498 rFont
.SetItalic( ITALIC_NONE
);
499 if ( rLogFont
.lfUnderline
)
500 rFont
.SetUnderline( LINESTYLE_SINGLE
);
502 rFont
.SetUnderline( LINESTYLE_NONE
);
503 if ( rLogFont
.lfStrikeOut
)
504 rFont
.SetStrikeout( STRIKEOUT_SINGLE
);
506 rFont
.SetStrikeout( STRIKEOUT_NONE
);
510 WinFontFace::WinFontFace(const ENUMLOGFONTEXW
& rEnumFont
, const NEWTEXTMETRICW
& rMetric
)
511 : vcl::font::PhysicalFontFace(WinFont2DevFontAttributes(rEnumFont
, rMetric
)),
513 meWinCharSet(rEnumFont
.elfLogFont
.lfCharSet
),
514 mnPitchAndFamily(rMetric
.tmPitchAndFamily
),
515 maLogFont(rEnumFont
.elfLogFont
)
519 WinFontFace::~WinFontFace()
523 sal_IntPtr
WinFontFace::GetFontId() const
528 rtl::Reference
<LogicalFontInstance
> WinFontFace::CreateFontInstance(const vcl::font::FontSelectPattern
& rFSD
) const
530 #if HAVE_FEATURE_SKIA
531 if (SkiaHelper::isVCLSkiaEnabled())
532 return new SkiaWinFontInstance(*this, rFSD
);
534 return new WinFontInstance(*this, rFSD
);
537 const std::vector
<hb_variation_t
>&
538 WinFontFace::GetVariations(const LogicalFontInstance
& rFont
) const
542 mxVariations
.emplace();
543 auto pDWFontFace
= static_cast<const WinFontInstance
&>(rFont
).GetDWFontFace();
546 sal::systools::COMReference
<IDWriteFontFace5
> xDWFontFace5
;
547 auto hr
= pDWFontFace
->QueryInterface(__uuidof(IDWriteFontFace5
),
548 reinterpret_cast<void**>(&xDWFontFace5
));
549 if (SUCCEEDED(hr
) && xDWFontFace5
->HasVariations())
551 std::vector
<DWRITE_FONT_AXIS_VALUE
> aAxisValues(
552 xDWFontFace5
->GetFontAxisValueCount());
553 hr
= xDWFontFace5
->GetFontAxisValues(aAxisValues
.data(), aAxisValues
.size());
556 mxVariations
->reserve(aAxisValues
.size());
557 for (auto& rAxisValue
: aAxisValues
)
558 mxVariations
->push_back(
559 { OSL_NETDWORD(rAxisValue
.axisTag
), rAxisValue
.value
});
565 return *mxVariations
;
573 BlobReference(hb_blob_t
* pBlob
)
576 hb_blob_reference(mpBlob
);
578 BlobReference(BlobReference
&& other
) noexcept
579 : mpBlob(other
.mpBlob
)
581 other
.mpBlob
= nullptr;
583 BlobReference
& operator=(BlobReference
&& other
)
585 std::swap(mpBlob
, other
.mpBlob
);
588 BlobReference(const BlobReference
& other
) = delete;
589 BlobReference
& operator=(BlobReference
& other
) = delete;
590 ~BlobReference() { hb_blob_destroy(mpBlob
); }
594 using BlobCacheKey
= std::pair
<sal_IntPtr
, hb_tag_t
>;
598 struct BlobCacheKeyHash
600 std::size_t operator()(BlobCacheKey
const& rKey
) const
602 std::size_t seed
= 0;
603 o3tl::hash_combine(seed
, rKey
.first
);
604 o3tl::hash_combine(seed
, rKey
.second
);
610 hb_blob_t
* WinFontFace::GetHbTable(hb_tag_t nTag
) const
612 static o3tl::lru_map
<BlobCacheKey
, BlobReference
, BlobCacheKeyHash
> gCache(50);
613 BlobCacheKey aCacheKey
{ GetFontId(), nTag
};
614 auto it
= gCache
.find(aCacheKey
);
615 if (it
!= gCache
.end())
617 hb_blob_reference(it
->second
.mpBlob
);
618 return it
->second
.mpBlob
;
621 sal_uLong nLength
= 0;
622 unsigned char* pBuffer
= nullptr;
624 HDC
hDC(::GetDC(nullptr));
625 HFONT hFont
= ::CreateFontIndirectW(&maLogFont
);
626 HFONT hOldFont
= ::SelectFont(hDC
, hFont
);
628 nLength
= ::GetFontData(hDC
, OSL_NETDWORD(nTag
), 0, nullptr, 0);
629 if (nLength
> 0 && nLength
!= GDI_ERROR
)
631 pBuffer
= new unsigned char[nLength
];
632 ::GetFontData(hDC
, OSL_NETDWORD(nTag
), 0, pBuffer
, nLength
);
635 ::SelectFont(hDC
, hOldFont
);
637 ::ReleaseDC(nullptr, hDC
);
639 hb_blob_t
* pBlob
= nullptr;
642 pBlob
= hb_blob_create(reinterpret_cast<const char*>(pBuffer
), nLength
, HB_MEMORY_MODE_READONLY
,
643 pBuffer
, [](void* data
) { delete[] static_cast<unsigned char*>(data
); });
645 gCache
.insert({ aCacheKey
, BlobReference(pBlob
) });
649 void WinSalGraphics::SetTextColor( Color nColor
)
651 COLORREF aCol
= PALETTERGB( nColor
.GetRed(),
656 GetSalData()->mhDitherPal
&&
657 ImplIsSysColorEntry( nColor
) )
659 aCol
= PALRGB_TO_RGB( aCol
);
662 ::SetTextColor( getHDC(), aCol
);
665 static int CALLBACK
SalEnumQueryFontProcExW( const LOGFONTW
*, const TEXTMETRICW
*, DWORD
, LPARAM lParam
)
667 *reinterpret_cast<bool*>(lParam
) = true;
671 void ImplGetLogFontFromFontSelect( const vcl::font::FontSelectPattern
& rFont
,
672 const vcl::font::PhysicalFontFace
* pFontFace
,
673 LOGFONTW
& rLogFont
, bool bAntiAliased
)
677 aName
= pFontFace
->GetFamilyName();
679 aName
= rFont
.GetFamilyName().getToken( 0, ';' );
681 UINT nNameLen
= aName
.getLength();
682 if (nNameLen
>= LF_FACESIZE
)
683 nNameLen
= LF_FACESIZE
- 1;
684 memcpy( rLogFont
.lfFaceName
, aName
.getStr(), nNameLen
*sizeof( wchar_t ) );
685 rLogFont
.lfFaceName
[nNameLen
] = 0;
689 const WinFontFace
* pWinFontData
= static_cast<const WinFontFace
*>(pFontFace
);
690 rLogFont
.lfCharSet
= pWinFontData
->GetCharSet();
691 rLogFont
.lfPitchAndFamily
= pWinFontData
->GetPitchAndFamily();
695 rLogFont
.lfCharSet
= rFont
.IsMicrosoftSymbolEncoded() ? SYMBOL_CHARSET
: DEFAULT_CHARSET
;
696 rLogFont
.lfPitchAndFamily
= ImplPitchToWin( rFont
.GetPitch() )
697 | ImplFamilyToWin( rFont
.GetFamilyType() );
700 rLogFont
.lfWeight
= ImplWeightToWin( rFont
.GetWeight() );
701 rLogFont
.lfHeight
= static_cast<LONG
>(-rFont
.mnHeight
);
702 rLogFont
.lfWidth
= static_cast<LONG
>(rFont
.mnWidth
);
703 rLogFont
.lfUnderline
= 0;
704 rLogFont
.lfStrikeOut
= 0;
705 rLogFont
.lfItalic
= BYTE(rFont
.GetItalic() != ITALIC_NONE
);
706 rLogFont
.lfEscapement
= rFont
.mnOrientation
.get();
707 rLogFont
.lfOrientation
= rLogFont
.lfEscapement
;
708 rLogFont
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
709 rLogFont
.lfOutPrecision
= OUT_TT_PRECIS
;
710 if ( rFont
.mnOrientation
)
711 rLogFont
.lfClipPrecision
|= CLIP_LH_ANGLES
;
713 // disable antialiasing if requested
714 if ( rFont
.mbNonAntialiased
)
715 rLogFont
.lfQuality
= NONANTIALIASED_QUALITY
;
716 else if (Application::GetSettings().GetStyleSettings().GetUseFontAAFromSystem())
717 rLogFont
.lfQuality
= DEFAULT_QUALITY
; // for display on screen
719 rLogFont
.lfQuality
= bAntiAliased
? ANTIALIASED_QUALITY
: NONANTIALIASED_QUALITY
;
722 std::tuple
<HFONT
,bool,sal_Int32
> WinSalGraphics::ImplDoSetFont(HDC hDC
, vcl::font::FontSelectPattern
const & i_rFont
,
723 const vcl::font::PhysicalFontFace
* i_pFontFace
,
726 HFONT hNewFont
= nullptr;
729 ImplGetLogFontFromFontSelect( i_rFont
, i_pFontFace
, aLogFont
, getAntiAlias());
731 bool bIsCJKVerticalFont
= false;
732 // select vertical mode for printing if requested and available
733 if ( i_rFont
.mbVertical
&& mbPrinter
)
735 constexpr size_t nLen
= sizeof(aLogFont
.lfFaceName
) - sizeof(aLogFont
.lfFaceName
[0]);
736 // vertical fonts start with an '@'
737 memmove( &aLogFont
.lfFaceName
[1], &aLogFont
.lfFaceName
[0], nLen
);
738 aLogFont
.lfFaceName
[0] = '@';
739 aLogFont
.lfFaceName
[LF_FACESIZE
- 1] = 0;
741 // check availability of vertical mode for this font
742 EnumFontFamiliesExW( getHDC(), &aLogFont
, SalEnumQueryFontProcExW
,
743 reinterpret_cast<LPARAM
>(&bIsCJKVerticalFont
), 0 );
744 if( !bIsCJKVerticalFont
)
746 // restore non-vertical name if not vertical mode isn't available
747 memcpy( &aLogFont
.lfFaceName
[0], &aLogFont
.lfFaceName
[1], nLen
);
748 aLogFont
.lfFaceName
[LF_FACESIZE
- 1] = 0;
752 hNewFont
= ::CreateFontIndirectW( &aLogFont
);
753 o_rOldFont
= ::SelectFont(hDC
, hNewFont
);
755 TEXTMETRICW aTextMetricW
;
756 if (!::GetTextMetricsW(hDC
, &aTextMetricW
))
758 // the selected font doesn't work => try a replacement
759 // TODO: use its font fallback instead
760 lstrcpynW( aLogFont
.lfFaceName
, L
"Courier New", 12 );
761 aLogFont
.lfPitchAndFamily
= FIXED_PITCH
;
762 HFONT hNewFont2
= CreateFontIndirectW( &aLogFont
);
763 SelectFont(hDC
, hNewFont2
);
764 DeleteFont( hNewFont
);
765 hNewFont
= hNewFont2
;
766 bIsCJKVerticalFont
= false;
769 return std::make_tuple(hNewFont
, bIsCJKVerticalFont
, static_cast<sal_Int32
>(aTextMetricW
.tmDescent
));
772 void WinSalGraphics::SetFont(LogicalFontInstance
* pFont
, int nFallbackLevel
)
774 assert(nFallbackLevel
>= 0 && nFallbackLevel
< MAX_FALLBACK
);
776 // return early if there is no new font
779 if (!mpWinFontEntry
[nFallbackLevel
].is())
782 // DeInitGraphics doesn't free the cached fonts, so mhDefFont might be nullptr
785 ::SelectFont(getHDC(), mhDefFont
);
789 // release no longer referenced font handles
790 for( int i
= nFallbackLevel
; i
< MAX_FALLBACK
; ++i
)
791 mpWinFontEntry
[i
] = nullptr;
795 WinFontInstance
*pFontInstance
= static_cast<WinFontInstance
*>(pFont
);
796 mpWinFontEntry
[ nFallbackLevel
] = pFontInstance
;
798 HFONT hOldFont
= nullptr;
799 HFONT hNewFont
= pFontInstance
->GetHFONT();
802 pFontInstance
->SetGraphics(this);
803 hNewFont
= pFontInstance
->GetHFONT();
805 hOldFont
= ::SelectFont(getHDC(), hNewFont
);
809 mhDefFont
= hOldFont
;
812 // release no longer referenced font handles
813 for( int i
= nFallbackLevel
+ 1; i
< MAX_FALLBACK
&& mpWinFontEntry
[i
].is(); ++i
)
814 mpWinFontEntry
[i
] = nullptr;
818 void WinSalGraphics::GetFontMetric( FontMetricDataRef
& rxFontMetric
, int nFallbackLevel
)
820 // temporarily change the HDC to the font in the fallback level
821 rtl::Reference
<WinFontInstance
> pFontInstance
= mpWinFontEntry
[nFallbackLevel
];
822 const HFONT hOldFont
= SelectFont(getHDC(), pFontInstance
->GetHFONT());
824 wchar_t aFaceName
[LF_FACESIZE
+60];
825 if( GetTextFaceW( getHDC(), SAL_N_ELEMENTS(aFaceName
), aFaceName
) )
826 rxFontMetric
->SetFamilyName(OUString(o3tl::toU(aFaceName
)));
828 rxFontMetric
->SetMinKashida(pFontInstance
->GetKashidaWidth());
829 rxFontMetric
->ImplCalcLineSpacing(pFontInstance
.get());
830 rxFontMetric
->ImplInitBaselines(pFontInstance
.get());
832 // get the font metric
833 OUTLINETEXTMETRICW aOutlineMetric
;
834 const bool bOK
= GetOutlineTextMetricsW(getHDC(), sizeof(aOutlineMetric
), &aOutlineMetric
);
835 // restore the HDC to the font in the base level
836 SelectFont( getHDC(), hOldFont
);
840 TEXTMETRICW aWinMetric
= aOutlineMetric
.otmTextMetrics
;
842 // device independent font attributes
843 rxFontMetric
->SetFamilyType(ImplFamilyToSal( aWinMetric
.tmPitchAndFamily
));
844 rxFontMetric
->SetMicrosoftSymbolEncoded(aWinMetric
.tmCharSet
== SYMBOL_CHARSET
);
845 rxFontMetric
->SetWeight(ImplWeightToSal( aWinMetric
.tmWeight
));
846 rxFontMetric
->SetPitch(ImplMetricPitchToSal( aWinMetric
.tmPitchAndFamily
));
847 rxFontMetric
->SetItalic(aWinMetric
.tmItalic
? ITALIC_NORMAL
: ITALIC_NONE
);
848 rxFontMetric
->SetSlant( 0 );
850 // transformation dependent font metrics
851 rxFontMetric
->SetWidth(aWinMetric
.tmAveCharWidth
);
854 FontCharMapRef
WinSalGraphics::GetFontCharMap() const
856 if (!mpWinFontEntry
[0])
858 return FontCharMapRef( new FontCharMap() );
860 return mpWinFontEntry
[0]->GetFontFace()->GetFontCharMap();
863 bool WinSalGraphics::GetFontCapabilities(vcl::FontCapabilities
&rFontCapabilities
) const
865 if (!mpWinFontEntry
[0])
867 return mpWinFontEntry
[0]->GetFontFace()->GetFontCapabilities(rFontCapabilities
);
870 static int CALLBACK
SalEnumFontsProcExW( const LOGFONTW
* lpelfe
,
871 const TEXTMETRICW
* lpntme
,
872 DWORD nFontType
, LPARAM lParam
)
874 ENUMLOGFONTEXW
const * pLogFont
875 = reinterpret_cast<ENUMLOGFONTEXW
const *>(lpelfe
);
876 NEWTEXTMETRICEXW
const * pMetric
877 = reinterpret_cast<NEWTEXTMETRICEXW
const *>(lpntme
);
878 ImplEnumInfo
* pInfo
= reinterpret_cast<ImplEnumInfo
*>(lParam
);
879 if ( !pInfo
->mpName
)
881 // Ignore vertical fonts
882 if ( pLogFont
->elfLogFont
.lfFaceName
[0] != '@' )
884 OUString
aName(o3tl::toU(pLogFont
->elfLogFont
.lfFaceName
));
885 pInfo
->mpName
= &aName
;
886 memcpy(pInfo
->mpLogFont
->lfFaceName
, pLogFont
->elfLogFont
.lfFaceName
, (aName
.getLength()+1)*sizeof(wchar_t));
887 pInfo
->mpLogFont
->lfCharSet
= pLogFont
->elfLogFont
.lfCharSet
;
888 EnumFontFamiliesExW(pInfo
->mhDC
, pInfo
->mpLogFont
, SalEnumFontsProcExW
,
889 reinterpret_cast<LPARAM
>(pInfo
), 0);
890 pInfo
->mpLogFont
->lfFaceName
[0] = '\0';
891 pInfo
->mpLogFont
->lfCharSet
= DEFAULT_CHARSET
;
892 pInfo
->mpName
= nullptr;
897 // Ignore non-device fonts on printers.
898 if (pInfo
->mbPrinter
)
900 if ((nFontType
& RASTER_FONTTYPE
) && !(nFontType
& DEVICE_FONTTYPE
))
902 SAL_INFO("vcl.fonts", "Unsupported printer font ignored: " << OUString(o3tl::toU(pLogFont
->elfLogFont
.lfFaceName
)));
906 // Only SFNT fonts are supported, ignore anything else.
907 else if (!(nFontType
& TRUETYPE_FONTTYPE
) &&
908 !(pMetric
->ntmTm
.ntmFlags
& NTM_PS_OPENTYPE
) &&
909 !(pMetric
->ntmTm
.ntmFlags
& NTM_TT_OPENTYPE
))
911 SAL_INFO("vcl.fonts", "Unsupported font ignored: " << OUString(o3tl::toU(pLogFont
->elfLogFont
.lfFaceName
)));
915 rtl::Reference
<WinFontFace
> pData
= new WinFontFace(*pLogFont
, pMetric
->ntmTm
);
916 pData
->SetFontId( sal_IntPtr( pInfo
->mnFontCount
++ ) );
918 pInfo
->mpList
->Add( pData
.get() );
919 SAL_INFO("vcl.fonts", "SalEnumFontsProcExW: font added: " << pData
->GetFamilyName() << " " << pData
->GetStyleName());
927 OUString maFontResourcePath
;
928 TempFontItem
* mpNextItem
;
931 static int lcl_AddFontResource(SalData
& rSalData
, const OUString
& rFontFileURL
, bool bShared
)
933 OUString aFontSystemPath
;
934 OSL_VERIFY(!osl::FileBase::getSystemPathFromFileURL(rFontFileURL
, aFontSystemPath
));
936 int nRet
= AddFontResourceExW(o3tl::toW(aFontSystemPath
.getStr()), FR_PRIVATE
, nullptr);
937 SAL_WARN_IF(nRet
<= 0, "vcl.fonts", "AddFontResourceExW failed for " << rFontFileURL
);
940 TempFontItem
* pNewItem
= new TempFontItem
;
941 pNewItem
->maFontResourcePath
= aFontSystemPath
;
944 pNewItem
->mpNextItem
= rSalData
.mpSharedTempFontItem
;
945 rSalData
.mpSharedTempFontItem
= pNewItem
;
949 pNewItem
->mpNextItem
= rSalData
.mpOtherTempFontItem
;
950 rSalData
.mpOtherTempFontItem
= pNewItem
;
956 void ImplReleaseTempFonts(SalData
& rSalData
, bool bAll
)
958 while (TempFontItem
* p
= rSalData
.mpOtherTempFontItem
)
960 RemoveFontResourceExW(o3tl::toW(p
->maFontResourcePath
.getStr()), FR_PRIVATE
, nullptr);
961 rSalData
.mpOtherTempFontItem
= p
->mpNextItem
;
968 while (TempFontItem
* p
= rSalData
.mpSharedTempFontItem
)
970 RemoveFontResourceExW(o3tl::toW(p
->maFontResourcePath
.getStr()), FR_PRIVATE
, nullptr);
971 rSalData
.mpSharedTempFontItem
= p
->mpNextItem
;
976 static OUString
lcl_GetFontFamilyName(std::u16string_view rFontFileURL
)
978 // Create temporary file name
979 OUString aTempFileURL
;
980 if (osl::File::E_None
!= osl::File::createTempFile(nullptr, nullptr, &aTempFileURL
))
982 osl::File::remove(aTempFileURL
);
983 OUString aResSystemPath
;
984 osl::FileBase::getSystemPathFromFileURL(aTempFileURL
, aResSystemPath
);
986 // Create font resource file (.fot)
987 // There is a limit of 127 characters for the full path passed via lpszFile, so we have to
988 // split the font URL and pass it as two parameters. As a result we can't use
989 // CreateScalableFontResource for renaming, as it now expects the font in the system path.
990 // But it's still good to use it for family name extraction, we're currently after.
991 // BTW: it doesn't help to prefix the lpszFile with \\?\ to support larger paths.
992 // TODO: use TTLoadEmbeddedFont (needs an EOT as input, so we have to add a header to the TTF)
993 // TODO: forward the EOT from the AddTempDevFont call side, if VCL supports it
994 INetURLObject
aTTFUrl(rFontFileURL
);
995 // GetBase() strips the extension
996 OUString aFilename
= aTTFUrl
.GetLastName(INetURLObject::DecodeMechanism::WithCharset
);
997 if (!CreateScalableFontResourceW(0, o3tl::toW(aResSystemPath
.getStr()),
998 o3tl::toW(aFilename
.getStr()), o3tl::toW(aTTFUrl
.GetPath().getStr())))
1000 sal_uInt32 nError
= GetLastError();
1001 SAL_WARN("vcl.fonts", "CreateScalableFontResource failed for " << aResSystemPath
<< " "
1002 << aFilename
<< " " << aTTFUrl
.GetPath() << " " << nError
);
1006 // Open and read the font resource file
1007 osl::File
aFotFile(aTempFileURL
);
1008 if (osl::FileBase::E_None
!= aFotFile
.open(osl_File_OpenFlag_Read
))
1011 sal_uInt64 nBytesRead
= 0;
1013 aFotFile
.read( aBuffer
, sizeof( aBuffer
), nBytesRead
);
1014 // clean up temporary resource file
1016 osl::File::remove(aTempFileURL
);
1018 // retrieve font family name from byte offset 0x4F6
1019 static const sal_uInt64 nNameOfs
= 0x4F6;
1020 sal_uInt64 nPos
= nNameOfs
;
1021 for (; (nPos
< nBytesRead
) && (aBuffer
[nPos
] != 0); nPos
++);
1022 if (nPos
>= nBytesRead
|| (nPos
== nNameOfs
))
1025 return OUString(aBuffer
+ nNameOfs
, nPos
- nNameOfs
, osl_getThreadTextEncoding());
1028 bool WinSalGraphics::AddTempDevFont(vcl::font::PhysicalFontCollection
* pFontCollection
,
1029 const OUString
& rFontFileURL
, const OUString
& rFontName
)
1031 OUString aFontFamily
= lcl_GetFontFamilyName(rFontFileURL
);
1032 if (aFontFamily
.isEmpty())
1034 SAL_WARN("vcl.fonts", "error extracting font family from " << rFontFileURL
);
1038 if (rFontName
!= aFontFamily
)
1040 SAL_WARN("vcl.fonts", "font family renaming not implemented; skipping embedded " << rFontName
);
1044 int nFonts
= lcl_AddFontResource(*GetSalData(), rFontFileURL
, false);
1049 aInfo
.mhDC
= getHDC();
1050 aInfo
.mpList
= pFontCollection
;
1051 aInfo
.mpName
= &aFontFamily
;
1052 aInfo
.mbPrinter
= mbPrinter
;
1053 aInfo
.mnFontCount
= pFontCollection
->Count();
1054 const int nExpectedFontCount
= aInfo
.mnFontCount
+ nFonts
;
1056 LOGFONTW aLogFont
= {};
1057 aLogFont
.lfCharSet
= DEFAULT_CHARSET
;
1058 aInfo
.mpLogFont
= &aLogFont
;
1060 // add the font to the PhysicalFontCollection
1061 EnumFontFamiliesExW(getHDC(), &aLogFont
,
1062 SalEnumFontsProcExW
, reinterpret_cast<LPARAM
>(&aInfo
), 0);
1064 SAL_WARN_IF(nExpectedFontCount
!= pFontCollection
->Count(), "vcl.fonts",
1065 "temp font was registered but is not in enumeration: " << rFontFileURL
);
1070 void WinSalGraphics::GetDevFontList( vcl::font::PhysicalFontCollection
* pFontCollection
)
1072 // make sure all LO shared fonts are registered temporarily
1073 static std::once_flag init
;
1074 std::call_once(init
, []()
1076 auto registerFontsIn
= [](const OUString
& dir
) {
1077 // collect fonts in font path that could not be registered
1078 osl::Directory
aFontDir(dir
);
1079 osl::FileBase::RC rcOSL
= aFontDir
.open();
1080 if (rcOSL
== osl::FileBase::E_None
)
1082 osl::DirectoryItem aDirItem
;
1083 SalData
* pSalData
= GetSalData();
1086 while (aFontDir
.getNextItem(aDirItem
, 10) == osl::FileBase::E_None
)
1088 osl::FileStatus
aFileStatus(osl_FileStatus_Mask_FileURL
);
1089 rcOSL
= aDirItem
.getFileStatus(aFileStatus
);
1090 if (rcOSL
== osl::FileBase::E_None
)
1091 lcl_AddFontResource(*pSalData
, aFileStatus
.getFileURL(), true);
1096 // determine font path
1097 // since we are only interested in fonts that could not be
1098 // registered before because of missing administration rights
1099 // only the font path of the user installation is needed
1100 OUString
aPath("$BRAND_BASE_DIR");
1101 rtl_bootstrap_expandMacros(&aPath
.pData
);
1103 // internal font resources, required for normal operation, like OpenSymbol
1104 registerFontsIn(aPath
+ "/" LIBO_SHARE_RESOURCE_FOLDER
"/common/fonts");
1106 // collect fonts in font path that could not be registered
1107 registerFontsIn(aPath
+ "/" LIBO_SHARE_FOLDER
"/fonts/truetype");
1113 aInfo
.mhDC
= getHDC();
1114 aInfo
.mpList
= pFontCollection
;
1115 aInfo
.mpName
= nullptr;
1116 aInfo
.mbPrinter
= mbPrinter
;
1117 aInfo
.mnFontCount
= 0;
1119 LOGFONTW aLogFont
= {};
1120 aLogFont
.lfCharSet
= DEFAULT_CHARSET
;
1121 aInfo
.mpLogFont
= &aLogFont
;
1123 // fill the PhysicalFontCollection
1124 EnumFontFamiliesExW( getHDC(), &aLogFont
,
1125 SalEnumFontsProcExW
, reinterpret_cast<LPARAM
>(&aInfo
), 0 );
1127 // set glyph fallback hook
1128 static WinGlyphFallbackSubstititution aSubstFallback
;
1129 static WinPreMatchFontSubstititution aPreMatchFont
;
1130 pFontCollection
->SetFallbackHook( &aSubstFallback
);
1131 pFontCollection
->SetPreMatchHook(&aPreMatchFont
);
1134 void WinSalGraphics::ClearDevFontCache()
1136 mWinSalGraphicsImplBase
->ClearDevFontCache();
1137 ImplReleaseTempFonts(*GetSalData(), false);
1140 bool WinFontInstance::GetGlyphOutline(sal_GlyphId nId
, basegfx::B2DPolyPolygon
& rB2DPolyPoly
, bool) const
1142 rB2DPolyPoly
.clear();
1144 assert(m_pGraphics
);
1145 HDC hDC
= m_pGraphics
->getHDC();
1146 const HFONT hOrigFont
= static_cast<HFONT
>(GetCurrentObject(hDC
, OBJ_FONT
));
1147 const HFONT hFont
= GetHFONT();
1148 if (hFont
!= hOrigFont
)
1149 SelectObject(hDC
, hFont
);
1151 const ::comphelper::ScopeGuard
aFontRestoreScopeGuard([hFont
, hOrigFont
, hDC
]()
1152 { if (hFont
!= hOrigFont
) SelectObject(hDC
, hOrigFont
); });
1156 aMat
.eM11
= aMat
.eM22
= FixedFromDouble( 1.0 );
1157 aMat
.eM12
= aMat
.eM21
= FixedFromDouble( 0.0 );
1159 UINT nGGOFlags
= GGO_NATIVE
;
1160 nGGOFlags
|= GGO_GLYPH_INDEX
;
1162 GLYPHMETRICS aGlyphMetrics
;
1163 const DWORD nSize1
= ::GetGlyphOutlineW(hDC
, nId
, nGGOFlags
, &aGlyphMetrics
, 0, nullptr, &aMat
);
1164 if( !nSize1
) // blank glyphs are ok
1166 else if( nSize1
== GDI_ERROR
)
1169 BYTE
* pData
= new BYTE
[ nSize1
];
1170 const DWORD nSize2
= ::GetGlyphOutlineW(hDC
, nId
, nGGOFlags
,
1171 &aGlyphMetrics
, nSize1
, pData
, &aMat
);
1173 if( nSize1
!= nSize2
)
1176 // TODO: avoid tools polygon by creating B2DPolygon directly
1178 Point
* pPoints
= new Point
[ nPtSize
];
1179 PolyFlags
* pFlags
= new PolyFlags
[ nPtSize
];
1181 TTPOLYGONHEADER
* pHeader
= reinterpret_cast<TTPOLYGONHEADER
*>(pData
);
1182 while( reinterpret_cast<BYTE
*>(pHeader
) < pData
+nSize2
)
1184 // only outline data is interesting
1185 if( pHeader
->dwType
!= TT_POLYGON_TYPE
)
1188 // get start point; next start points are end points
1189 // of previous segment
1190 sal_uInt16 nPnt
= 0;
1192 tools::Long nX
= IntTimes256FromFixed( pHeader
->pfxStart
.x
);
1193 tools::Long nY
= IntTimes256FromFixed( pHeader
->pfxStart
.y
);
1194 pPoints
[ nPnt
] = Point( nX
, nY
);
1195 pFlags
[ nPnt
++ ] = PolyFlags::Normal
;
1197 bool bHasOfflinePoints
= false;
1198 TTPOLYCURVE
* pCurve
= reinterpret_cast<TTPOLYCURVE
*>( pHeader
+ 1 );
1199 pHeader
= reinterpret_cast<TTPOLYGONHEADER
*>( reinterpret_cast<BYTE
*>(pHeader
) + pHeader
->cb
);
1200 while( reinterpret_cast<BYTE
*>(pCurve
) < reinterpret_cast<BYTE
*>(pHeader
) )
1202 int nNeededSize
= nPnt
+ 16 + 3 * pCurve
->cpfx
;
1203 if( nPtSize
< nNeededSize
)
1205 Point
* pOldPoints
= pPoints
;
1206 PolyFlags
* pOldFlags
= pFlags
;
1207 nPtSize
= 2 * nNeededSize
;
1208 pPoints
= new Point
[ nPtSize
];
1209 pFlags
= new PolyFlags
[ nPtSize
];
1210 for( sal_uInt16 i
= 0; i
< nPnt
; ++i
)
1212 pPoints
[ i
] = pOldPoints
[ i
];
1213 pFlags
[ i
] = pOldFlags
[ i
];
1215 delete[] pOldPoints
;
1220 if( TT_PRIM_LINE
== pCurve
->wType
)
1222 while( i
< pCurve
->cpfx
)
1224 nX
= IntTimes256FromFixed( pCurve
->apfx
[ i
].x
);
1225 nY
= IntTimes256FromFixed( pCurve
->apfx
[ i
].y
);
1227 pPoints
[ nPnt
] = Point( nX
, nY
);
1228 pFlags
[ nPnt
] = PolyFlags::Normal
;
1232 else if( TT_PRIM_QSPLINE
== pCurve
->wType
)
1234 bHasOfflinePoints
= true;
1235 while( i
< pCurve
->cpfx
)
1237 // get control point of quadratic bezier spline
1238 nX
= IntTimes256FromFixed( pCurve
->apfx
[ i
].x
);
1239 nY
= IntTimes256FromFixed( pCurve
->apfx
[ i
].y
);
1241 Point
aControlP( nX
, nY
);
1243 // calculate first cubic control point
1244 // P0 = 1/3 * (PBeg + 2 * PQControl)
1245 nX
= pPoints
[ nPnt
-1 ].X() + 2 * aControlP
.X();
1246 nY
= pPoints
[ nPnt
-1 ].Y() + 2 * aControlP
.Y();
1247 pPoints
[ nPnt
+0 ] = Point( (2*nX
+3)/6, (2*nY
+3)/6 );
1248 pFlags
[ nPnt
+0 ] = PolyFlags::Control
;
1250 // calculate endpoint of segment
1251 nX
= IntTimes256FromFixed( pCurve
->apfx
[ i
].x
);
1252 nY
= IntTimes256FromFixed( pCurve
->apfx
[ i
].y
);
1254 if ( i
+1 >= pCurve
->cpfx
)
1256 // endpoint is either last point in segment => advance
1261 // or endpoint is the middle of two control points
1262 nX
+= IntTimes256FromFixed( pCurve
->apfx
[ i
-1 ].x
);
1263 nY
+= IntTimes256FromFixed( pCurve
->apfx
[ i
-1 ].y
);
1266 // no need to advance, because the current point
1267 // is the control point in next bezier spline
1270 pPoints
[ nPnt
+2 ] = Point( nX
, nY
);
1271 pFlags
[ nPnt
+2 ] = PolyFlags::Normal
;
1273 // calculate second cubic control point
1274 // P1 = 1/3 * (PEnd + 2 * PQControl)
1275 nX
= pPoints
[ nPnt
+2 ].X() + 2 * aControlP
.X();
1276 nY
= pPoints
[ nPnt
+2 ].Y() + 2 * aControlP
.Y();
1277 pPoints
[ nPnt
+1 ] = Point( (2*nX
+3)/6, (2*nY
+3)/6 );
1278 pFlags
[ nPnt
+1 ] = PolyFlags::Control
;
1284 // next curve segment
1285 pCurve
= reinterpret_cast<TTPOLYCURVE
*>(&pCurve
->apfx
[ i
]);
1288 // end point is start point for closed contour
1289 // disabled, because Polygon class closes the contour itself
1290 // pPoints[nPnt++] = pPoints[0];
1292 // Added again, but add only when not yet closed
1293 if(pPoints
[nPnt
- 1] != pPoints
[0])
1295 if( bHasOfflinePoints
)
1296 pFlags
[nPnt
] = pFlags
[0];
1298 pPoints
[nPnt
++] = pPoints
[0];
1301 // convert y-coordinates W32 -> VCL
1302 for( int i
= 0; i
< nPnt
; ++i
)
1303 pPoints
[i
].setY(-pPoints
[i
].Y());
1305 // insert into polypolygon
1306 tools::Polygon
aPoly( nPnt
, pPoints
, (bHasOfflinePoints
? pFlags
: nullptr) );
1307 // convert to B2DPolyPolygon
1308 // TODO: get rid of the intermediate PolyPolygon
1309 rB2DPolyPoly
.append( aPoly
.getB2DPolygon() );
1317 // rescaling needed for the tools::PolyPolygon conversion
1318 if( rB2DPolyPoly
.count() )
1320 const double fFactor(1.0f
/256);
1321 rB2DPolyPoly
.transform(basegfx::utils::createScaleB2DHomMatrix(fFactor
, fFactor
));
1327 IDWriteFontFace
* WinFontInstance::GetDWFontFace() const
1331 assert(m_pGraphics
);
1332 HDC hDC
= m_pGraphics
->getHDC();
1333 const HFONT hOrigFont
= static_cast<HFONT
>(GetCurrentObject(hDC
, OBJ_FONT
));
1334 const HFONT hFont
= GetHFONT();
1335 if (hFont
!= hOrigFont
)
1336 SelectObject(hDC
, hFont
);
1338 const ::comphelper::ScopeGuard
aFontRestoreScopeGuard([hFont
, hOrigFont
, hDC
]() {
1339 if (hFont
!= hOrigFont
)
1340 SelectObject(hDC
, hOrigFont
);
1343 IDWriteGdiInterop
* pDWriteGdiInterop
= WinSalGraphics::getDWriteGdiInterop();
1345 HRESULT hr
= pDWriteGdiInterop
->CreateFontFaceFromHdc(hDC
, &mxDWFontFace
);
1348 SAL_WARN("vcl.fonts", "HRESULT 0x" << OUString::number(hr
, 16) << ": "
1349 << WindowsErrorStringFromHRESULT(hr
));
1350 mxDWFontFace
= nullptr;
1354 return mxDWFontFace
;
1357 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */