1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/types.h>
21 #include <config_folders.h>
22 
23 #include <algorithm>
24 #include <map>
25 #include <memory>
26 #include <mutex>
27 #include <set>
28 #include <string.h>
29 #include <svsys.h>
30 #include <vector>
31 
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 <comphelper/scopeguard.hxx>
51 
52 #include <fontsubset.hxx>
53 #include <outdev.h>
54 #include <PhysicalFontCollection.hxx>
55 #include <PhysicalFontFace.hxx>
56 #include <sft.hxx>
57 #include <win/saldata.hxx>
58 #include <win/salgdi.h>
59 #include <win/winlayout.hxx>
60 #include <win/wingdiimpl.hxx>
61 #include <impfontcharmap.hxx>
62 #include <impfontmetricdata.hxx>
63 #include <impglyphitem.hxx>
64 
65 #if HAVE_FEATURE_SKIA
66 #include <vcl/skia/SkiaHelper.hxx>
67 #include <skia/win/font.hxx>
68 #endif
69 
70 using namespace vcl;
71 
FixedFromDouble(double d)72 static FIXED FixedFromDouble( double d )
73 {
74     const tools::Long l = static_cast<tools::Long>( d * 65536. );
75     return *reinterpret_cast<FIXED const *>(&l);
76 }
77 
IntTimes256FromFixed(FIXED f)78 static int IntTimes256FromFixed(FIXED f)
79 {
80     int nFixedTimes256 = (f.value << 8) + ((f.fract+0x80) >> 8);
81     return nFixedTimes256;
82 }
83 
84 namespace {
85 
86 // raw font data with a scoped lifetime
87 class RawFontData
88 {
89 public:
90     explicit    RawFontData( HDC, DWORD nTableTag=0 );
get() const91     const unsigned char*    get() const { return mpRawBytes.get(); }
steal()92     const unsigned char*    steal() { return mpRawBytes.release(); }
size() const93     int               size() const { return mnByteCount; }
94 
95 private:
96     std::unique_ptr<unsigned char[]> mpRawBytes;
97     unsigned        mnByteCount;
98 };
99 
100 }
101 
RawFontData(HDC hDC,DWORD nTableTag)102 RawFontData::RawFontData( HDC hDC, DWORD nTableTag )
103 :   mnByteCount( 0 )
104 {
105     // get required size in bytes
106     mnByteCount = ::GetFontData( hDC, nTableTag, 0, nullptr, 0 );
107     if (mnByteCount == GDI_ERROR)
108         mnByteCount = 0;
109     if (!mnByteCount)
110         return;
111 
112     // allocate the array
113     mpRawBytes.reset(new unsigned char[ mnByteCount ]);
114 
115     // get raw data in chunks small enough for GetFontData()
116     unsigned nRawDataOfs = 0;
117     DWORD nMaxChunkSize = 0x100000;
118     for(;;)
119     {
120         // calculate remaining raw data to get
121         DWORD nFDGet = mnByteCount - nRawDataOfs;
122         if( nFDGet <= 0 )
123             break;
124         // #i56745# limit GetFontData requests
125         if( nFDGet > nMaxChunkSize )
126             nFDGet = nMaxChunkSize;
127         const DWORD nFDGot = ::GetFontData( hDC, nTableTag, nRawDataOfs,
128             mpRawBytes.get() + nRawDataOfs, nFDGet );
129         if( !nFDGot )
130             break;
131         else if( nFDGot != GDI_ERROR )
132             nRawDataOfs += nFDGot;
133         else
134         {
135             // was the chunk too big? reduce it
136             nMaxChunkSize /= 2;
137             if( nMaxChunkSize < 0x10000 )
138                 break;
139         }
140     }
141 
142     // cleanup if the raw data is incomplete
143     if( nRawDataOfs != mnByteCount )
144     {
145         mpRawBytes.reset();
146         // mnByteCount must correspond to mpRawBytes length
147         SAL_WARN( "vcl", "Raw data of font is incomplete: " << nRawDataOfs << " byte(s) found whereas " << mnByteCount << " byte(s) expected!" );
148         mnByteCount = 0;
149     }
150 }
151 
152 // platform specific font substitution hooks for glyph fallback enhancement
153 
154 namespace {
155 
156 class WinPreMatchFontSubstititution
157 :    public ImplPreMatchFontSubstitution
158 {
159 public:
160     bool FindFontSubstitute(FontSelectPattern&) const override;
161 };
162 
163 class WinGlyphFallbackSubstititution
164 :    public ImplGlyphFallbackFontSubstitution
165 {
166 public:
WinGlyphFallbackSubstititution()167     explicit WinGlyphFallbackSubstititution()
168         : mhDC(GetDC(nullptr))
169     {
170     };
171 
~WinGlyphFallbackSubstititution()172     ~WinGlyphFallbackSubstititution() override
173     {
174         ReleaseDC(nullptr, mhDC);
175     };
176 
177     bool FindFontSubstitute(FontSelectPattern&, LogicalFontInstance* pLogicalFont, OUString& rMissingChars) const override;
178 private:
179     HDC mhDC;
180     bool HasMissingChars(PhysicalFontFace*, OUString& rMissingChars) const;
181 };
182 
183 }
184 
185 // does a font face hold the given missing characters?
HasMissingChars(PhysicalFontFace * pFace,OUString & rMissingChars) const186 bool WinGlyphFallbackSubstititution::HasMissingChars(PhysicalFontFace* pFace, OUString& rMissingChars) const
187 {
188     WinFontFace* pWinFont = static_cast< WinFontFace* >(pFace);
189     FontCharMapRef xFontCharMap = pWinFont->GetFontCharMap();
190     if( !xFontCharMap.is() )
191     {
192         // construct a Size structure as the parameter of constructor of class FontSelectPattern
193         const Size aSize( pFace->GetWidth(), pFace->GetHeight() );
194         // create a FontSelectPattern object for getting s LOGFONT
195         const FontSelectPattern aFSD( *pFace, aSize, static_cast<float>(aSize.Height()), 0, false );
196         // construct log font
197         LOGFONTW aLogFont;
198         ImplGetLogFontFromFontSelect( aFSD, pFace, aLogFont );
199 
200         // create HFONT from log font
201         HFONT hNewFont = ::CreateFontIndirectW( &aLogFont );
202         // select the new font into device
203         HFONT hOldFont = ::SelectFont( mhDC, hNewFont );
204 
205         // read CMAP table to update their xFontCharMap
206         pWinFont->UpdateFromHDC( mhDC );
207 
208         // cleanup temporary font
209         ::SelectFont( mhDC, hOldFont );
210         ::DeleteFont( hNewFont );
211 
212         // get the new charmap
213         xFontCharMap = pWinFont->GetFontCharMap();
214     }
215 
216     // avoid fonts with unknown CMAP subtables for glyph fallback
217     if( !xFontCharMap.is() || xFontCharMap->IsDefaultMap() )
218         return false;
219 
220     int nMatchCount = 0;
221     std::vector<sal_UCS4> rRemainingCodes;
222     const sal_Int32 nStrLen = rMissingChars.getLength();
223     sal_Int32 nStrIdx = 0;
224     while (nStrIdx < nStrLen)
225     {
226         const sal_UCS4 uChar = rMissingChars.iterateCodePoints( &nStrIdx );
227         if (xFontCharMap->HasChar(uChar))
228             nMatchCount++;
229         else
230             rRemainingCodes.push_back(uChar);
231     }
232 
233     xFontCharMap = nullptr;
234 
235     if (nMatchCount > 0)
236         rMissingChars = OUString(rRemainingCodes.data(), rRemainingCodes.size());
237 
238     return nMatchCount > 0;
239 }
240 
241 namespace
242 {
243     //used by 2-level font fallback
findDevFontListByLocale(const PhysicalFontCollection & rFontCollection,const LanguageTag & rLanguageTag)244     PhysicalFontFamily* findDevFontListByLocale(const PhysicalFontCollection &rFontCollection,
245                                                 const LanguageTag& rLanguageTag )
246     {
247         // get the default font for a specified locale
248         const utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get();
249         const OUString aDefault = rDefaults.getUserInterfaceFont(rLanguageTag);
250         return rFontCollection.FindFontFamilyByTokenNames(aDefault);
251     }
252 }
253 
254 // These are Win 3.1 bitmap fonts using "FON" font format
255 // which is not supported with DirectWrite so let's substitute them
256 // with a font that is supported and always available.
257 // Based on:
258 // https://dxr.mozilla.org/mozilla-esr10/source/gfx/thebes/gfxDWriteFontList.cpp#1057
259 const std::map<OUString, OUString> aBitmapFontSubs =
260 {
261     { "MS Sans Serif", "Microsoft Sans Serif" },
262     { "MS Serif",      "Times New Roman" },
263     { "Small Fonts",   "Arial" },
264     { "Courier",       "Courier New" },
265     { "Roman",         "Times New Roman" },
266     { "Script",        "Mistral" }
267 };
268 
269 // TODO: See if Windows have API that we can use here to improve font fallback.
FindFontSubstitute(FontSelectPattern & rFontSelData) const270 bool WinPreMatchFontSubstititution::FindFontSubstitute(FontSelectPattern& rFontSelData) const
271 {
272     if (rFontSelData.IsSymbolFont() || IsStarSymbol(rFontSelData.maSearchName))
273         return false;
274 
275     for (const auto& aSub : aBitmapFontSubs)
276     {
277         if (rFontSelData.maSearchName == GetEnglishSearchFontName(aSub.first))
278         {
279             rFontSelData.maSearchName = aSub.second;
280             return true;
281         }
282     }
283 
284     return false;
285 }
286 
287 // find a fallback font for missing characters
288 // TODO: should stylistic matches be searched and preferred?
FindFontSubstitute(FontSelectPattern & rFontSelData,LogicalFontInstance *,OUString & rMissingChars) const289 bool WinGlyphFallbackSubstititution::FindFontSubstitute(FontSelectPattern& rFontSelData, LogicalFontInstance* /*pLogicalFont*/, OUString& rMissingChars) const
290 {
291     // guess a locale matching to the missing chars
292     LanguageType eLang = rFontSelData.meLanguage;
293     LanguageTag aLanguageTag( eLang);
294 
295     // fall back to default UI locale if the font language is inconclusive
296     if( eLang == LANGUAGE_DONTKNOW )
297         aLanguageTag = Application::GetSettings().GetUILanguageTag();
298 
299     // first level fallback:
300     // try use the locale specific default fonts defined in VCL.xcu
301     const PhysicalFontCollection* pFontCollection = ImplGetSVData()->maGDIData.mxScreenFontList.get();
302     PhysicalFontFamily* pFontFamily = findDevFontListByLocale(*pFontCollection, aLanguageTag);
303     if( pFontFamily )
304     {
305         PhysicalFontFace* pFace = pFontFamily->FindBestFontFace( rFontSelData );
306         if( HasMissingChars( pFace, rMissingChars ) )
307         {
308             rFontSelData.maSearchName = pFontFamily->GetSearchName();
309             return true;
310         }
311     }
312 
313     // are the missing characters symbols?
314     pFontFamily = pFontCollection->FindFontFamilyByAttributes( ImplFontAttrs::Symbol,
315                                                      rFontSelData.GetWeight(),
316                                                      rFontSelData.GetWidthType(),
317                                                      rFontSelData.GetItalic(),
318                                                      rFontSelData.maSearchName );
319     if( pFontFamily )
320     {
321         PhysicalFontFace* pFace = pFontFamily->FindBestFontFace( rFontSelData );
322         if( HasMissingChars( pFace, rMissingChars ) )
323         {
324             rFontSelData.maSearchName = pFontFamily->GetSearchName();
325             return true;
326         }
327     }
328 
329     // last level fallback, check each font type face one by one
330     std::unique_ptr<ImplDeviceFontList> pTestFontList = pFontCollection->GetDeviceFontList();
331     // limit the count of fonts to be checked to prevent hangs
332     static const int MAX_GFBFONT_COUNT = 600;
333     int nTestFontCount = pTestFontList->Count();
334     if( nTestFontCount > MAX_GFBFONT_COUNT )
335         nTestFontCount = MAX_GFBFONT_COUNT;
336 
337     bool bFound = false;
338     for( int i = 0; i < nTestFontCount; ++i )
339     {
340         PhysicalFontFace* pFace = pTestFontList->Get( i );
341         bFound = HasMissingChars( pFace, rMissingChars );
342         if( !bFound )
343             continue;
344         rFontSelData.maSearchName = pFace->GetFamilyName();
345         break;
346     }
347 
348     return bFound;
349 }
350 
351 namespace {
352 
353 struct ImplEnumInfo
354 {
355     HDC                 mhDC;
356     PhysicalFontCollection* mpList;
357     OUString*           mpName;
358     LOGFONTW*           mpLogFont;
359     bool                mbPrinter;
360     int                 mnFontCount;
361 };
362 
363 }
364 
ImplCharSetToSal(BYTE nCharSet)365 static rtl_TextEncoding ImplCharSetToSal( BYTE nCharSet )
366 {
367     rtl_TextEncoding eTextEncoding;
368 
369     if ( nCharSet == OEM_CHARSET )
370     {
371         UINT nCP = static_cast<sal_uInt16>(GetOEMCP());
372         switch ( nCP )
373         {
374             // It is unclear why these two (undefined?) code page numbers are
375             // handled specially here:
376             case 1004:  eTextEncoding = RTL_TEXTENCODING_MS_1252; break;
377             case 65400: eTextEncoding = RTL_TEXTENCODING_SYMBOL; break;
378             default:
379                 eTextEncoding = rtl_getTextEncodingFromWindowsCodePage(nCP);
380                 break;
381         }
382     }
383     else
384     {
385         if( nCharSet )
386             eTextEncoding = rtl_getTextEncodingFromWindowsCharset( nCharSet );
387         else
388             eTextEncoding = RTL_TEXTENCODING_UNICODE;
389     }
390 
391     return eTextEncoding;
392 }
393 
ImplFamilyToSal(BYTE nFamily)394 static FontFamily ImplFamilyToSal( BYTE nFamily )
395 {
396     switch ( nFamily & 0xF0 )
397     {
398         case FF_DECORATIVE:
399             return FAMILY_DECORATIVE;
400 
401         case FF_MODERN:
402             return FAMILY_MODERN;
403 
404         case FF_ROMAN:
405             return FAMILY_ROMAN;
406 
407         case FF_SCRIPT:
408             return FAMILY_SCRIPT;
409 
410         case FF_SWISS:
411             return FAMILY_SWISS;
412 
413         default:
414             break;
415     }
416 
417     return FAMILY_DONTKNOW;
418 }
419 
ImplFamilyToWin(FontFamily eFamily)420 static BYTE ImplFamilyToWin( FontFamily eFamily )
421 {
422     switch ( eFamily )
423     {
424         case FAMILY_DECORATIVE:
425             return FF_DECORATIVE;
426 
427         case FAMILY_MODERN:
428             return FF_MODERN;
429 
430         case FAMILY_ROMAN:
431             return FF_ROMAN;
432 
433         case FAMILY_SCRIPT:
434             return FF_SCRIPT;
435 
436         case FAMILY_SWISS:
437             return FF_SWISS;
438 
439         case FAMILY_SYSTEM:
440             return FF_SWISS;
441 
442         default:
443             break;
444     }
445 
446     return FF_DONTCARE;
447 }
448 
ImplWeightToSal(int nWeight)449 static FontWeight ImplWeightToSal( int nWeight )
450 {
451     if ( nWeight <= FW_THIN )
452         return WEIGHT_THIN;
453     else if ( nWeight <= FW_ULTRALIGHT )
454         return WEIGHT_ULTRALIGHT;
455     else if ( nWeight <= FW_LIGHT )
456         return WEIGHT_LIGHT;
457     else if ( nWeight < FW_MEDIUM )
458         return WEIGHT_NORMAL;
459     else if ( nWeight == FW_MEDIUM )
460         return WEIGHT_MEDIUM;
461     else if ( nWeight <= FW_SEMIBOLD )
462         return WEIGHT_SEMIBOLD;
463     else if ( nWeight <= FW_BOLD )
464         return WEIGHT_BOLD;
465     else if ( nWeight <= FW_ULTRABOLD )
466         return WEIGHT_ULTRABOLD;
467     else
468         return WEIGHT_BLACK;
469 }
470 
ImplWeightToWin(FontWeight eWeight)471 static int ImplWeightToWin( FontWeight eWeight )
472 {
473     switch ( eWeight )
474     {
475         case WEIGHT_THIN:
476             return FW_THIN;
477 
478         case WEIGHT_ULTRALIGHT:
479             return FW_ULTRALIGHT;
480 
481         case WEIGHT_LIGHT:
482             return FW_LIGHT;
483 
484         case WEIGHT_SEMILIGHT:
485         case WEIGHT_NORMAL:
486             return FW_NORMAL;
487 
488         case WEIGHT_MEDIUM:
489             return FW_MEDIUM;
490 
491         case WEIGHT_SEMIBOLD:
492             return FW_SEMIBOLD;
493 
494         case WEIGHT_BOLD:
495             return FW_BOLD;
496 
497         case WEIGHT_ULTRABOLD:
498             return FW_ULTRABOLD;
499 
500         case WEIGHT_BLACK:
501             return FW_BLACK;
502 
503         default:
504             break;
505     }
506 
507     return 0;
508 }
509 
ImplLogPitchToSal(BYTE nPitch)510 static FontPitch ImplLogPitchToSal( BYTE nPitch )
511 {
512     if ( nPitch & FIXED_PITCH )
513         return PITCH_FIXED;
514     else
515         return PITCH_VARIABLE;
516 }
517 
ImplMetricPitchToSal(BYTE nPitch)518 static FontPitch ImplMetricPitchToSal( BYTE nPitch )
519 {
520     // Grrrr! See NT help
521     if ( !(nPitch & TMPF_FIXED_PITCH) )
522         return PITCH_FIXED;
523     else
524         return PITCH_VARIABLE;
525 }
526 
ImplPitchToWin(FontPitch ePitch)527 static BYTE ImplPitchToWin( FontPitch ePitch )
528 {
529     if ( ePitch == PITCH_FIXED )
530         return FIXED_PITCH;
531     else if ( ePitch == PITCH_VARIABLE )
532         return VARIABLE_PITCH;
533     else
534         return DEFAULT_PITCH;
535 }
536 
WinFont2DevFontAttributes(const ENUMLOGFONTEXW & rEnumFont,const NEWTEXTMETRICW & rMetric)537 static FontAttributes WinFont2DevFontAttributes( const ENUMLOGFONTEXW& rEnumFont,
538     const NEWTEXTMETRICW& rMetric)
539 {
540     FontAttributes aDFA;
541 
542     const LOGFONTW rLogFont = rEnumFont.elfLogFont;
543 
544     // get font face attributes
545     aDFA.SetFamilyType(ImplFamilyToSal( rLogFont.lfPitchAndFamily ));
546     aDFA.SetWidthType(WIDTH_DONTKNOW);
547     aDFA.SetWeight(ImplWeightToSal( rLogFont.lfWeight ));
548     aDFA.SetItalic((rLogFont.lfItalic) ? ITALIC_NORMAL : ITALIC_NONE);
549     aDFA.SetPitch(ImplLogPitchToSal( rLogFont.lfPitchAndFamily ));
550     aDFA.SetSymbolFlag(rLogFont.lfCharSet == SYMBOL_CHARSET);
551 
552     // get the font face name
553     aDFA.SetFamilyName(OUString(o3tl::toU(rLogFont.lfFaceName)));
554 
555     // use the face's style name only if it looks reasonable
556     const wchar_t* pStyleName = rEnumFont.elfStyle;
557     const wchar_t* pEnd = pStyleName + sizeof(rEnumFont.elfStyle)/sizeof(*rEnumFont.elfStyle);
558     const wchar_t* p = pStyleName;
559     for(; *p && (p < pEnd); ++p )
560         if( *p < 0x0020 )
561             break;
562     if( p < pEnd )
563         aDFA.SetStyleName(OUString(o3tl::toU(pStyleName)));
564 
565     // heuristics for font quality
566     // -   opentypeTT > truetype
567     aDFA.SetQuality( 0 );
568     if( rMetric.tmPitchAndFamily & TMPF_TRUETYPE )
569         aDFA.IncreaseQualityBy( 50 );
570     if( 0 != (rMetric.ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE)) )
571         aDFA.IncreaseQualityBy( 10 );
572 
573     // TODO: add alias names
574     return aDFA;
575 }
576 
577 
ImplLogMetricToDevFontDataW(const ENUMLOGFONTEXW * pLogFont,const NEWTEXTMETRICW * pMetric)578 static rtl::Reference<WinFontFace> ImplLogMetricToDevFontDataW( const ENUMLOGFONTEXW* pLogFont,
579                                          const NEWTEXTMETRICW* pMetric)
580 {
581     rtl::Reference<WinFontFace> pData = new WinFontFace(
582         WinFont2DevFontAttributes(*pLogFont, *pMetric),
583         pLogFont->elfLogFont.lfCharSet,
584         pMetric->tmPitchAndFamily );
585 
586     return pData;
587 }
588 
ImplSalLogFontToFontW(HDC hDC,const LOGFONTW & rLogFont,Font & rFont)589 void ImplSalLogFontToFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont )
590 {
591     OUString aFontName( o3tl::toU(rLogFont.lfFaceName) );
592     if (!aFontName.isEmpty())
593     {
594         rFont.SetFamilyName( aFontName );
595         rFont.SetCharSet( ImplCharSetToSal( rLogFont.lfCharSet ) );
596         rFont.SetFamily( ImplFamilyToSal( rLogFont.lfPitchAndFamily ) );
597         rFont.SetPitch( ImplLogPitchToSal( rLogFont.lfPitchAndFamily ) );
598         rFont.SetWeight( ImplWeightToSal( rLogFont.lfWeight ) );
599 
600         tools::Long nFontHeight = rLogFont.lfHeight;
601         if ( nFontHeight < 0 )
602             nFontHeight = -nFontHeight;
603         tools::Long nDPIY = GetDeviceCaps( hDC, LOGPIXELSY );
604         if( !nDPIY )
605             nDPIY = 600;
606         nFontHeight *= 72;
607         nFontHeight += nDPIY/2;
608         nFontHeight /= nDPIY;
609         rFont.SetFontSize( Size( 0, nFontHeight ) );
610         rFont.SetOrientation( Degree10(static_cast<sal_Int16>(rLogFont.lfEscapement)) );
611         if ( rLogFont.lfItalic )
612             rFont.SetItalic( ITALIC_NORMAL );
613         else
614             rFont.SetItalic( ITALIC_NONE );
615         if ( rLogFont.lfUnderline )
616             rFont.SetUnderline( LINESTYLE_SINGLE );
617         else
618             rFont.SetUnderline( LINESTYLE_NONE );
619         if ( rLogFont.lfStrikeOut )
620             rFont.SetStrikeout( STRIKEOUT_SINGLE );
621         else
622             rFont.SetStrikeout( STRIKEOUT_NONE );
623     }
624 }
625 
WinFontFace(const FontAttributes & rDFS,BYTE eWinCharSet,BYTE nPitchAndFamily)626 WinFontFace::WinFontFace( const FontAttributes& rDFS,
627     BYTE eWinCharSet, BYTE nPitchAndFamily )
628 :   PhysicalFontFace( rDFS ),
629     mnId( 0 ),
630     mbFontCapabilitiesRead( false ),
631     meWinCharSet( eWinCharSet ),
632     mnPitchAndFamily( nPitchAndFamily ),
633     mbAliasSymbolsHigh( false ),
634     mbAliasSymbolsLow( false )
635 {
636     if( eWinCharSet == SYMBOL_CHARSET )
637     {
638         if( (nPitchAndFamily & TMPF_TRUETYPE) != 0 )
639         {
640             // truetype fonts need their symbols as U+F0xx
641             mbAliasSymbolsHigh = true;
642         }
643         else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_DEVICE))
644                                  == (TMPF_VECTOR|TMPF_DEVICE) )
645         {
646             // scalable device fonts (e.g. builtin printer fonts)
647             // need their symbols as U+00xx
648             mbAliasSymbolsLow  = true;
649         }
650         else if( (nPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE)) == 0 )
651         {
652             // bitmap fonts need their symbols as U+F0xx
653             mbAliasSymbolsHigh = true;
654         }
655     }
656 }
657 
~WinFontFace()658 WinFontFace::~WinFontFace()
659 {
660     mxUnicodeMap.clear();
661 }
662 
GetFontId() const663 sal_IntPtr WinFontFace::GetFontId() const
664 {
665     return mnId;
666 }
667 
CreateFontInstance(const FontSelectPattern & rFSD) const668 rtl::Reference<LogicalFontInstance> WinFontFace::CreateFontInstance(const FontSelectPattern& rFSD) const
669 {
670 #if HAVE_FEATURE_SKIA
671     if (SkiaHelper::isVCLSkiaEnabled())
672         return new SkiaWinFontInstance(*this, rFSD);
673 #endif
674     return new WinFontInstance(*this, rFSD);
675 }
676 
CalcTag(const char p[5])677 static DWORD CalcTag( const char p[5]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); }
678 
UpdateFromHDC(HDC hDC) const679 void WinFontFace::UpdateFromHDC( HDC hDC ) const
680 {
681     // short circuit if already initialized
682     if( mxUnicodeMap.is() )
683         return;
684 
685     ReadCmapTable( hDC );
686     GetFontCapabilities( hDC );
687 }
688 
GetFontCharMap() const689 FontCharMapRef WinFontFace::GetFontCharMap() const
690 {
691     return mxUnicodeMap;
692 }
693 
GetFontCapabilities(vcl::FontCapabilities & rFontCapabilities) const694 bool WinFontFace::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
695 {
696     rFontCapabilities = maFontCapabilities;
697     return rFontCapabilities.oUnicodeRange || rFontCapabilities.oCodePageRange;
698 }
699 
ReadCmapTable(HDC hDC) const700 void WinFontFace::ReadCmapTable( HDC hDC ) const
701 {
702     if( mxUnicodeMap.is() )
703         return;
704 
705     bool bIsSymbolFont = (meWinCharSet == SYMBOL_CHARSET);
706     // get the CMAP table from the font which is selected into the DC
707     const DWORD nCmapTag = CalcTag( "cmap" );
708     const RawFontData aRawFontData( hDC, nCmapTag );
709     // parse the CMAP table if available
710     if( aRawFontData.get() ) {
711         CmapResult aResult;
712         ParseCMAP( aRawFontData.get(), aRawFontData.size(), aResult );
713         aResult.mbSymbolic = bIsSymbolFont;
714         if( aResult.mnRangeCount > 0 )
715         {
716             FontCharMapRef pUnicodeMap(new FontCharMap(aResult));
717             mxUnicodeMap = pUnicodeMap;
718         }
719     }
720 
721     if( !mxUnicodeMap.is() )
722     {
723         mxUnicodeMap = FontCharMap::GetDefaultMap( bIsSymbolFont );
724     }
725 }
726 
GetFontCapabilities(HDC hDC) const727 void WinFontFace::GetFontCapabilities( HDC hDC ) const
728 {
729     // read this only once per font
730     if( mbFontCapabilitiesRead )
731         return;
732 
733     mbFontCapabilitiesRead = true;
734 
735     // OS/2 table
736     const DWORD OS2Tag = CalcTag( "OS/2" );
737     DWORD nLength = ::GetFontData( hDC, OS2Tag, 0, nullptr, 0 );
738     if( (nLength != GDI_ERROR) && nLength )
739     {
740         std::vector<unsigned char> aTable( nLength );
741         unsigned char* pTable = aTable.data();
742         ::GetFontData( hDC, OS2Tag, 0, pTable, nLength );
743         vcl::getTTCoverage(maFontCapabilities.oUnicodeRange, maFontCapabilities.oCodePageRange, pTable, nLength);
744     }
745 }
746 
SetTextColor(Color nColor)747 void WinSalGraphics::SetTextColor( Color nColor )
748 {
749     COLORREF aCol = PALETTERGB( nColor.GetRed(),
750                                 nColor.GetGreen(),
751                                 nColor.GetBlue() );
752 
753     if( !mbPrinter &&
754         GetSalData()->mhDitherPal &&
755         ImplIsSysColorEntry( nColor ) )
756     {
757         aCol = PALRGB_TO_RGB( aCol );
758     }
759 
760     ::SetTextColor( getHDC(), aCol );
761 }
762 
SalEnumQueryFontProcExW(const LOGFONTW *,const TEXTMETRICW *,DWORD,LPARAM lParam)763 static int CALLBACK SalEnumQueryFontProcExW( const LOGFONTW*, const TEXTMETRICW*, DWORD, LPARAM lParam )
764 {
765     *reinterpret_cast<bool*>(lParam) = true;
766     return 0;
767 }
768 
ImplGetLogFontFromFontSelect(const FontSelectPattern & rFont,const PhysicalFontFace * pFontFace,LOGFONTW & rLogFont)769 void ImplGetLogFontFromFontSelect( const FontSelectPattern& rFont,
770                                    const PhysicalFontFace* pFontFace,
771                                    LOGFONTW& rLogFont )
772 {
773     OUString aName;
774     if (pFontFace)
775         aName = pFontFace->GetFamilyName();
776     else
777         aName = rFont.GetFamilyName().getToken( 0, ';' );
778 
779     UINT nNameLen = aName.getLength();
780     if (nNameLen >= LF_FACESIZE)
781         nNameLen = LF_FACESIZE - 1;
782     memcpy( rLogFont.lfFaceName, aName.getStr(), nNameLen*sizeof( wchar_t ) );
783     rLogFont.lfFaceName[nNameLen] = 0;
784 
785     if  (pFontFace)
786     {
787         const WinFontFace* pWinFontData = static_cast<const WinFontFace*>(pFontFace);
788         rLogFont.lfCharSet = pWinFontData->GetCharSet();
789         rLogFont.lfPitchAndFamily = pWinFontData->GetPitchAndFamily();
790     }
791     else
792     {
793         rLogFont.lfCharSet = rFont.IsSymbolFont() ? SYMBOL_CHARSET : DEFAULT_CHARSET;
794         rLogFont.lfPitchAndFamily = ImplPitchToWin( rFont.GetPitch() )
795                                   | ImplFamilyToWin( rFont.GetFamilyType() );
796     }
797 
798     rLogFont.lfWeight          = ImplWeightToWin( rFont.GetWeight() );
799     rLogFont.lfHeight          = static_cast<LONG>(-rFont.mnHeight);
800     rLogFont.lfWidth           = static_cast<LONG>(rFont.mnWidth);
801     rLogFont.lfUnderline       = 0;
802     rLogFont.lfStrikeOut       = 0;
803     rLogFont.lfItalic          = BYTE(rFont.GetItalic() != ITALIC_NONE);
804     rLogFont.lfEscapement      = rFont.mnOrientation.get();
805     rLogFont.lfOrientation     = rLogFont.lfEscapement;
806     rLogFont.lfClipPrecision   = CLIP_DEFAULT_PRECIS;
807     rLogFont.lfQuality         = DEFAULT_QUALITY;
808     rLogFont.lfOutPrecision    = OUT_TT_PRECIS;
809     if ( rFont.mnOrientation )
810         rLogFont.lfClipPrecision |= CLIP_LH_ANGLES;
811 
812     // disable antialiasing if requested
813     if ( rFont.mbNonAntialiased )
814         rLogFont.lfQuality = NONANTIALIASED_QUALITY;
815 
816 }
817 
ImplDoSetFont(FontSelectPattern const & i_rFont,const PhysicalFontFace * i_pFontFace,HFONT & o_rOldFont)818 std::tuple<HFONT,bool,sal_Int32> WinSalGraphics::ImplDoSetFont(FontSelectPattern const & i_rFont,
819                                     const PhysicalFontFace * i_pFontFace,
820                                     HFONT& o_rOldFont)
821 {
822     HFONT hNewFont = nullptr;
823 
824     LOGFONTW aLogFont;
825     ImplGetLogFontFromFontSelect( i_rFont, i_pFontFace, aLogFont );
826 
827     bool    bIsCJKVerticalFont = false;
828     // select vertical mode for printing if requested and available
829     if ( i_rFont.mbVertical && mbPrinter )
830     {
831         constexpr size_t nLen = sizeof(aLogFont.lfFaceName) - sizeof(aLogFont.lfFaceName[0]);
832         // vertical fonts start with an '@'
833         memmove( &aLogFont.lfFaceName[1], &aLogFont.lfFaceName[0], nLen );
834         aLogFont.lfFaceName[0] = '@';
835         aLogFont.lfFaceName[LF_FACESIZE - 1] = 0;
836 
837         // check availability of vertical mode for this font
838         EnumFontFamiliesExW( getHDC(), &aLogFont, SalEnumQueryFontProcExW,
839                 reinterpret_cast<LPARAM>(&bIsCJKVerticalFont), 0 );
840         if( !bIsCJKVerticalFont )
841         {
842             // restore non-vertical name if not vertical mode isn't available
843             memcpy( &aLogFont.lfFaceName[0], &aLogFont.lfFaceName[1], nLen );
844             aLogFont.lfFaceName[LF_FACESIZE - 1] = 0;
845         }
846     }
847 
848     hNewFont = ::CreateFontIndirectW( &aLogFont );
849 
850     HDC hdcScreen = nullptr;
851     if( mbVirDev )
852         // only required for virtual devices, see below for details
853         hdcScreen = GetDC(nullptr);
854     if( hdcScreen )
855     {
856         // select font into screen hdc first to get an antialiased font
857         // and instantly restore the default font!
858         // see knowledge base article 305290:
859         // "PRB: Fonts Not Drawn Antialiased on Device Context for DirectDraw Surface"
860         SelectFont( hdcScreen, SelectFont( hdcScreen , hNewFont ) );
861     }
862     o_rOldFont = ::SelectFont( getHDC(), hNewFont );
863 
864     TEXTMETRICW aTextMetricW;
865     if( !::GetTextMetricsW( getHDC(), &aTextMetricW ) )
866     {
867         // the selected font doesn't work => try a replacement
868         // TODO: use its font fallback instead
869         lstrcpynW( aLogFont.lfFaceName, L"Courier New", 12 );
870         aLogFont.lfPitchAndFamily = FIXED_PITCH;
871         HFONT hNewFont2 = CreateFontIndirectW( &aLogFont );
872         SelectFont( getHDC(), hNewFont2 );
873         DeleteFont( hNewFont );
874         hNewFont = hNewFont2;
875         bIsCJKVerticalFont = false;
876     }
877 
878     if( hdcScreen )
879         ::ReleaseDC( nullptr, hdcScreen );
880 
881     return std::make_tuple(hNewFont, bIsCJKVerticalFont, static_cast<sal_Int32>(aTextMetricW.tmDescent));
882 }
883 
SetFont(LogicalFontInstance * pFont,int nFallbackLevel)884 void WinSalGraphics::SetFont(LogicalFontInstance* pFont, int nFallbackLevel)
885 {
886     // return early if there is no new font
887     if( !pFont )
888     {
889         if (!mpWinFontEntry[nFallbackLevel].is())
890             return;
891 
892         // select original DC font
893         assert(mhDefFont);
894         ::SelectFont(getHDC(), mhDefFont);
895         mhDefFont = nullptr;
896 
897         // release no longer referenced font handles
898         for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
899             mpWinFontEntry[i] = nullptr;
900         return;
901     }
902 
903     WinFontInstance *pFontInstance = static_cast<WinFontInstance*>(pFont);
904     mpWinFontEntry[ nFallbackLevel ] = pFontInstance;
905 
906     HFONT hOldFont = nullptr;
907     HFONT hNewFont = pFontInstance->GetHFONT();
908     if (!hNewFont)
909     {
910         pFontInstance->SetGraphics(this);
911         hNewFont = pFontInstance->GetHFONT();
912     }
913     hOldFont = ::SelectFont(getHDC(), hNewFont);
914 
915     // keep default font
916     if( !mhDefFont )
917         mhDefFont = hOldFont;
918     else
919     {
920         // release no longer referenced font handles
921         for( int i = nFallbackLevel + 1; i < MAX_FALLBACK && mpWinFontEntry[i].is(); ++i )
922             mpWinFontEntry[i] = nullptr;
923     }
924 
925     // now the font is live => update font face
926     const WinFontFace* pFontFace = pFontInstance->GetFontFace();
927     pFontFace->UpdateFromHDC(getHDC());
928 }
929 
GetFontMetric(ImplFontMetricDataRef & rxFontMetric,int nFallbackLevel)930 void WinSalGraphics::GetFontMetric( ImplFontMetricDataRef& rxFontMetric, int nFallbackLevel )
931 {
932     // temporarily change the HDC to the font in the fallback level
933     rtl::Reference<WinFontInstance> pFontInstance = mpWinFontEntry[nFallbackLevel];
934     const HFONT hOldFont = SelectFont(getHDC(), pFontInstance->GetHFONT());
935 
936     wchar_t aFaceName[LF_FACESIZE+60];
937     if( GetTextFaceW( getHDC(), SAL_N_ELEMENTS(aFaceName), aFaceName ) )
938         rxFontMetric->SetFamilyName(OUString(o3tl::toU(aFaceName)));
939 
940     rxFontMetric->SetMinKashida(pFontInstance->GetKashidaWidth());
941     rxFontMetric->ImplCalcLineSpacing(pFontInstance.get());
942 
943     // get the font metric
944     OUTLINETEXTMETRICW aOutlineMetric;
945     const bool bOK = GetOutlineTextMetricsW(getHDC(), sizeof(aOutlineMetric), &aOutlineMetric);
946     // restore the HDC to the font in the base level
947     SelectFont( getHDC(), hOldFont );
948     if( !bOK )
949         return;
950 
951     TEXTMETRICW aWinMetric = aOutlineMetric.otmTextMetrics;
952 
953     // device independent font attributes
954     rxFontMetric->SetFamilyType(ImplFamilyToSal( aWinMetric.tmPitchAndFamily ));
955     rxFontMetric->SetSymbolFlag(aWinMetric.tmCharSet == SYMBOL_CHARSET);
956     rxFontMetric->SetWeight(ImplWeightToSal( aWinMetric.tmWeight ));
957     rxFontMetric->SetPitch(ImplMetricPitchToSal( aWinMetric.tmPitchAndFamily ));
958     rxFontMetric->SetItalic(aWinMetric.tmItalic ? ITALIC_NORMAL : ITALIC_NONE);
959     rxFontMetric->SetSlant( 0 );
960 
961     // transformation dependent font metrics
962     rxFontMetric->SetWidth(static_cast<int>(pFontInstance->GetScale() * aWinMetric.tmAveCharWidth));
963 }
964 
GetFontCharMap() const965 FontCharMapRef WinSalGraphics::GetFontCharMap() const
966 {
967     if (!mpWinFontEntry[0])
968     {
969         return FontCharMapRef( new FontCharMap() );
970     }
971     return mpWinFontEntry[0]->GetFontFace()->GetFontCharMap();
972 }
973 
GetFontCapabilities(vcl::FontCapabilities & rFontCapabilities) const974 bool WinSalGraphics::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
975 {
976     if (!mpWinFontEntry[0])
977         return false;
978     return mpWinFontEntry[0]->GetFontFace()->GetFontCapabilities(rFontCapabilities);
979 }
980 
SalEnumFontsProcExW(const LOGFONTW * lpelfe,const TEXTMETRICW * lpntme,DWORD nFontType,LPARAM lParam)981 static int CALLBACK SalEnumFontsProcExW( const LOGFONTW* lpelfe,
982                                   const TEXTMETRICW* lpntme,
983                                   DWORD nFontType, LPARAM lParam )
984 {
985     ENUMLOGFONTEXW const * pLogFont
986         = reinterpret_cast<ENUMLOGFONTEXW const *>(lpelfe);
987     NEWTEXTMETRICEXW const * pMetric
988         = reinterpret_cast<NEWTEXTMETRICEXW const *>(lpntme);
989     ImplEnumInfo* pInfo = reinterpret_cast<ImplEnumInfo*>(lParam);
990     if ( !pInfo->mpName )
991     {
992         // Ignore vertical fonts
993         if ( pLogFont->elfLogFont.lfFaceName[0] != '@' )
994         {
995             OUString aName(o3tl::toU(pLogFont->elfLogFont.lfFaceName));
996             pInfo->mpName = &aName;
997             memcpy(pInfo->mpLogFont->lfFaceName, pLogFont->elfLogFont.lfFaceName, (aName.getLength()+1)*sizeof(wchar_t));
998             pInfo->mpLogFont->lfCharSet = pLogFont->elfLogFont.lfCharSet;
999             EnumFontFamiliesExW(pInfo->mhDC, pInfo->mpLogFont, SalEnumFontsProcExW,
1000                                 reinterpret_cast<LPARAM>(pInfo), 0);
1001             pInfo->mpLogFont->lfFaceName[0] = '\0';
1002             pInfo->mpLogFont->lfCharSet = DEFAULT_CHARSET;
1003             pInfo->mpName = nullptr;
1004         }
1005     }
1006     else
1007     {
1008         // Ignore non-device fonts on printers.
1009         if (pInfo->mbPrinter)
1010         {
1011             if ((nFontType & RASTER_FONTTYPE) && !(nFontType & DEVICE_FONTTYPE))
1012             {
1013                 SAL_INFO("vcl.fonts", "Unsupported printer font ignored: " << OUString(o3tl::toU(pLogFont->elfLogFont.lfFaceName)));
1014                 return 1;
1015             }
1016         }
1017         // Only SFNT fonts are supported, ignore anything else.
1018         else if (!(nFontType & TRUETYPE_FONTTYPE) &&
1019                  !(pMetric->ntmTm.ntmFlags & NTM_PS_OPENTYPE) &&
1020                  !(pMetric->ntmTm.ntmFlags & NTM_TT_OPENTYPE))
1021         {
1022             SAL_INFO("vcl.fonts", "Unsupported font ignored: " << OUString(o3tl::toU(pLogFont->elfLogFont.lfFaceName)));
1023             return 1;
1024         }
1025 
1026         rtl::Reference<WinFontFace> pData = ImplLogMetricToDevFontDataW(pLogFont, &(pMetric->ntmTm));
1027         pData->SetFontId( sal_IntPtr( pInfo->mnFontCount++ ) );
1028 
1029         pInfo->mpList->Add( pData.get() );
1030         SAL_INFO("vcl.fonts", "SalEnumFontsProcExW: font added: " << pData->GetFamilyName() << " " << pData->GetStyleName());
1031     }
1032 
1033     return 1;
1034 }
1035 
1036 struct TempFontItem
1037 {
1038     OUString maFontResourcePath;
1039     TempFontItem* mpNextItem;
1040 };
1041 
lcl_AddFontResource(SalData & rSalData,const OUString & rFontFileURL,bool bShared)1042 static int lcl_AddFontResource(SalData& rSalData, const OUString& rFontFileURL, bool bShared)
1043 {
1044     OUString aFontSystemPath;
1045     OSL_VERIFY(!osl::FileBase::getSystemPathFromFileURL(rFontFileURL, aFontSystemPath));
1046 
1047     int nRet = AddFontResourceExW(o3tl::toW(aFontSystemPath.getStr()), FR_PRIVATE, nullptr);
1048     SAL_WARN_IF(nRet <= 0, "vcl.fonts", "AddFontResourceExW failed for " << rFontFileURL);
1049     if (nRet > 0)
1050     {
1051         TempFontItem* pNewItem = new TempFontItem;
1052         pNewItem->maFontResourcePath = aFontSystemPath;
1053         if (bShared)
1054         {
1055             pNewItem->mpNextItem = rSalData.mpSharedTempFontItem;
1056             rSalData.mpSharedTempFontItem = pNewItem;
1057         }
1058         else
1059         {
1060             pNewItem->mpNextItem = rSalData.mpOtherTempFontItem;
1061             rSalData.mpOtherTempFontItem = pNewItem;
1062         }
1063     }
1064     return nRet;
1065 }
1066 
ImplReleaseTempFonts(SalData & rSalData,bool bAll)1067 void ImplReleaseTempFonts(SalData& rSalData, bool bAll)
1068 {
1069     while (TempFontItem* p = rSalData.mpOtherTempFontItem)
1070     {
1071         RemoveFontResourceExW(o3tl::toW(p->maFontResourcePath.getStr()), FR_PRIVATE, nullptr);
1072         rSalData.mpOtherTempFontItem = p->mpNextItem;
1073         delete p;
1074     }
1075 
1076     if (!bAll)
1077         return;
1078 
1079     while (TempFontItem* p = rSalData.mpSharedTempFontItem)
1080     {
1081         RemoveFontResourceExW(o3tl::toW(p->maFontResourcePath.getStr()), FR_PRIVATE, nullptr);
1082         rSalData.mpSharedTempFontItem = p->mpNextItem;
1083         delete p;
1084     }
1085 }
1086 
lcl_GetFontFamilyName(const OUString & rFontFileURL)1087 static OUString lcl_GetFontFamilyName(const OUString& rFontFileURL)
1088 {
1089     // Create temporary file name
1090     OUString aTempFileURL;
1091     if (osl::File::E_None != osl::File::createTempFile(nullptr, nullptr, &aTempFileURL))
1092         return OUString();
1093     osl::File::remove(aTempFileURL);
1094     OUString aResSystemPath;
1095     osl::FileBase::getSystemPathFromFileURL(aTempFileURL, aResSystemPath);
1096 
1097     // Create font resource file (.fot)
1098     // There is a limit of 127 characters for the full path passed via lpszFile, so we have to
1099     // split the font URL and pass it as two parameters. As a result we can't use
1100     // CreateScalableFontResource for renaming, as it now expects the font in the system path.
1101     // But it's still good to use it for family name extraction, we're currently after.
1102     // BTW: it doesn't help to prefix the lpszFile with \\?\ to support larger paths.
1103     // TODO: use TTLoadEmbeddedFont (needs an EOT as input, so we have to add a header to the TTF)
1104     // TODO: forward the EOT from the AddTempDevFont call side, if VCL supports it
1105     INetURLObject aTTFUrl(rFontFileURL);
1106     // GetBase() strips the extension
1107     OUString aFilename = aTTFUrl.GetLastName(INetURLObject::DecodeMechanism::WithCharset);
1108     if (!CreateScalableFontResourceW(0, o3tl::toW(aResSystemPath.getStr()),
1109             o3tl::toW(aFilename.getStr()), o3tl::toW(aTTFUrl.GetPath().getStr())))
1110     {
1111         sal_uInt32 nError = GetLastError();
1112         SAL_WARN("vcl.fonts", "CreateScalableFontResource failed for " << aResSystemPath << " "
1113                               << aFilename << " " << aTTFUrl.GetPath() << " " << nError);
1114         return OUString();
1115     }
1116 
1117     // Open and read the font resource file
1118     osl::File aFotFile(aTempFileURL);
1119     if (osl::FileBase::E_None != aFotFile.open(osl_File_OpenFlag_Read))
1120         return OUString();
1121 
1122     sal_uInt64  nBytesRead = 0;
1123     char        aBuffer[4096];
1124     aFotFile.read( aBuffer, sizeof( aBuffer ), nBytesRead );
1125     // clean up temporary resource file
1126     aFotFile.close();
1127     osl::File::remove(aTempFileURL);
1128 
1129     // retrieve font family name from byte offset 0x4F6
1130     static const sal_uInt64 nNameOfs = 0x4F6;
1131     sal_uInt64 nPos = nNameOfs;
1132     for (; (nPos < nBytesRead) && (aBuffer[nPos] != 0); nPos++);
1133     if (nPos >= nBytesRead || (nPos == nNameOfs))
1134         return OUString();
1135 
1136     return OUString(aBuffer + nNameOfs, nPos - nNameOfs, osl_getThreadTextEncoding());
1137 }
1138 
AddTempDevFont(PhysicalFontCollection * pFontCollection,const OUString & rFontFileURL,const OUString & rFontName)1139 bool WinSalGraphics::AddTempDevFont(PhysicalFontCollection* pFontCollection,
1140                                     const OUString& rFontFileURL, const OUString& rFontName)
1141 {
1142     OUString aFontFamily = lcl_GetFontFamilyName(rFontFileURL);
1143     if (aFontFamily.isEmpty())
1144     {
1145         SAL_WARN("vcl.fonts", "error extracting font family from " << rFontFileURL);
1146         return false;
1147     }
1148 
1149     if (rFontName != aFontFamily)
1150     {
1151         SAL_WARN("vcl.fonts", "font family renaming not implemented; skipping embedded " << rFontName);
1152         return false;
1153     }
1154 
1155     int nFonts = lcl_AddFontResource(*GetSalData(), rFontFileURL, false);
1156     if (nFonts <= 0)
1157         return false;
1158 
1159     ImplEnumInfo aInfo;
1160     aInfo.mhDC = getHDC();
1161     aInfo.mpList = pFontCollection;
1162     aInfo.mpName = &aFontFamily;
1163     aInfo.mbPrinter = mbPrinter;
1164     aInfo.mnFontCount = pFontCollection->Count();
1165     const int nExpectedFontCount = aInfo.mnFontCount + nFonts;
1166 
1167     LOGFONTW aLogFont = {};
1168     aLogFont.lfCharSet = DEFAULT_CHARSET;
1169     aInfo.mpLogFont = &aLogFont;
1170 
1171     // add the font to the PhysicalFontCollection
1172     EnumFontFamiliesExW(getHDC(), &aLogFont,
1173         SalEnumFontsProcExW, reinterpret_cast<LPARAM>(&aInfo), 0);
1174 
1175     SAL_WARN_IF(nExpectedFontCount != pFontCollection->Count(), "vcl.fonts",
1176         "temp font was registered but is not in enumeration: " << rFontFileURL);
1177 
1178     return true;
1179 }
1180 
GetDevFontList(PhysicalFontCollection * pFontCollection)1181 void WinSalGraphics::GetDevFontList( PhysicalFontCollection* pFontCollection )
1182 {
1183     // make sure all LO shared fonts are registered temporarily
1184     static std::once_flag init;
1185     std::call_once(init, []()
1186     {
1187         auto registerFontsIn = [](const OUString& dir) {
1188             // collect fonts in font path that could not be registered
1189             osl::Directory aFontDir(dir);
1190             osl::FileBase::RC rcOSL = aFontDir.open();
1191             if (rcOSL == osl::FileBase::E_None)
1192             {
1193                 osl::DirectoryItem aDirItem;
1194                 SalData* pSalData = GetSalData();
1195                 assert(pSalData);
1196 
1197                 while (aFontDir.getNextItem(aDirItem, 10) == osl::FileBase::E_None)
1198                 {
1199                     osl::FileStatus aFileStatus(osl_FileStatus_Mask_FileURL);
1200                     rcOSL = aDirItem.getFileStatus(aFileStatus);
1201                     if (rcOSL == osl::FileBase::E_None)
1202                         lcl_AddFontResource(*pSalData, aFileStatus.getFileURL(), true);
1203                 }
1204             }
1205         };
1206 
1207         // determine font path
1208         // since we are only interested in fonts that could not be
1209         // registered before because of missing administration rights
1210         // only the font path of the user installation is needed
1211         OUString aPath("$BRAND_BASE_DIR");
1212         rtl_bootstrap_expandMacros(&aPath.pData);
1213 
1214         // internal font resources, required for normal operation, like OpenSymbol
1215         registerFontsIn(aPath + "/" LIBO_SHARE_RESOURCE_FOLDER "/common/fonts");
1216 
1217         // collect fonts in font path that could not be registered
1218         registerFontsIn(aPath + "/" LIBO_SHARE_FOLDER "/fonts/truetype");
1219 
1220         return true;
1221     });
1222 
1223     ImplEnumInfo aInfo;
1224     aInfo.mhDC          = getHDC();
1225     aInfo.mpList        = pFontCollection;
1226     aInfo.mpName        = nullptr;
1227     aInfo.mbPrinter     = mbPrinter;
1228     aInfo.mnFontCount   = 0;
1229 
1230     LOGFONTW aLogFont = {};
1231     aLogFont.lfCharSet = DEFAULT_CHARSET;
1232     aInfo.mpLogFont = &aLogFont;
1233 
1234     // fill the PhysicalFontCollection
1235     EnumFontFamiliesExW( getHDC(), &aLogFont,
1236         SalEnumFontsProcExW, reinterpret_cast<LPARAM>(&aInfo), 0 );
1237 
1238     // set glyph fallback hook
1239     static WinGlyphFallbackSubstititution aSubstFallback;
1240     static WinPreMatchFontSubstititution aPreMatchFont;
1241     pFontCollection->SetFallbackHook( &aSubstFallback );
1242     pFontCollection->SetPreMatchHook(&aPreMatchFont);
1243 }
1244 
ClearDevFontCache()1245 void WinSalGraphics::ClearDevFontCache()
1246 {
1247     WinSalGraphicsImplBase* pImpl = dynamic_cast<WinSalGraphicsImplBase*>(GetImpl());
1248     assert(pImpl != nullptr);
1249     pImpl->ClearDevFontCache();
1250     ImplReleaseTempFonts(*GetSalData(), false);
1251 }
1252 
ImplGetGlyphBoundRect(sal_GlyphId nId,tools::Rectangle & rRect,bool bIsVertical) const1253 bool WinFontInstance::ImplGetGlyphBoundRect(sal_GlyphId nId, tools::Rectangle& rRect, bool bIsVertical) const
1254 {
1255     assert(m_pGraphics);
1256     HDC hDC = m_pGraphics->getHDC();
1257     const HFONT hOrigFont = static_cast<HFONT>(GetCurrentObject(hDC, OBJ_FONT));
1258     const HFONT hFont = GetHFONT();
1259     if (hFont != hOrigFont)
1260         SelectObject(hDC, hFont);
1261 
1262     const ::comphelper::ScopeGuard aFontRestoreScopeGuard([hFont, hOrigFont, hDC]()
1263         { if (hFont != hOrigFont) SelectObject(hDC, hOrigFont); });
1264     const float fFontScale = GetScale();
1265 
1266     // use unity matrix
1267     MAT2 aMat;
1268     const FontSelectPattern& rFSD = GetFontSelectPattern();
1269 
1270     // Use identity matrix for fonts requested in horizontal
1271     // writing (LTR or RTL), or rotated glyphs in vertical writing.
1272     if (!rFSD.mbVertical || !bIsVertical)
1273     {
1274         aMat.eM11 = aMat.eM22 = FixedFromDouble(1.0);
1275         aMat.eM12 = aMat.eM21 = FixedFromDouble(0.0);
1276     }
1277     else
1278     {
1279         constexpr double nCos = 0.0;
1280         constexpr double nSin = 1.0;
1281         aMat.eM11 = FixedFromDouble(nCos);
1282         aMat.eM12 = FixedFromDouble(nSin);
1283         aMat.eM21 = FixedFromDouble(-nSin);
1284         aMat.eM22 = FixedFromDouble(nCos);
1285     }
1286 
1287     UINT nGGOFlags = GGO_METRICS;
1288     nGGOFlags |= GGO_GLYPH_INDEX;
1289 
1290     GLYPHMETRICS aGM;
1291     aGM.gmptGlyphOrigin.x = aGM.gmptGlyphOrigin.y = 0;
1292     aGM.gmBlackBoxX = aGM.gmBlackBoxY = 0;
1293     DWORD nSize = ::GetGlyphOutlineW(hDC, nId, nGGOFlags, &aGM, 0, nullptr, &aMat);
1294     if (nSize == GDI_ERROR)
1295         return false;
1296 
1297     rRect = tools::Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
1298         Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
1299     rRect.SetLeft(static_cast<int>( fFontScale * rRect.Left() ));
1300     rRect.SetRight(static_cast<int>( fFontScale * rRect.Right() ) + 1);
1301     rRect.SetTop(static_cast<int>( fFontScale * rRect.Top() ));
1302     rRect.SetBottom(static_cast<int>( fFontScale * rRect.Bottom() ) + 1);
1303     return true;
1304 }
1305 
GetGlyphOutline(sal_GlyphId nId,basegfx::B2DPolyPolygon & rB2DPolyPoly,bool) const1306 bool WinFontInstance::GetGlyphOutline(sal_GlyphId nId, basegfx::B2DPolyPolygon& rB2DPolyPoly, bool) const
1307 {
1308     rB2DPolyPoly.clear();
1309 
1310     assert(m_pGraphics);
1311     HDC hDC = m_pGraphics->getHDC();
1312     const HFONT hOrigFont = static_cast<HFONT>(GetCurrentObject(hDC, OBJ_FONT));
1313     const HFONT hFont = GetHFONT();
1314     if (hFont != hOrigFont)
1315         SelectObject(hDC, hFont);
1316 
1317     const ::comphelper::ScopeGuard aFontRestoreScopeGuard([hFont, hOrigFont, hDC]()
1318         { if (hFont != hOrigFont) SelectObject(hDC, hOrigFont); });
1319 
1320     // use unity matrix
1321     MAT2 aMat;
1322     aMat.eM11 = aMat.eM22 = FixedFromDouble( 1.0 );
1323     aMat.eM12 = aMat.eM21 = FixedFromDouble( 0.0 );
1324 
1325     UINT nGGOFlags = GGO_NATIVE;
1326     nGGOFlags |= GGO_GLYPH_INDEX;
1327 
1328     GLYPHMETRICS aGlyphMetrics;
1329     const DWORD nSize1 = ::GetGlyphOutlineW(hDC, nId, nGGOFlags, &aGlyphMetrics, 0, nullptr, &aMat);
1330     if( !nSize1 )       // blank glyphs are ok
1331         return true;
1332     else if( nSize1 == GDI_ERROR )
1333         return false;
1334 
1335     BYTE* pData = new BYTE[ nSize1 ];
1336     const DWORD nSize2 = ::GetGlyphOutlineW(hDC, nId, nGGOFlags,
1337               &aGlyphMetrics, nSize1, pData, &aMat );
1338 
1339     if( nSize1 != nSize2 )
1340         return false;
1341 
1342     // TODO: avoid tools polygon by creating B2DPolygon directly
1343     int     nPtSize = 512;
1344     Point*  pPoints = new Point[ nPtSize ];
1345     PolyFlags* pFlags = new PolyFlags[ nPtSize ];
1346 
1347     TTPOLYGONHEADER* pHeader = reinterpret_cast<TTPOLYGONHEADER*>(pData);
1348     while( reinterpret_cast<BYTE*>(pHeader) < pData+nSize2 )
1349     {
1350         // only outline data is interesting
1351         if( pHeader->dwType != TT_POLYGON_TYPE )
1352             break;
1353 
1354         // get start point; next start points are end points
1355         // of previous segment
1356         sal_uInt16 nPnt = 0;
1357 
1358         tools::Long nX = IntTimes256FromFixed( pHeader->pfxStart.x );
1359         tools::Long nY = IntTimes256FromFixed( pHeader->pfxStart.y );
1360         pPoints[ nPnt ] = Point( nX, nY );
1361         pFlags[ nPnt++ ] = PolyFlags::Normal;
1362 
1363         bool bHasOfflinePoints = false;
1364         TTPOLYCURVE* pCurve = reinterpret_cast<TTPOLYCURVE*>( pHeader + 1 );
1365         pHeader = reinterpret_cast<TTPOLYGONHEADER*>( reinterpret_cast<BYTE*>(pHeader) + pHeader->cb );
1366         while( reinterpret_cast<BYTE*>(pCurve) < reinterpret_cast<BYTE*>(pHeader) )
1367         {
1368             int nNeededSize = nPnt + 16 + 3 * pCurve->cpfx;
1369             if( nPtSize < nNeededSize )
1370             {
1371                 Point* pOldPoints = pPoints;
1372                 PolyFlags* pOldFlags = pFlags;
1373                 nPtSize = 2 * nNeededSize;
1374                 pPoints = new Point[ nPtSize ];
1375                 pFlags = new PolyFlags[ nPtSize ];
1376                 for( sal_uInt16 i = 0; i < nPnt; ++i )
1377                 {
1378                     pPoints[ i ] = pOldPoints[ i ];
1379                     pFlags[ i ] = pOldFlags[ i ];
1380                 }
1381                 delete[] pOldPoints;
1382                 delete[] pOldFlags;
1383             }
1384 
1385             int i = 0;
1386             if( TT_PRIM_LINE == pCurve->wType )
1387             {
1388                 while( i < pCurve->cpfx )
1389                 {
1390                     nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1391                     nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1392                     ++i;
1393                     pPoints[ nPnt ] = Point( nX, nY );
1394                     pFlags[ nPnt ] = PolyFlags::Normal;
1395                     ++nPnt;
1396                 }
1397             }
1398             else if( TT_PRIM_QSPLINE == pCurve->wType )
1399             {
1400                 bHasOfflinePoints = true;
1401                 while( i < pCurve->cpfx )
1402                 {
1403                     // get control point of quadratic bezier spline
1404                     nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1405                     nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1406                     ++i;
1407                     Point aControlP( nX, nY );
1408 
1409                     // calculate first cubic control point
1410                     // P0 = 1/3 * (PBeg + 2 * PQControl)
1411                     nX = pPoints[ nPnt-1 ].X() + 2 * aControlP.X();
1412                     nY = pPoints[ nPnt-1 ].Y() + 2 * aControlP.Y();
1413                     pPoints[ nPnt+0 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
1414                     pFlags[ nPnt+0 ] = PolyFlags::Control;
1415 
1416                     // calculate endpoint of segment
1417                     nX = IntTimes256FromFixed( pCurve->apfx[ i ].x );
1418                     nY = IntTimes256FromFixed( pCurve->apfx[ i ].y );
1419 
1420                     if ( i+1 >= pCurve->cpfx )
1421                     {
1422                         // endpoint is either last point in segment => advance
1423                         ++i;
1424                     }
1425                     else
1426                     {
1427                         // or endpoint is the middle of two control points
1428                         nX += IntTimes256FromFixed( pCurve->apfx[ i-1 ].x );
1429                         nY += IntTimes256FromFixed( pCurve->apfx[ i-1 ].y );
1430                         nX = (nX + 1) / 2;
1431                         nY = (nY + 1) / 2;
1432                         // no need to advance, because the current point
1433                         // is the control point in next bezier spline
1434                     }
1435 
1436                     pPoints[ nPnt+2 ] = Point( nX, nY );
1437                     pFlags[ nPnt+2 ] = PolyFlags::Normal;
1438 
1439                     // calculate second cubic control point
1440                     // P1 = 1/3 * (PEnd + 2 * PQControl)
1441                     nX = pPoints[ nPnt+2 ].X() + 2 * aControlP.X();
1442                     nY = pPoints[ nPnt+2 ].Y() + 2 * aControlP.Y();
1443                     pPoints[ nPnt+1 ] = Point( (2*nX+3)/6, (2*nY+3)/6 );
1444                     pFlags[ nPnt+1 ] = PolyFlags::Control;
1445 
1446                     nPnt += 3;
1447                 }
1448             }
1449 
1450             // next curve segment
1451             pCurve = reinterpret_cast<TTPOLYCURVE*>(&pCurve->apfx[ i ]);
1452         }
1453 
1454         // end point is start point for closed contour
1455         // disabled, because Polygon class closes the contour itself
1456         // pPoints[nPnt++] = pPoints[0];
1457         // #i35928#
1458         // Added again, but add only when not yet closed
1459         if(pPoints[nPnt - 1] != pPoints[0])
1460         {
1461             if( bHasOfflinePoints )
1462                 pFlags[nPnt] = pFlags[0];
1463 
1464             pPoints[nPnt++] = pPoints[0];
1465         }
1466 
1467         // convert y-coordinates W32 -> VCL
1468         for( int i = 0; i < nPnt; ++i )
1469             pPoints[i].setY(-pPoints[i].Y());
1470 
1471         // insert into polypolygon
1472         tools::Polygon aPoly( nPnt, pPoints, (bHasOfflinePoints ? pFlags : nullptr) );
1473         // convert to B2DPolyPolygon
1474         // TODO: get rid of the intermediate PolyPolygon
1475         rB2DPolyPoly.append( aPoly.getB2DPolygon() );
1476     }
1477 
1478     delete[] pPoints;
1479     delete[] pFlags;
1480 
1481     delete[] pData;
1482 
1483     // rescaling needed for the tools::PolyPolygon conversion
1484     if( rB2DPolyPoly.count() )
1485     {
1486         const double fFactor(GetScale()/256);
1487         rB2DPolyPoly.transform(basegfx::utils::createScaleB2DHomMatrix(fFactor, fFactor));
1488     }
1489 
1490     return true;
1491 }
1492 
1493 class ScopedFont
1494 {
1495 public:
1496     explicit ScopedFont(WinSalGraphics & rData);
1497 
1498     ~ScopedFont();
1499 
1500 private:
1501     WinSalGraphics & m_rData;
1502     HFONT m_hOrigFont;
1503 };
1504 
ScopedFont(WinSalGraphics & rData)1505 ScopedFont::ScopedFont(WinSalGraphics & rData): m_rData(rData), m_hOrigFont(nullptr)
1506 {
1507     if (m_rData.mpWinFontEntry[0])
1508     {
1509         m_hOrigFont = m_rData.mpWinFontEntry[0]->GetHFONT();
1510         m_rData.mpWinFontEntry[0]->SetHFONT(nullptr);
1511     }
1512 }
1513 
~ScopedFont()1514 ScopedFont::~ScopedFont()
1515 {
1516     if( m_hOrigFont )
1517     {
1518         // restore original font, destroy temporary font
1519         HFONT hTempFont = m_rData.mpWinFontEntry[0]->GetHFONT();
1520         m_rData.mpWinFontEntry[0]->SetHFONT(m_hOrigFont);
1521         SelectObject( m_rData.getHDC(), m_hOrigFont );
1522         DeleteObject( hTempFont );
1523     }
1524 }
1525 
1526 namespace {
1527 
1528 class ScopedTrueTypeFont
1529 {
1530 public:
ScopedTrueTypeFont()1531     ScopedTrueTypeFont(): m_pFont(nullptr) {}
1532 
1533     ~ScopedTrueTypeFont();
1534 
1535     SFErrCodes open(void const * pBuffer, sal_uInt32 nLen, sal_uInt32 nFaceNum, const FontCharMapRef xCharMap = nullptr);
1536 
get() const1537     TrueTypeFont * get() const { return m_pFont; }
1538 
1539 private:
1540     TrueTypeFont * m_pFont;
1541 };
1542 
1543 }
1544 
~ScopedTrueTypeFont()1545 ScopedTrueTypeFont::~ScopedTrueTypeFont()
1546 {
1547     if (m_pFont != nullptr)
1548         CloseTTFont(m_pFont);
1549 }
1550 
open(void const * pBuffer,sal_uInt32 nLen,sal_uInt32 nFaceNum,const FontCharMapRef xCharMap)1551 SFErrCodes ScopedTrueTypeFont::open(void const * pBuffer, sal_uInt32 nLen,
1552                              sal_uInt32 nFaceNum, const FontCharMapRef xCharMap)
1553 {
1554     OSL_ENSURE(m_pFont == nullptr, "already open");
1555     return OpenTTFontBuffer(pBuffer, nLen, nFaceNum, &m_pFont, xCharMap);
1556 }
1557 
CreateFontSubset(const OUString & rToFile,const PhysicalFontFace * pFont,const sal_GlyphId * pGlyphIds,const sal_uInt8 * pEncoding,sal_Int32 * pGlyphWidths,int nGlyphCount,FontSubsetInfo & rInfo)1558 bool WinSalGraphics::CreateFontSubset( const OUString& rToFile,
1559     const PhysicalFontFace* pFont, const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding,
1560     sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo )
1561 {
1562     // TODO: use more of the central font-subsetting code, move stuff there if needed
1563 
1564     // create matching FontSelectPattern
1565     // we need just enough to get to the font file data
1566     // use height=1000 for easier debugging (to match psprint's font units)
1567     FontSelectPattern aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1568 
1569     // TODO: much better solution: move SetFont and restoration of old font to caller
1570     ScopedFont aOldFont(*this);
1571     HFONT hOldFont = nullptr;
1572     ImplDoSetFont(aIFSD, pFont, hOldFont);
1573 
1574     WinFontFace const * pWinFontData = static_cast<WinFontFace const *>(pFont);
1575 
1576 #if OSL_DEBUG_LEVEL > 1
1577     // get font metrics
1578     TEXTMETRICW aWinMetric;
1579     if( !::GetTextMetricsW( getHDC(), &aWinMetric ) )
1580         return FALSE;
1581 
1582     SAL_WARN_IF( (aWinMetric.tmPitchAndFamily & TMPF_DEVICE), "vcl", "cannot subset device font" );
1583     SAL_WARN_IF( !(aWinMetric.tmPitchAndFamily & TMPF_TRUETYPE), "vcl", "can only subset TT font" );
1584 #endif
1585 
1586     OUString aSysPath;
1587     if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) )
1588         return false;
1589     const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding();
1590     const OString aToFile(OUStringToOString(aSysPath, aThreadEncoding));
1591 
1592     // check if the font has a CFF-table
1593     const DWORD nCffTag = CalcTag( "CFF " );
1594     const RawFontData aRawCffData( getHDC(), nCffTag );
1595     if (aRawCffData.get())
1596     {
1597         pWinFontData->UpdateFromHDC( getHDC() );
1598         return SalGraphics::CreateCFFfontSubset(aRawCffData.get(), aRawCffData.size(), aToFile,
1599                                                 pGlyphIds, pEncoding, pGlyphWidths, nGlyphCount,
1600                                                 rInfo);
1601     }
1602 
1603     // get raw font file data
1604     const RawFontData xRawFontData( getHDC(), 0 );
1605     if( !xRawFontData.get() )
1606         return false;
1607 
1608     // open font file
1609     sal_uInt32 nFaceNum = 0;
1610     if( !*xRawFontData.get() )  // TTC candidate
1611         nFaceNum = ~0U;  // indicate "TTC font extracts only"
1612 
1613     ScopedTrueTypeFont aSftTTF;
1614     SFErrCodes nRC = aSftTTF.open( xRawFontData.get(), xRawFontData.size(), nFaceNum, pFont->GetFontCharMap());
1615     if( nRC != SFErrCodes::Ok )
1616         return false;
1617 
1618     TTGlobalFontInfo aTTInfo;
1619     ::GetTTGlobalFontInfo( aSftTTF.get(), &aTTInfo );
1620     OUString aPSName = ImplSalGetUniString(aTTInfo.psname);
1621     FillFontSubsetInfo(aTTInfo, aPSName, rInfo);
1622 
1623     // write subset into destination file
1624     return SalGraphics::CreateTTFfontSubset(*aSftTTF.get(), aToFile, aIFSD.mbVertical, pGlyphIds,
1625                                             pEncoding, pGlyphWidths, nGlyphCount);
1626 }
1627 
GetEmbedFontData(const PhysicalFontFace * pFont,tools::Long * pDataLen)1628 const void* WinSalGraphics::GetEmbedFontData(const PhysicalFontFace* pFont, tools::Long* pDataLen)
1629 {
1630     // create matching FontSelectPattern
1631     // we need just enough to get to the font file data
1632     FontSelectPattern aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1633 
1634     ScopedFont aOldFont(*this);
1635 
1636     HFONT hOldFont = nullptr;
1637     ImplDoSetFont(aIFSD, pFont, hOldFont);
1638 
1639     // get the raw font file data
1640     RawFontData aRawFontData( getHDC() );
1641     *pDataLen = aRawFontData.size();
1642     if( !aRawFontData.get() )
1643         return nullptr;
1644 
1645     const unsigned char* pData = aRawFontData.steal();
1646     return pData;
1647 }
1648 
FreeEmbedFontData(const void * pData,tools::Long)1649 void WinSalGraphics::FreeEmbedFontData( const void* pData, tools::Long /*nLen*/ )
1650 {
1651     delete[] static_cast<char const *>(pData);
1652 }
1653 
GetGlyphWidths(const PhysicalFontFace * pFont,bool bVertical,std::vector<sal_Int32> & rWidths,Ucs2UIntMap & rUnicodeEnc)1654 void WinSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFont,
1655                                      bool bVertical,
1656                                      std::vector< sal_Int32 >& rWidths,
1657                                      Ucs2UIntMap& rUnicodeEnc )
1658 {
1659     // create matching FontSelectPattern
1660     // we need just enough to get to the font file data
1661     FontSelectPattern aIFSD( *pFont, Size(0,1000), 1000.0, 0, false );
1662 
1663     // TODO: much better solution: move SetFont and restoration of old font to caller
1664     ScopedFont aOldFont(*this);
1665 
1666     HFONT hOldFont = nullptr;
1667     ImplDoSetFont(aIFSD, pFont, hOldFont);
1668 
1669     // get raw font file data
1670     const RawFontData xRawFontData( getHDC() );
1671     if( !xRawFontData.get() )
1672         return;
1673 
1674     // open font file
1675     sal_uInt32 nFaceNum = 0;
1676     if( !*xRawFontData.get() )  // TTC candidate
1677         nFaceNum = ~0U;  // indicate "TTC font extracts only"
1678 
1679     ScopedTrueTypeFont aSftTTF;
1680     SFErrCodes nRC = aSftTTF.open(xRawFontData.get(), xRawFontData.size(), nFaceNum, pFont->GetFontCharMap());
1681     if( nRC != SFErrCodes::Ok )
1682         return;
1683 
1684     SalGraphics::GetGlyphWidths(*aSftTTF.get(), *pFont, bVertical, rWidths, rUnicodeEnc);
1685 }
1686 
1687 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1688