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