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 <tools/stream.hxx>
21 #include <tools/vcompat.hxx>
22 #include <tools/gen.hxx>
23 #include <unotools/fontcfg.hxx>
24 #include <unotools/fontdefs.hxx>
25 
26 #include <vcl/font.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/outdev.hxx>
29 #include <vcl/virdev.hxx>
30 
31 #include <impfont.hxx>
32 #include <fontattributes.hxx>
33 #include <sft.hxx>
34 
35 #include <algorithm>
36 #include <string_view>
37 
38 #include <rtl/instance.hxx>
39 #include <vcl/TypeSerializer.hxx>
40 
41 #ifdef _WIN32
42 #include <vcl/metric.hxx>
43 #endif
44 
45 using namespace vcl;
46 
47 namespace
48 {
49     struct theGlobalDefault :
50         public rtl::Static< Font::ImplType, theGlobalDefault > {};
51 }
52 
Font()53 Font::Font() : mpImplFont(theGlobalDefault::get())
54 {
55 }
56 
Font(const vcl::Font & rFont)57 Font::Font( const vcl::Font& rFont ) : mpImplFont( rFont.mpImplFont )
58 {
59 }
60 
Font(vcl::Font && rFont)61 Font::Font( vcl::Font&& rFont ) noexcept : mpImplFont( std::move(rFont.mpImplFont) )
62 {
63 }
64 
Font(const OUString & rFamilyName,const Size & rSize)65 Font::Font( const OUString& rFamilyName, const Size& rSize ) : mpImplFont()
66 {
67     mpImplFont->SetFamilyName( rFamilyName );
68     mpImplFont->SetFontSize( rSize );
69 }
70 
Font(const OUString & rFamilyName,const OUString & rStyleName,const Size & rSize)71 Font::Font( const OUString& rFamilyName, const OUString& rStyleName, const Size& rSize ) : mpImplFont()
72 {
73     mpImplFont->SetFamilyName( rFamilyName );
74     mpImplFont->SetStyleName( rStyleName );
75     mpImplFont->SetFontSize( rSize );
76 }
77 
Font(FontFamily eFamily,const Size & rSize)78 Font::Font( FontFamily eFamily, const Size& rSize ) : mpImplFont()
79 {
80     mpImplFont->SetFamilyType( eFamily );
81     mpImplFont->SetFontSize( rSize );
82 }
83 
~Font()84 Font::~Font()
85 {
86 }
87 
SetColor(const Color & rColor)88 void Font::SetColor( const Color& rColor )
89 {
90     if (const_cast<const ImplType&>(mpImplFont)->maColor != rColor)
91     {
92         mpImplFont->maColor = rColor;
93     }
94 }
95 
SetFillColor(const Color & rColor)96 void Font::SetFillColor( const Color& rColor )
97 {
98     mpImplFont->maFillColor = rColor;
99     if ( rColor.IsTransparent() )
100         mpImplFont->mbTransparent = true;
101 }
102 
SetTransparent(bool bTransparent)103 void Font::SetTransparent( bool bTransparent )
104 {
105     if (const_cast<const ImplType&>(mpImplFont)->mbTransparent != bTransparent)
106         mpImplFont->mbTransparent = bTransparent;
107 }
108 
SetAlignment(FontAlign eAlign)109 void Font::SetAlignment( FontAlign eAlign )
110 {
111     if (const_cast<const ImplType&>(mpImplFont)->meAlign != eAlign)
112         mpImplFont->SetAlignment(eAlign);
113 }
114 
SetFamilyName(const OUString & rFamilyName)115 void Font::SetFamilyName( const OUString& rFamilyName )
116 {
117     mpImplFont->SetFamilyName( rFamilyName );
118 }
119 
SetStyleName(const OUString & rStyleName)120 void Font::SetStyleName( const OUString& rStyleName )
121 {
122     mpImplFont->maStyleName = rStyleName;
123 }
124 
SetFontSize(const Size & rSize)125 void Font::SetFontSize( const Size& rSize )
126 {
127     if (const_cast<const ImplType&>(mpImplFont)->GetFontSize() != rSize)
128         mpImplFont->SetFontSize( rSize );
129 }
130 
SetFamily(FontFamily eFamily)131 void Font::SetFamily( FontFamily eFamily )
132 {
133     if (const_cast<const ImplType&>(mpImplFont)->GetFamilyTypeNoAsk() != eFamily)
134         mpImplFont->SetFamilyType( eFamily );
135 }
136 
SetCharSet(rtl_TextEncoding eCharSet)137 void Font::SetCharSet( rtl_TextEncoding eCharSet )
138 {
139     if (const_cast<const ImplType&>(mpImplFont)->GetCharSet() != eCharSet)
140     {
141         mpImplFont->SetCharSet( eCharSet );
142 
143         if ( eCharSet == RTL_TEXTENCODING_SYMBOL )
144             mpImplFont->SetSymbolFlag( true );
145         else
146             mpImplFont->SetSymbolFlag( false );
147     }
148 }
149 
IsSymbolFont() const150 bool Font::IsSymbolFont() const
151 {
152     return mpImplFont->IsSymbolFont();
153 }
154 
SetSymbolFlag(bool bSymbol)155 void Font::SetSymbolFlag( bool bSymbol )
156 {
157     mpImplFont->SetSymbolFlag( bSymbol );
158 
159     if ( IsSymbolFont() )
160     {
161         mpImplFont->SetCharSet( RTL_TEXTENCODING_SYMBOL );
162     }
163     else
164     {
165         if ( mpImplFont->GetCharSet() == RTL_TEXTENCODING_SYMBOL )
166             mpImplFont->SetCharSet( RTL_TEXTENCODING_DONTKNOW );
167     }
168 }
169 
SetLanguageTag(const LanguageTag & rLanguageTag)170 void Font::SetLanguageTag( const LanguageTag& rLanguageTag )
171 {
172     if (const_cast<const ImplType&>(mpImplFont)->maLanguageTag != rLanguageTag)
173         mpImplFont->maLanguageTag = rLanguageTag;
174 }
175 
SetCJKContextLanguageTag(const LanguageTag & rLanguageTag)176 void Font::SetCJKContextLanguageTag( const LanguageTag& rLanguageTag )
177 {
178     if (const_cast<const ImplType&>(mpImplFont)->maCJKLanguageTag != rLanguageTag)
179         mpImplFont->maCJKLanguageTag = rLanguageTag;
180 }
181 
SetLanguage(LanguageType eLanguage)182 void Font::SetLanguage( LanguageType eLanguage )
183 {
184     if (const_cast<const ImplType&>(mpImplFont)->maLanguageTag.getLanguageType(false) != eLanguage)
185         mpImplFont->maLanguageTag.reset( eLanguage);
186 }
187 
SetCJKContextLanguage(LanguageType eLanguage)188 void Font::SetCJKContextLanguage( LanguageType eLanguage )
189 {
190     if (const_cast<const ImplType&>(mpImplFont)->maCJKLanguageTag.getLanguageType(false) != eLanguage)
191         mpImplFont->maCJKLanguageTag.reset( eLanguage);
192 }
193 
SetPitch(FontPitch ePitch)194 void Font::SetPitch( FontPitch ePitch )
195 {
196     if (const_cast<const ImplType&>(mpImplFont)->GetPitchNoAsk() != ePitch)
197         mpImplFont->SetPitch( ePitch );
198 }
199 
SetOrientation(Degree10 nOrientation)200 void Font::SetOrientation( Degree10 nOrientation )
201 {
202     if (const_cast<const ImplType&>(mpImplFont)->mnOrientation != nOrientation)
203         mpImplFont->mnOrientation = nOrientation;
204 }
205 
SetVertical(bool bVertical)206 void Font::SetVertical( bool bVertical )
207 {
208     if (const_cast<const ImplType&>(mpImplFont)->mbVertical != bVertical)
209         mpImplFont->mbVertical = bVertical;
210 }
211 
SetKerning(FontKerning eKerning)212 void Font::SetKerning( FontKerning eKerning )
213 {
214     if (const_cast<const ImplType&>(mpImplFont)->meKerning != eKerning)
215         mpImplFont->meKerning = eKerning;
216 }
217 
IsKerning() const218 bool Font::IsKerning() const
219 {
220     return mpImplFont->meKerning != FontKerning::NONE;
221 }
222 
SetWeight(FontWeight eWeight)223 void Font::SetWeight( FontWeight eWeight )
224 {
225     if (const_cast<const ImplType&>(mpImplFont)->GetWeightNoAsk() != eWeight)
226         mpImplFont->SetWeight( eWeight );
227 }
228 
SetWidthType(FontWidth eWidth)229 void Font::SetWidthType( FontWidth eWidth )
230 {
231     if (const_cast<const ImplType&>(mpImplFont)->GetWidthTypeNoAsk() != eWidth)
232         mpImplFont->SetWidthType( eWidth );
233 }
234 
SetItalic(FontItalic eItalic)235 void Font::SetItalic( FontItalic eItalic )
236 {
237     if (const_cast<const ImplType&>(mpImplFont)->GetItalicNoAsk() != eItalic)
238         mpImplFont->SetItalic( eItalic );
239 }
240 
SetOutline(bool bOutline)241 void Font::SetOutline( bool bOutline )
242 {
243     if (const_cast<const ImplType&>(mpImplFont)->mbOutline != bOutline)
244         mpImplFont->mbOutline = bOutline;
245 }
246 
SetShadow(bool bShadow)247 void Font::SetShadow( bool bShadow )
248 {
249     if (const_cast<const ImplType&>(mpImplFont)->mbShadow != bShadow)
250         mpImplFont->mbShadow = bShadow;
251 }
252 
SetUnderline(FontLineStyle eUnderline)253 void Font::SetUnderline( FontLineStyle eUnderline )
254 {
255     if (const_cast<const ImplType&>(mpImplFont)->meUnderline != eUnderline)
256         mpImplFont->meUnderline = eUnderline;
257 }
258 
SetOverline(FontLineStyle eOverline)259 void Font::SetOverline( FontLineStyle eOverline )
260 {
261     if (const_cast<const ImplType&>(mpImplFont)->meOverline != eOverline)
262         mpImplFont->meOverline = eOverline;
263 }
264 
SetStrikeout(FontStrikeout eStrikeout)265 void Font::SetStrikeout( FontStrikeout eStrikeout )
266 {
267     if (const_cast<const ImplType&>(mpImplFont)->meStrikeout != eStrikeout)
268         mpImplFont->meStrikeout = eStrikeout;
269 }
270 
SetRelief(FontRelief eRelief)271 void Font::SetRelief( FontRelief eRelief )
272 {
273     if (const_cast<const ImplType&>(mpImplFont)->meRelief != eRelief)
274         mpImplFont->meRelief = eRelief;
275 }
276 
SetEmphasisMark(FontEmphasisMark eEmphasisMark)277 void Font::SetEmphasisMark( FontEmphasisMark eEmphasisMark )
278 {
279     if (const_cast<const ImplType&>(mpImplFont)->meEmphasisMark != eEmphasisMark )
280         mpImplFont->meEmphasisMark = eEmphasisMark;
281 }
282 
SetWordLineMode(bool bWordLine)283 void Font::SetWordLineMode( bool bWordLine )
284 {
285     if (const_cast<const ImplType&>(mpImplFont)->mbWordLine != bWordLine)
286         mpImplFont->mbWordLine = bWordLine;
287 }
288 
operator =(const vcl::Font & rFont)289 Font& Font::operator=( const vcl::Font& rFont )
290 {
291     mpImplFont = rFont.mpImplFont;
292     return *this;
293 }
294 
operator =(vcl::Font && rFont)295 Font& Font::operator=( vcl::Font&& rFont ) noexcept
296 {
297     mpImplFont = std::move(rFont.mpImplFont);
298     return *this;
299 }
300 
operator ==(const vcl::Font & rFont) const301 bool Font::operator==( const vcl::Font& rFont ) const
302 {
303     return mpImplFont == rFont.mpImplFont;
304 }
305 
Merge(const vcl::Font & rFont)306 void Font::Merge( const vcl::Font& rFont )
307 {
308     if ( !rFont.GetFamilyName().isEmpty() )
309     {
310         SetFamilyName( rFont.GetFamilyName() );
311         SetStyleName( rFont.GetStyleName() );
312         SetCharSet( GetCharSet() );
313         SetLanguageTag( rFont.GetLanguageTag() );
314         SetCJKContextLanguageTag( rFont.GetCJKContextLanguageTag() );
315         // don't use access methods here, might lead to AskConfig(), if DONTKNOW
316         SetFamily( rFont.mpImplFont->GetFamilyTypeNoAsk() );
317         SetPitch( rFont.mpImplFont->GetPitchNoAsk() );
318     }
319 
320     // don't use access methods here, might lead to AskConfig(), if DONTKNOW
321     if ( rFont.mpImplFont->GetWeightNoAsk() != WEIGHT_DONTKNOW )
322         SetWeight( rFont.GetWeight() );
323     if ( rFont.mpImplFont->GetItalicNoAsk() != ITALIC_DONTKNOW )
324         SetItalic( rFont.GetItalic() );
325     if ( rFont.mpImplFont->GetWidthTypeNoAsk() != WIDTH_DONTKNOW )
326         SetWidthType( rFont.GetWidthType() );
327 
328     if ( rFont.GetFontSize().Height() )
329         SetFontSize( rFont.GetFontSize() );
330     if ( rFont.GetUnderline() != LINESTYLE_DONTKNOW )
331     {
332         SetUnderline( rFont.GetUnderline() );
333         SetWordLineMode( rFont.IsWordLineMode() );
334     }
335     if ( rFont.GetOverline() != LINESTYLE_DONTKNOW )
336     {
337         SetOverline( rFont.GetOverline() );
338         SetWordLineMode( rFont.IsWordLineMode() );
339     }
340     if ( rFont.GetStrikeout() != STRIKEOUT_DONTKNOW )
341     {
342         SetStrikeout( rFont.GetStrikeout() );
343         SetWordLineMode( rFont.IsWordLineMode() );
344     }
345 
346     // Defaults?
347     SetOrientation( rFont.GetOrientation() );
348     SetVertical( rFont.IsVertical() );
349     SetEmphasisMark( rFont.GetEmphasisMark() );
350     SetKerning( rFont.IsKerning() ? FontKerning::FontSpecific : FontKerning::NONE );
351     SetOutline( rFont.IsOutline() );
352     SetShadow( rFont.IsShadow() );
353     SetRelief( rFont.GetRelief() );
354 }
355 
GetFontAttributes(FontAttributes & rAttrs) const356 void Font::GetFontAttributes( FontAttributes& rAttrs ) const
357 {
358     rAttrs.SetFamilyName( mpImplFont->GetFamilyName() );
359     rAttrs.SetStyleName( mpImplFont->maStyleName );
360     rAttrs.SetFamilyType( mpImplFont->GetFamilyTypeNoAsk() );
361     rAttrs.SetPitch( mpImplFont->GetPitchNoAsk() );
362     rAttrs.SetItalic( mpImplFont->GetItalicNoAsk() );
363     rAttrs.SetWeight( mpImplFont->GetWeightNoAsk() );
364     rAttrs.SetWidthType( WIDTH_DONTKNOW );
365     rAttrs.SetSymbolFlag( mpImplFont->GetCharSet() == RTL_TEXTENCODING_SYMBOL );
366 }
367 
368 // tdf#127471 for corrections on EMF/WMF we need the AvgFontWidth in Windows-specific notation
GetOrCalculateAverageFontWidth() const369 tools::Long Font::GetOrCalculateAverageFontWidth() const
370 {
371     if(0 == mpImplFont->GetCalculatedAverageFontWidth())
372     {
373         // VirtualDevice is not thread safe
374         SolarMutexGuard aGuard;
375 
376         // create unscaled copy of font (this), a VirtualDevice and set it there
377         vcl::Font aUnscaledFont(*this);
378         ScopedVclPtr<VirtualDevice> pTempVirtualDevice(VclPtr<VirtualDevice>::Create());
379         aUnscaledFont.SetAverageFontWidth(0);
380         pTempVirtualDevice->SetFont(aUnscaledFont);
381 
382 #ifdef _WIN32
383         // on Windows systems use FontMetric to get/create AverageFontWidth from system
384         const FontMetric aMetric(pTempVirtualDevice->GetFontMetric());
385         const_cast<Font*>(this)->mpImplFont->SetCalculatedAverageFontWidth(aMetric.GetAverageFontWidth());
386 #else
387         // On non-Windows systems we need to calculate AvgFontWidth
388         // as close as possible (discussion see documentation in task),
389         // so calculate it. For discussion of method used, see task
390         // buffer measure string creation, will always use the same
391         static constexpr OUStringLiteral aMeasureString
392             = u"\u0020\u0021\u0022\u0023\u0024\u0025\u0026\u0027"
393                "\u0028\u0029\u002A\u002B\u002C\u002D\u002E\u002F"
394                "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037"
395                "\u0038\u0039\u003A\u003B\u003C\u003D\u003E\u003F"
396                "\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047"
397                "\u0048\u0049\u004A\u004B\u004C\u004D\u004E\u004F"
398                "\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057"
399                "\u0058\u0059\u005A\u005B\u005C\u005D\u005E\u005F"
400                "\u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067"
401                "\u0068\u0069\u006A\u006B\u006C\u006D\u006E\u006F"
402                "\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077"
403                "\u0078\u0079\u007A\u007B\u007C\u007D\u007E";
404 
405         const double fAverageFontWidth(
406             pTempVirtualDevice->GetTextWidth(aMeasureString) /
407             static_cast<double>(aMeasureString.getLength()));
408         const_cast<Font*>(this)->mpImplFont->SetCalculatedAverageFontWidth(basegfx::fround(fAverageFontWidth));
409 #endif
410     }
411 
412     return mpImplFont->GetCalculatedAverageFontWidth();
413 }
414 
ReadImplFont(SvStream & rIStm,ImplFont & rImplFont,tools::Long & rnNormedFontScaling)415 SvStream& ReadImplFont( SvStream& rIStm, ImplFont& rImplFont, tools::Long& rnNormedFontScaling )
416 {
417     VersionCompatRead aCompat( rIStm );
418     sal_uInt16      nTmp16(0);
419     sal_Int16       nTmps16(0);
420     bool            bTmp(false);
421     sal_uInt8       nTmp8(0);
422 
423     rImplFont.SetFamilyName( rIStm.ReadUniOrByteString(rIStm.GetStreamCharSet()) );
424     rImplFont.maStyleName = rIStm.ReadUniOrByteString(rIStm.GetStreamCharSet());
425     TypeSerializer aSerializer(rIStm);
426     aSerializer.readSize(rImplFont.maAverageFontSize);
427 
428     rIStm.ReadUInt16( nTmp16 ); rImplFont.SetCharSet( static_cast<rtl_TextEncoding>(nTmp16) );
429     rIStm.ReadUInt16( nTmp16 ); rImplFont.SetFamilyType( static_cast<FontFamily>(nTmp16) );
430     rIStm.ReadUInt16( nTmp16 ); rImplFont.SetPitch( static_cast<FontPitch>(nTmp16) );
431     rIStm.ReadUInt16( nTmp16 ); rImplFont.SetWeight( static_cast<FontWeight>(nTmp16) );
432     rIStm.ReadUInt16( nTmp16 ); rImplFont.meUnderline = static_cast<FontLineStyle>(nTmp16);
433     rIStm.ReadUInt16( nTmp16 ); rImplFont.meStrikeout = static_cast<FontStrikeout>(nTmp16);
434     rIStm.ReadUInt16( nTmp16 ); rImplFont.SetItalic( static_cast<FontItalic>(nTmp16) );
435     rIStm.ReadUInt16( nTmp16 ); rImplFont.maLanguageTag.reset( LanguageType(nTmp16) );
436     rIStm.ReadUInt16( nTmp16 ); rImplFont.meWidthType = static_cast<FontWidth>(nTmp16);
437 
438     rIStm.ReadInt16( nTmps16 ); rImplFont.mnOrientation = Degree10(nTmps16);
439 
440     rIStm.ReadCharAsBool( bTmp ); rImplFont.mbWordLine = bTmp;
441     rIStm.ReadCharAsBool( bTmp ); rImplFont.mbOutline = bTmp;
442     rIStm.ReadCharAsBool( bTmp ); rImplFont.mbShadow = bTmp;
443     rIStm.ReadUChar( nTmp8 ); rImplFont.meKerning = static_cast<FontKerning>(nTmp8);
444 
445     if( aCompat.GetVersion() >= 2 )
446     {
447         rIStm.ReadUChar( nTmp8 );     rImplFont.meRelief = static_cast<FontRelief>(nTmp8);
448         rIStm.ReadUInt16( nTmp16 );   rImplFont.maCJKLanguageTag.reset( LanguageType(nTmp16) );
449         rIStm.ReadCharAsBool( bTmp ); rImplFont.mbVertical = bTmp;
450         rIStm.ReadUInt16( nTmp16 );   rImplFont.meEmphasisMark = static_cast<FontEmphasisMark>(nTmp16);
451     }
452 
453     if( aCompat.GetVersion() >= 3 )
454     {
455         rIStm.ReadUInt16( nTmp16 ); rImplFont.meOverline = static_cast<FontLineStyle>(nTmp16);
456     }
457 
458     // tdf#127471 read NormedFontScaling
459     if( aCompat.GetVersion() >= 4 )
460     {
461         sal_Int32 nNormedFontScaling(0);
462         rIStm.ReadInt32(nNormedFontScaling);
463         rnNormedFontScaling = nNormedFontScaling;
464     }
465 
466     // Relief
467     // CJKContextLanguage
468 
469     return rIStm;
470 }
471 
WriteImplFont(SvStream & rOStm,const ImplFont & rImplFont,const tools::Long & rnNormedFontScaling)472 SvStream& WriteImplFont( SvStream& rOStm, const ImplFont& rImplFont, const tools::Long& rnNormedFontScaling )
473 {
474     // tdf#127471 increase to version 4
475     VersionCompatWrite aCompat( rOStm, 4 );
476 
477     TypeSerializer aSerializer(rOStm);
478     rOStm.WriteUniOrByteString( rImplFont.GetFamilyName(), rOStm.GetStreamCharSet() );
479     rOStm.WriteUniOrByteString( rImplFont.GetStyleName(), rOStm.GetStreamCharSet() );
480     aSerializer.writeSize(rImplFont.maAverageFontSize);
481 
482     rOStm.WriteUInt16( GetStoreCharSet( rImplFont.GetCharSet() ) );
483     rOStm.WriteUInt16( rImplFont.GetFamilyTypeNoAsk() );
484     rOStm.WriteUInt16( rImplFont.GetPitchNoAsk() );
485     rOStm.WriteUInt16( rImplFont.GetWeightNoAsk() );
486     rOStm.WriteUInt16( rImplFont.meUnderline );
487     rOStm.WriteUInt16( rImplFont.meStrikeout );
488     rOStm.WriteUInt16( rImplFont.GetItalicNoAsk() );
489     rOStm.WriteUInt16( static_cast<sal_uInt16>(rImplFont.maLanguageTag.getLanguageType( false)) );
490     rOStm.WriteUInt16( rImplFont.GetWidthTypeNoAsk() );
491 
492     rOStm.WriteInt16( rImplFont.mnOrientation.get() );
493 
494     rOStm.WriteBool( rImplFont.mbWordLine );
495     rOStm.WriteBool( rImplFont.mbOutline );
496     rOStm.WriteBool( rImplFont.mbShadow );
497     rOStm.WriteUChar( static_cast<sal_uInt8>(rImplFont.meKerning) );
498 
499     // new in version 2
500     rOStm.WriteUChar( static_cast<unsigned char>(rImplFont.meRelief) );
501     rOStm.WriteUInt16( static_cast<sal_uInt16>(rImplFont.maCJKLanguageTag.getLanguageType( false)) );
502     rOStm.WriteBool( rImplFont.mbVertical );
503     rOStm.WriteUInt16( static_cast<sal_uInt16>(rImplFont.meEmphasisMark) );
504 
505     // new in version 3
506     rOStm.WriteUInt16( rImplFont.meOverline );
507 
508     // new in version 4, NormedFontScaling
509     rOStm.WriteInt32(rnNormedFontScaling);
510 
511     return rOStm;
512 }
513 
ReadFont(SvStream & rIStm,vcl::Font & rFont)514 SvStream& ReadFont( SvStream& rIStm, vcl::Font& rFont )
515 {
516     // tdf#127471 try to read NormedFontScaling
517     tools::Long nNormedFontScaling(0);
518     SvStream& rRetval(ReadImplFont( rIStm, *rFont.mpImplFont, nNormedFontScaling ));
519 
520     if (nNormedFontScaling > 0)
521     {
522 #ifdef _WIN32
523         // we run on windows and a NormedFontScaling was written
524         if(rFont.GetFontSize().getWidth() == nNormedFontScaling)
525         {
526             // the writing producer was running on a non-windows system, adapt to needed windows
527             // system-specific pre-multiply
528             const tools::Long nHeight(std::max<tools::Long>(rFont.GetFontSize().getHeight(), 0));
529             sal_uInt32 nScaledWidth(0);
530 
531             if(nHeight > 0)
532             {
533                 vcl::Font aUnscaledFont(rFont);
534                 aUnscaledFont.SetAverageFontWidth(0);
535                 const FontMetric aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aUnscaledFont));
536 
537                 if (nHeight > 0)
538                 {
539                     const double fScaleFactor(static_cast<double>(nNormedFontScaling) / static_cast<double>(nHeight));
540                     nScaledWidth = basegfx::fround(static_cast<double>(aUnscaledFontMetric.GetAverageFontWidth()) * fScaleFactor);
541                 }
542             }
543 
544             rFont.SetAverageFontWidth(nScaledWidth);
545         }
546         else
547         {
548             // the writing producer was on a windows system, correct pre-multiplied value
549             // is already set, nothing to do. Ignore 2nd value. Here a check
550             // could be done if adapting the 2nd, NormedFontScaling value would be similar to
551             // the set value for plausibility reasons
552         }
553 #else
554         // we do not run on windows and a NormedFontScaling was written
555         if(rFont.GetFontSize().getWidth() == nNormedFontScaling)
556         {
557             // the writing producer was not on a windows system, correct value
558             // already set, nothing to do
559         }
560         else
561         {
562             // the writing producer was on a windows system, correct FontScaling.
563             // The correct non-pre-multiplied value is the 2nd one, use it
564             rFont.SetAverageFontWidth(nNormedFontScaling);
565         }
566 #endif
567     }
568 
569     return rRetval;
570 }
571 
WriteFont(SvStream & rOStm,const vcl::Font & rFont)572 SvStream& WriteFont( SvStream& rOStm, const vcl::Font& rFont )
573 {
574     // tdf#127471 prepare NormedFontScaling for additional export
575     tools::Long nNormedFontScaling(rFont.GetFontSize().getWidth());
576 
577     // FontScaling usage at vcl-Font is detected by checking that FontWidth != 0
578     if (nNormedFontScaling > 0)
579     {
580         const tools::Long nHeight(std::max<tools::Long>(rFont.GetFontSize().getHeight(), 0));
581 
582         // check for negative height
583         if(0 == nHeight)
584         {
585             nNormedFontScaling = 0;
586         }
587         else
588         {
589 #ifdef _WIN32
590             // for WIN32 the value is pre-multiplied with AverageFontWidth
591             // which makes it system-dependent. Turn that back to have the
592             // normed non-windows form of it for export as 2nd value
593             vcl::Font aUnscaledFont(rFont);
594             aUnscaledFont.SetAverageFontWidth(0);
595             const FontMetric aUnscaledFontMetric(
596                 Application::GetDefaultDevice()->GetFontMetric(aUnscaledFont));
597 
598             if (aUnscaledFontMetric.GetAverageFontWidth() > 0)
599             {
600                 const double fScaleFactor(
601                     static_cast<double>(nNormedFontScaling)
602                     / static_cast<double>(aUnscaledFontMetric.GetAverageFontWidth()));
603                 nNormedFontScaling = static_cast<tools::Long>(fScaleFactor * nHeight);
604             }
605 #endif
606         }
607     }
608 
609     return WriteImplFont( rOStm, *rFont.mpImplFont, nNormedFontScaling );
610 }
611 
612 namespace
613 {
identifyTrueTypeFont(const void * i_pBuffer,sal_uInt32 i_nSize,Font & o_rResult)614     bool identifyTrueTypeFont( const void* i_pBuffer, sal_uInt32 i_nSize, Font& o_rResult )
615     {
616         bool bResult = false;
617         TrueTypeFont* pTTF = nullptr;
618         if( OpenTTFontBuffer( i_pBuffer, i_nSize, 0, &pTTF ) == SFErrCodes::Ok )
619         {
620             TTGlobalFontInfo aInfo;
621             GetTTGlobalFontInfo( pTTF, &aInfo );
622             // most importantly: the family name
623             if( aInfo.ufamily )
624                 o_rResult.SetFamilyName( OUString(aInfo.ufamily) );
625             else if( aInfo.family )
626                 o_rResult.SetFamilyName( OStringToOUString( aInfo.family, RTL_TEXTENCODING_ASCII_US ) );
627             // set weight
628             if( aInfo.weight )
629             {
630                 if( aInfo.weight < FW_EXTRALIGHT )
631                     o_rResult.SetWeight( WEIGHT_THIN );
632                 else if( aInfo.weight < FW_LIGHT )
633                     o_rResult.SetWeight( WEIGHT_ULTRALIGHT );
634                 else if( aInfo.weight < FW_NORMAL )
635                     o_rResult.SetWeight( WEIGHT_LIGHT );
636                 else if( aInfo.weight < FW_MEDIUM )
637                     o_rResult.SetWeight( WEIGHT_NORMAL );
638                 else if( aInfo.weight < FW_SEMIBOLD )
639                     o_rResult.SetWeight( WEIGHT_MEDIUM );
640                 else if( aInfo.weight < FW_BOLD )
641                     o_rResult.SetWeight( WEIGHT_SEMIBOLD );
642                 else if( aInfo.weight < FW_EXTRABOLD )
643                     o_rResult.SetWeight( WEIGHT_BOLD );
644                 else if( aInfo.weight < FW_BLACK )
645                     o_rResult.SetWeight( WEIGHT_ULTRABOLD );
646                 else
647                     o_rResult.SetWeight( WEIGHT_BLACK );
648             }
649             else
650                 o_rResult.SetWeight( (aInfo.macStyle & 1) ? WEIGHT_BOLD : WEIGHT_NORMAL );
651             // set width
652             if( aInfo.width )
653             {
654                 if( aInfo.width == FWIDTH_ULTRA_CONDENSED )
655                     o_rResult.SetAverageFontWidth( WIDTH_ULTRA_CONDENSED );
656                 else if( aInfo.width == FWIDTH_EXTRA_CONDENSED )
657                     o_rResult.SetAverageFontWidth( WIDTH_EXTRA_CONDENSED );
658                 else if( aInfo.width == FWIDTH_CONDENSED )
659                     o_rResult.SetAverageFontWidth( WIDTH_CONDENSED );
660                 else if( aInfo.width == FWIDTH_SEMI_CONDENSED )
661                     o_rResult.SetAverageFontWidth( WIDTH_SEMI_CONDENSED );
662                 else if( aInfo.width == FWIDTH_NORMAL )
663                     o_rResult.SetAverageFontWidth( WIDTH_NORMAL );
664                 else if( aInfo.width == FWIDTH_SEMI_EXPANDED )
665                     o_rResult.SetAverageFontWidth( WIDTH_SEMI_EXPANDED );
666                 else if( aInfo.width == FWIDTH_EXPANDED )
667                     o_rResult.SetAverageFontWidth( WIDTH_EXPANDED );
668                 else if( aInfo.width == FWIDTH_EXTRA_EXPANDED )
669                     o_rResult.SetAverageFontWidth( WIDTH_EXTRA_EXPANDED );
670                 else if( aInfo.width >= FWIDTH_ULTRA_EXPANDED )
671                     o_rResult.SetAverageFontWidth( WIDTH_ULTRA_EXPANDED );
672             }
673             // set italic
674             o_rResult.SetItalic( (aInfo.italicAngle != 0) ? ITALIC_NORMAL : ITALIC_NONE );
675 
676             // set pitch
677             o_rResult.SetPitch( (aInfo.pitch == 0) ? PITCH_VARIABLE : PITCH_FIXED );
678 
679             // set style name
680             if( aInfo.usubfamily )
681                 o_rResult.SetStyleName( OUString( aInfo.usubfamily ) );
682             else if( aInfo.subfamily )
683                 o_rResult.SetStyleName( OUString::createFromAscii( aInfo.subfamily ) );
684 
685             // cleanup
686             CloseTTFont( pTTF );
687             // success
688             bResult = true;
689         }
690         return bResult;
691     }
692 
693     struct WeightSearchEntry
694     {
695         const char* string;
696         int         string_len;
697         FontWeight  weight;
698 
operator <__anon8415ccdf0211::WeightSearchEntry699         bool operator<( const WeightSearchEntry& rRight ) const
700         {
701             return rtl_str_compareIgnoreAsciiCase_WithLength( string, string_len, rRight.string, rRight.string_len ) < 0;
702         }
703     }
704     const weight_table[] =
705     {
706         { "black", 5, WEIGHT_BLACK },
707         { "bold", 4, WEIGHT_BOLD },
708         { "book", 4, WEIGHT_LIGHT },
709         { "demi", 4, WEIGHT_SEMIBOLD },
710         { "heavy", 5, WEIGHT_BLACK },
711         { "light", 5, WEIGHT_LIGHT },
712         { "medium", 6, WEIGHT_MEDIUM },
713         { "regular", 7, WEIGHT_NORMAL },
714         { "super", 5, WEIGHT_ULTRABOLD },
715         { "thin", 4, WEIGHT_THIN }
716     };
717 
identifyType1Font(const char * i_pBuffer,sal_uInt32 i_nSize,Font & o_rResult)718     bool identifyType1Font( const char* i_pBuffer, sal_uInt32 i_nSize, Font& o_rResult )
719     {
720         // might be a type1, find eexec
721         const char* pStream = i_pBuffer;
722         const char* const pExec = "eexec";
723         const char* pExecPos = std::search( pStream, pStream+i_nSize, pExec, pExec+5 );
724         if( pExecPos != pStream+i_nSize)
725         {
726             // find /FamilyName entry
727             static const char* const pFam = "/FamilyName";
728             const char* pFamPos = std::search( pStream, pExecPos, pFam, pFam+11 );
729             if( pFamPos != pExecPos )
730             {
731                 // extract the string value behind /FamilyName
732                 const char* pOpen = pFamPos+11;
733                 while( pOpen < pExecPos && *pOpen != '(' )
734                     pOpen++;
735                 const char* pClose = pOpen;
736                 while( pClose < pExecPos && *pClose != ')' )
737                     pClose++;
738                 if( pClose - pOpen > 1 )
739                 {
740                     o_rResult.SetFamilyName( OStringToOUString( std::string_view( pOpen+1, pClose-pOpen-1 ), RTL_TEXTENCODING_ASCII_US ) );
741                 }
742             }
743 
744             // parse /ItalicAngle
745             static const char* const pItalic = "/ItalicAngle";
746             const char* pItalicPos = std::search( pStream, pExecPos, pItalic, pItalic+12 );
747             if( pItalicPos != pExecPos )
748             {
749                 const char* pItalicEnd = pItalicPos + 12;
750                 auto nItalic = rtl_str_toInt64_WithLength(pItalicEnd, 10, pExecPos - pItalicEnd);
751                 o_rResult.SetItalic( (nItalic != 0) ? ITALIC_NORMAL : ITALIC_NONE );
752             }
753 
754             // parse /Weight
755             static const char* const pWeight = "/Weight";
756             const char* pWeightPos = std::search( pStream, pExecPos, pWeight, pWeight+7 );
757             if( pWeightPos != pExecPos )
758             {
759                 // extract the string value behind /Weight
760                 const char* pOpen = pWeightPos+7;
761                 while( pOpen < pExecPos && *pOpen != '(' )
762                     pOpen++;
763                 const char* pClose = pOpen;
764                 while( pClose < pExecPos && *pClose != ')' )
765                     pClose++;
766                 if( pClose - pOpen > 1 )
767                 {
768                     WeightSearchEntry aEnt;
769                     aEnt.string = pOpen+1;
770                     aEnt.string_len = (pClose-pOpen)-1;
771                     aEnt.weight = WEIGHT_NORMAL;
772                     WeightSearchEntry const * pFound = std::lower_bound( std::begin(weight_table), std::end(weight_table), aEnt );
773                     if( pFound != std::end(weight_table) &&
774                         rtl_str_compareIgnoreAsciiCase_WithLength( pFound->string, pFound->string_len, aEnt.string, aEnt.string_len) == 0 )
775                         o_rResult.SetWeight( pFound->weight );
776                 }
777             }
778 
779             // parse isFixedPitch
780             static const char* const pFixed = "/isFixedPitch";
781             const char* pFixedPos = std::search( pStream, pExecPos, pFixed, pFixed+13 );
782             if( pFixedPos != pExecPos )
783             {
784                 // skip whitespace
785                 while( pFixedPos < pExecPos-4 &&
786                        ( *pFixedPos == ' '  ||
787                          *pFixedPos == '\t' ||
788                          *pFixedPos == '\r' ||
789                          *pFixedPos == '\n' ) )
790                 {
791                     pFixedPos++;
792                 }
793                 // find "true" value
794                 if( rtl_str_compareIgnoreAsciiCase_WithLength( pFixedPos, 4, "true", 4 ) == 0 )
795                     o_rResult.SetPitch( PITCH_FIXED );
796                 else
797                     o_rResult.SetPitch( PITCH_VARIABLE );
798             }
799         }
800         return false;
801     }
802 }
803 
identifyFont(const void * i_pBuffer,sal_uInt32 i_nSize)804 Font Font::identifyFont( const void* i_pBuffer, sal_uInt32 i_nSize )
805 {
806     Font aResult;
807     if( ! identifyTrueTypeFont( i_pBuffer, i_nSize, aResult ) )
808     {
809         const char* pStream = static_cast<const char*>(i_pBuffer);
810         if( pStream && i_nSize > 100 &&
811              *pStream == '%' && pStream[1] == '!' )
812         {
813             identifyType1Font( pStream, i_nSize, aResult );
814         }
815     }
816 
817     return aResult;
818 }
819 
820 // The inlines from the font.hxx header are now instantiated for pImpl-ification
GetColor() const821 const Color& Font::GetColor() const { return mpImplFont->maColor; }
GetFillColor() const822 const Color& Font::GetFillColor() const { return mpImplFont->maFillColor; }
IsTransparent() const823 bool Font::IsTransparent() const { return mpImplFont->mbTransparent; }
824 
GetAlignment() const825 FontAlign Font::GetAlignment() const { return mpImplFont->GetAlignment(); }
826 
GetFamilyName() const827 const OUString& Font::GetFamilyName() const { return mpImplFont->GetFamilyName(); }
GetStyleName() const828 const OUString& Font::GetStyleName() const { return mpImplFont->maStyleName; }
829 
GetFontSize() const830 const Size& Font::GetFontSize() const { return mpImplFont->GetFontSize(); }
SetFontHeight(tools::Long nHeight)831 void Font::SetFontHeight( tools::Long nHeight ) { SetFontSize( Size( mpImplFont->GetFontSize().Width(), nHeight ) ); }
GetFontHeight() const832 tools::Long Font::GetFontHeight() const { return mpImplFont->GetFontSize().Height(); }
SetAverageFontWidth(tools::Long nWidth)833 void Font::SetAverageFontWidth( tools::Long nWidth ) { SetFontSize( Size( nWidth, mpImplFont->GetFontSize().Height() ) ); }
GetAverageFontWidth() const834 tools::Long Font::GetAverageFontWidth() const { return mpImplFont->GetFontSize().Width(); }
835 
GetCharSet() const836 rtl_TextEncoding Font::GetCharSet() const { return mpImplFont->GetCharSet(); }
837 
GetLanguageTag() const838 const LanguageTag& Font::GetLanguageTag() const { return mpImplFont->maLanguageTag; }
GetCJKContextLanguageTag() const839 const LanguageTag& Font::GetCJKContextLanguageTag() const { return mpImplFont->maCJKLanguageTag; }
GetLanguage() const840 LanguageType Font::GetLanguage() const { return mpImplFont->maLanguageTag.getLanguageType( false); }
GetCJKContextLanguage() const841 LanguageType Font::GetCJKContextLanguage() const { return mpImplFont->maCJKLanguageTag.getLanguageType( false); }
842 
GetOrientation() const843 Degree10 Font::GetOrientation() const { return mpImplFont->mnOrientation; }
IsVertical() const844 bool Font::IsVertical() const { return mpImplFont->mbVertical; }
GetKerning() const845 FontKerning Font::GetKerning() const { return mpImplFont->meKerning; }
846 
GetPitch()847 FontPitch Font::GetPitch() { return mpImplFont->GetPitch(); }
GetWeight()848 FontWeight Font::GetWeight() { return mpImplFont->GetWeight(); }
GetWidthType()849 FontWidth Font::GetWidthType() { return mpImplFont->GetWidthType(); }
GetItalic()850 FontItalic Font::GetItalic() { return mpImplFont->GetItalic(); }
GetFamilyType()851 FontFamily Font::GetFamilyType() { return mpImplFont->GetFamilyType(); }
852 
GetPitch() const853 FontPitch Font::GetPitch() const { return mpImplFont->GetPitchNoAsk(); }
GetWeight() const854 FontWeight Font::GetWeight() const { return mpImplFont->GetWeightNoAsk(); }
GetWidthType() const855 FontWidth Font::GetWidthType() const { return mpImplFont->GetWidthTypeNoAsk(); }
GetItalic() const856 FontItalic Font::GetItalic() const { return mpImplFont->GetItalicNoAsk(); }
GetFamilyType() const857 FontFamily Font::GetFamilyType() const { return mpImplFont->GetFamilyTypeNoAsk(); }
858 
GetQuality() const859 int Font::GetQuality() const { return mpImplFont->GetQuality(); }
SetQuality(int nQuality)860 void Font::SetQuality( int nQuality ) { mpImplFont->SetQuality( nQuality ); }
IncreaseQualityBy(int nQualityAmount)861 void Font::IncreaseQualityBy( int nQualityAmount ) { mpImplFont->IncreaseQualityBy( nQualityAmount ); }
DecreaseQualityBy(int nQualityAmount)862 void Font::DecreaseQualityBy( int nQualityAmount ) { mpImplFont->DecreaseQualityBy( nQualityAmount ); }
863 
IsOutline() const864 bool Font::IsOutline() const { return mpImplFont->mbOutline; }
IsShadow() const865 bool Font::IsShadow() const { return mpImplFont->mbShadow; }
GetRelief() const866 FontRelief Font::GetRelief() const { return mpImplFont->meRelief; }
GetUnderline() const867 FontLineStyle Font::GetUnderline() const { return mpImplFont->meUnderline; }
GetOverline() const868 FontLineStyle Font::GetOverline()  const { return mpImplFont->meOverline; }
GetStrikeout() const869 FontStrikeout Font::GetStrikeout() const { return mpImplFont->meStrikeout; }
GetEmphasisMark() const870 FontEmphasisMark Font::GetEmphasisMark() const { return mpImplFont->meEmphasisMark; }
IsWordLineMode() const871 bool Font::IsWordLineMode() const { return mpImplFont->mbWordLine; }
IsSameInstance(const vcl::Font & rFont) const872 bool Font::IsSameInstance( const vcl::Font& rFont ) const { return (mpImplFont == rFont.mpImplFont); }
873 
874 
ImplFont()875 ImplFont::ImplFont() :
876     meWeight( WEIGHT_DONTKNOW ),
877     meFamily( FAMILY_DONTKNOW ),
878     mePitch( PITCH_DONTKNOW ),
879     meWidthType( WIDTH_DONTKNOW ),
880     meItalic( ITALIC_NONE ),
881     meAlign( ALIGN_TOP ),
882     meUnderline( LINESTYLE_NONE ),
883     meOverline( LINESTYLE_NONE ),
884     meStrikeout( STRIKEOUT_NONE ),
885     meRelief( FontRelief::NONE ),
886     meEmphasisMark( FontEmphasisMark::NONE ),
887     meKerning( FontKerning::FontSpecific ),
888     meCharSet( RTL_TEXTENCODING_DONTKNOW ),
889     maLanguageTag( LANGUAGE_DONTKNOW ),
890     maCJKLanguageTag( LANGUAGE_DONTKNOW ),
891     mbSymbolFlag( false ),
892     mbOutline( false ),
893     mbConfigLookup( false ),
894     mbShadow( false ),
895     mbVertical( false ),
896     mbTransparent( true ),
897     maColor( COL_TRANSPARENT ),
898     maFillColor( COL_TRANSPARENT ),
899     mbWordLine( false ),
900     mnOrientation( 0 ),
901     mnQuality( 0 ),
902     mnCalculatedAverageFontWidth( 0 )
903 {}
904 
ImplFont(const ImplFont & rImplFont)905 ImplFont::ImplFont( const ImplFont& rImplFont ) :
906     maFamilyName( rImplFont.maFamilyName ),
907     maStyleName( rImplFont.maStyleName ),
908     meWeight( rImplFont.meWeight ),
909     meFamily( rImplFont.meFamily ),
910     mePitch( rImplFont.mePitch ),
911     meWidthType( rImplFont.meWidthType ),
912     meItalic( rImplFont.meItalic ),
913     meAlign( rImplFont.meAlign ),
914     meUnderline( rImplFont.meUnderline ),
915     meOverline( rImplFont.meOverline ),
916     meStrikeout( rImplFont.meStrikeout ),
917     meRelief( rImplFont.meRelief ),
918     meEmphasisMark( rImplFont.meEmphasisMark ),
919     meKerning( rImplFont.meKerning ),
920     maAverageFontSize( rImplFont.maAverageFontSize ),
921     meCharSet( rImplFont.meCharSet ),
922     maLanguageTag( rImplFont.maLanguageTag ),
923     maCJKLanguageTag( rImplFont.maCJKLanguageTag ),
924     mbSymbolFlag( rImplFont.mbSymbolFlag ),
925     mbOutline( rImplFont.mbOutline ),
926     mbConfigLookup( rImplFont.mbConfigLookup ),
927     mbShadow( rImplFont.mbShadow ),
928     mbVertical( rImplFont.mbVertical ),
929     mbTransparent( rImplFont.mbTransparent ),
930     maColor( rImplFont.maColor ),
931     maFillColor( rImplFont.maFillColor ),
932     mbWordLine( rImplFont.mbWordLine ),
933     mnOrientation( rImplFont.mnOrientation ),
934     mnQuality( rImplFont.mnQuality ),
935     mnCalculatedAverageFontWidth( rImplFont.mnCalculatedAverageFontWidth )
936 {}
937 
operator ==(const ImplFont & rOther) const938 bool ImplFont::operator==( const ImplFont& rOther ) const
939 {
940     // equality tests split up for easier debugging
941     if( (meWeight   != rOther.meWeight)
942     ||  (meItalic   != rOther.meItalic)
943     ||  (meFamily   != rOther.meFamily)
944     ||  (mePitch    != rOther.mePitch) )
945         return false;
946 
947     if( (meCharSet        != rOther.meCharSet)
948     ||  (maLanguageTag    != rOther.maLanguageTag)
949     ||  (maCJKLanguageTag != rOther.maCJKLanguageTag)
950     ||  (meAlign          != rOther.meAlign) )
951         return false;
952 
953     if( (maAverageFontSize       != rOther.maAverageFontSize)
954     ||  (mnOrientation  != rOther.mnOrientation)
955     ||  (mbVertical     != rOther.mbVertical) )
956         return false;
957 
958     if( (maFamilyName   != rOther.maFamilyName)
959     ||  (maStyleName    != rOther.maStyleName) )
960         return false;
961 
962     if( (maColor        != rOther.maColor)
963     ||  (maFillColor    != rOther.maFillColor) )
964         return false;
965 
966     if( (meUnderline    != rOther.meUnderline)
967     ||  (meOverline     != rOther.meOverline)
968     ||  (meStrikeout    != rOther.meStrikeout)
969     ||  (meRelief       != rOther.meRelief)
970     ||  (meEmphasisMark != rOther.meEmphasisMark)
971     ||  (mbWordLine     != rOther.mbWordLine)
972     ||  (mbOutline      != rOther.mbOutline)
973     ||  (mbShadow       != rOther.mbShadow)
974     ||  (meKerning      != rOther.meKerning)
975     ||  (mbTransparent  != rOther.mbTransparent) )
976         return false;
977 
978     return true;
979 }
980 
AskConfig()981 void ImplFont::AskConfig()
982 {
983     if( mbConfigLookup )
984         return;
985 
986     mbConfigLookup = true;
987 
988     // prepare the FontSubst configuration lookup
989     const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get();
990 
991     OUString      aShortName;
992     OUString      aFamilyName;
993     ImplFontAttrs nType = ImplFontAttrs::None;
994     FontWeight  eWeight = WEIGHT_DONTKNOW;
995     FontWidth   eWidthType = WIDTH_DONTKNOW;
996     OUString    aMapName = GetEnglishSearchFontName( maFamilyName );
997 
998     utl::FontSubstConfiguration::getMapName( aMapName,
999         aShortName, aFamilyName, eWeight, eWidthType, nType );
1000 
1001     // lookup the font name in the configuration
1002     const utl::FontNameAttr* pFontAttr = rFontSubst.getSubstInfo( aMapName );
1003 
1004     // if the direct lookup failed try again with an alias name
1005     if ( !pFontAttr && (aShortName != aMapName) )
1006         pFontAttr = rFontSubst.getSubstInfo( aShortName );
1007 
1008     if( pFontAttr )
1009     {
1010         // the font was found in the configuration
1011         if( meFamily == FAMILY_DONTKNOW )
1012         {
1013             if ( pFontAttr->Type & ImplFontAttrs::Serif )
1014                 meFamily = FAMILY_ROMAN;
1015             else if ( pFontAttr->Type & ImplFontAttrs::SansSerif )
1016                 meFamily = FAMILY_SWISS;
1017             else if ( pFontAttr->Type & ImplFontAttrs::Typewriter )
1018                 meFamily = FAMILY_MODERN;
1019             else if ( pFontAttr->Type & ImplFontAttrs::Italic )
1020                 meFamily = FAMILY_SCRIPT;
1021             else if ( pFontAttr->Type & ImplFontAttrs::Decorative )
1022                 meFamily = FAMILY_DECORATIVE;
1023         }
1024 
1025         if( mePitch == PITCH_DONTKNOW )
1026         {
1027             if ( pFontAttr->Type & ImplFontAttrs::Fixed )
1028                 mePitch = PITCH_FIXED;
1029         }
1030     }
1031 
1032     // if some attributes are still unknown then use the FontSubst magic
1033     if( meFamily == FAMILY_DONTKNOW )
1034     {
1035         if( nType & ImplFontAttrs::Serif )
1036             meFamily = FAMILY_ROMAN;
1037         else if( nType & ImplFontAttrs::SansSerif )
1038             meFamily = FAMILY_SWISS;
1039         else if( nType & ImplFontAttrs::Typewriter )
1040             meFamily = FAMILY_MODERN;
1041         else if( nType & ImplFontAttrs::Italic )
1042             meFamily = FAMILY_SCRIPT;
1043         else if( nType & ImplFontAttrs::Decorative )
1044             meFamily = FAMILY_DECORATIVE;
1045     }
1046 
1047     if( GetWeight() == WEIGHT_DONTKNOW )
1048         SetWeight( eWeight );
1049     if( meWidthType == WIDTH_DONTKNOW )
1050         meWidthType = eWidthType;
1051 }
1052 
1053 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1054