Get the style color and number just once
[LibreOffice.git] / vcl / source / font / font.cxx
blobc47fb0bbac4d6a60cd06f402f9184a34ff02dcbf
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 <tools/stream.hxx>
21 #include <tools/vcompat.hxx>
22 #include <tools/gen.hxx>
23 #include <comphelper/configuration.hxx>
24 #include <unotools/fontcfg.hxx>
25 #include <unotools/fontdefs.hxx>
26 #include <o3tl/hash_combine.hxx>
27 #include <i18nlangtag/mslangid.hxx>
29 #include <vcl/font.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/outdev.hxx>
32 #include <vcl/virdev.hxx>
34 #include <impfont.hxx>
35 #include <fontattributes.hxx>
36 #include <fontsubset.hxx>
37 #include <sft.hxx>
39 #include <algorithm>
40 #include <string_view>
42 #include <vcl/TypeSerializer.hxx>
44 #ifdef _WIN32
45 #include <vcl/metric.hxx>
46 #endif
48 using namespace vcl;
50 namespace
52 Font::ImplType& GetGlobalDefault()
54 static Font::ImplType gDefault;
55 return gDefault;
59 Font::Font() : mpImplFont(GetGlobalDefault())
63 Font::Font( const vcl::Font& rFont ) : mpImplFont( rFont.mpImplFont )
67 Font::Font( vcl::Font&& rFont ) noexcept : mpImplFont( std::move(rFont.mpImplFont) )
71 Font::Font( const OUString& rFamilyName, const Size& rSize )
73 if (GetFamilyName() != rFamilyName
74 || GetAverageFontSize() != rSize)
76 auto impl = mpImplFont.get();
77 impl->SetFamilyName( rFamilyName );
78 impl->SetFontSize( rSize );
82 Font::Font( const OUString& rFamilyName, const OUString& rStyleName, const Size& rSize )
84 if (GetFamilyName() != rFamilyName
85 || GetStyleName() != rStyleName
86 || GetAverageFontSize() != rSize)
88 auto impl = mpImplFont.get();
89 impl->SetFamilyName( rFamilyName );
90 impl->SetStyleName( rStyleName );
91 impl->SetFontSize( rSize );
95 Font::Font( FontFamily eFamily, const Size& rSize )
97 if (GetFontFamily() != eFamily
98 || GetAverageFontSize() != rSize)
100 auto impl = mpImplFont.get();
101 impl->SetFamilyType( eFamily );
102 impl->SetFontSize( rSize );
106 Font::~Font()
110 void Font::SetColor( const Color& rColor )
112 if (GetColor() != rColor)
114 mpImplFont->maColor = rColor;
118 void Font::SetFillColor( const Color& rColor )
120 if (GetFillColor() != rColor)
122 auto impl = mpImplFont.get();
123 impl->maFillColor = rColor;
124 if ( rColor.IsTransparent() )
125 impl->mbTransparent = true;
129 void Font::SetTransparent( bool bTransparent )
131 if (IsTransparent() != bTransparent)
132 mpImplFont->mbTransparent = bTransparent;
135 void Font::SetAlignment( TextAlign eAlign )
137 if (GetAlignment() != eAlign)
138 mpImplFont->SetAlignment(eAlign);
141 void Font::SetFamilyName( const OUString& rFamilyName )
143 if (GetFamilyName() != rFamilyName)
144 mpImplFont->SetFamilyName( rFamilyName );
147 void Font::SetStyleName( const OUString& rStyleName )
149 if (GetStyleName() != rStyleName)
150 mpImplFont->maStyleName = rStyleName;
153 void Font::SetFontSize( const Size& rSize )
155 if (GetFontSize() != rSize)
156 mpImplFont->SetFontSize( rSize );
159 void Font::SetFamily( FontFamily eFamily )
161 if (std::as_const(mpImplFont)->GetFamilyTypeNoAsk() != eFamily)
162 mpImplFont->SetFamilyType( eFamily );
165 void Font::SetCharSet( rtl_TextEncoding eCharSet )
167 if (GetCharSet() != eCharSet)
168 mpImplFont->SetCharSet( eCharSet );
171 void Font::SetLanguageTag( const LanguageTag& rLanguageTag )
173 if (GetLanguageTag() != rLanguageTag)
174 mpImplFont->maLanguageTag = rLanguageTag;
177 void Font::SetCJKContextLanguageTag( const LanguageTag& rLanguageTag )
179 if (GetCJKContextLanguageTag() != rLanguageTag)
180 mpImplFont->maCJKLanguageTag = rLanguageTag;
183 void Font::SetLanguage( LanguageType eLanguage )
185 if (GetLanguage() != eLanguage)
186 mpImplFont->maLanguageTag.reset( eLanguage);
189 void Font::SetCJKContextLanguage( LanguageType eLanguage )
191 if (GetCJKContextLanguage() != eLanguage)
192 mpImplFont->maCJKLanguageTag.reset( eLanguage);
195 void Font::SetPitch( FontPitch ePitch )
197 if (std::as_const(mpImplFont)->GetPitchNoAsk() != ePitch)
198 mpImplFont->SetPitch( ePitch );
201 void Font::SetOrientation( Degree10 nOrientation )
203 if (GetOrientation() != nOrientation)
204 mpImplFont->mnOrientation = nOrientation;
207 void Font::SetVertical( bool bVertical )
209 if (IsVertical() != bVertical)
210 mpImplFont->mbVertical = bVertical;
213 void Font::SetKerning( FontKerning eKerning )
215 if (GetKerning() != eKerning)
216 mpImplFont->meKerning = eKerning;
219 bool Font::IsKerning() const
221 return mpImplFont->meKerning != FontKerning::NONE;
224 void Font::SetFixKerning( short nSpacing )
226 if (GetFixKerning() != nSpacing)
227 mpImplFont->mnSpacing = nSpacing;
230 short Font::GetFixKerning() const
232 return mpImplFont->mnSpacing;
235 bool Font::IsFixKerning() const
237 return mpImplFont->mnSpacing != 0;
240 void Font::SetWeight( FontWeight eWeight )
242 if (std::as_const(mpImplFont)->GetWeightNoAsk() != eWeight)
243 mpImplFont->SetWeight( eWeight );
246 void Font::SetWidthType( FontWidth eWidth )
248 if (std::as_const(mpImplFont)->GetWidthTypeNoAsk() != eWidth)
249 mpImplFont->SetWidthType( eWidth );
252 void Font::SetItalic( FontItalic eItalic )
254 if (std::as_const(mpImplFont)->GetItalicNoAsk() != eItalic)
255 mpImplFont->SetItalic( eItalic );
258 void Font::SetOutline( bool bOutline )
260 if (IsOutline() != bOutline)
261 mpImplFont->mbOutline = bOutline;
264 void Font::SetShadow( bool bShadow )
266 if (IsShadow() != bShadow)
267 mpImplFont->mbShadow = bShadow;
270 void Font::SetUnderline( FontLineStyle eUnderline )
272 if (GetUnderline() != eUnderline)
273 mpImplFont->meUnderline = eUnderline;
276 void Font::SetOverline( FontLineStyle eOverline )
278 if (GetOverline() != eOverline)
279 mpImplFont->meOverline = eOverline;
282 void Font::SetStrikeout( FontStrikeout eStrikeout )
284 if (GetStrikeout() != eStrikeout)
285 mpImplFont->meStrikeout = eStrikeout;
288 void Font::SetRelief( FontRelief eRelief )
290 if (GetRelief() != eRelief)
291 mpImplFont->meRelief = eRelief;
294 void Font::SetEmphasisMark( FontEmphasisMark eEmphasisMark )
296 if (GetEmphasisMark() != eEmphasisMark)
297 mpImplFont->meEmphasisMark = eEmphasisMark;
300 void Font::SetWordLineMode( bool bWordLine )
302 if (IsWordLineMode() != bWordLine)
303 mpImplFont->mbWordLine = bWordLine;
306 Font& Font::operator=( const vcl::Font& rFont )
308 mpImplFont = rFont.mpImplFont;
309 return *this;
312 Font& Font::operator=( vcl::Font&& rFont ) noexcept
314 mpImplFont = std::move(rFont.mpImplFont);
315 return *this;
318 FontEmphasisMark Font::GetEmphasisMarkStyle() const
320 FontEmphasisMark nEmphasisMark = GetEmphasisMark();
322 // If no Position is set, then calculate the default position, which
323 // depends on the language
324 if (!(nEmphasisMark & (FontEmphasisMark::PosAbove | FontEmphasisMark::PosBelow)))
326 LanguageType eLang = GetLanguage();
327 // In Chinese Simplified the EmphasisMarks are below/left
328 if (MsLangId::isSimplifiedChinese(eLang))
330 nEmphasisMark |= FontEmphasisMark::PosBelow;
332 else
334 eLang = GetCJKContextLanguage();
336 // In Chinese Simplified the EmphasisMarks are below/left
337 if (MsLangId::isSimplifiedChinese(eLang))
338 nEmphasisMark |= FontEmphasisMark::PosBelow;
339 else
340 nEmphasisMark |= FontEmphasisMark::PosAbove;
344 return nEmphasisMark;
347 bool Font::operator==( const vcl::Font& rFont ) const
349 return mpImplFont == rFont.mpImplFont;
352 bool Font::EqualIgnoreColor( const vcl::Font& rFont ) const
354 return mpImplFont->EqualIgnoreColor( *rFont.mpImplFont );
357 size_t Font::GetHashValueIgnoreColor() const
359 return mpImplFont->GetHashValueIgnoreColor();
362 void Font::Merge( const vcl::Font& rFont )
364 if ( !rFont.GetFamilyName().isEmpty() )
366 SetFamilyName( rFont.GetFamilyName() );
367 SetStyleName( rFont.GetStyleName() );
368 SetCharSet( rFont.GetCharSet() );
369 SetLanguageTag( rFont.GetLanguageTag() );
370 SetCJKContextLanguageTag( rFont.GetCJKContextLanguageTag() );
371 // don't use access methods here, might lead to AskConfig(), if DONTKNOW
372 SetFamily( rFont.GetFamilyType() );
373 SetPitch( rFont.GetPitch() );
376 if ( rFont.GetWeight() != WEIGHT_DONTKNOW )
377 SetWeight( rFont.GetWeight() );
378 if ( rFont.GetItalic() != ITALIC_DONTKNOW )
379 SetItalic( rFont.GetItalic() );
380 if ( rFont.GetWidthType() != WIDTH_DONTKNOW )
381 SetWidthType( rFont.GetWidthType() );
383 if ( rFont.GetFontSize().Height() )
384 SetFontSize( rFont.GetFontSize() );
385 if ( rFont.GetUnderline() != LINESTYLE_DONTKNOW )
387 SetUnderline( rFont.GetUnderline() );
388 SetWordLineMode( rFont.IsWordLineMode() );
390 if ( rFont.GetOverline() != LINESTYLE_DONTKNOW )
392 SetOverline( rFont.GetOverline() );
393 SetWordLineMode( rFont.IsWordLineMode() );
395 if ( rFont.GetStrikeout() != STRIKEOUT_DONTKNOW )
397 SetStrikeout( rFont.GetStrikeout() );
398 SetWordLineMode( rFont.IsWordLineMode() );
401 // Defaults?
402 SetOrientation( rFont.GetOrientation() );
403 SetVertical( rFont.IsVertical() );
404 SetEmphasisMark( rFont.GetEmphasisMark() );
405 SetKerning( rFont.IsKerning() ? FontKerning::FontSpecific : FontKerning::NONE );
406 SetOutline( rFont.IsOutline() );
407 SetShadow( rFont.IsShadow() );
408 SetRelief( rFont.GetRelief() );
411 void Font::GetFontAttributes( FontAttributes& rAttrs ) const
413 rAttrs.SetFamilyName( GetFamilyName() );
414 rAttrs.SetStyleName( GetStyleName() );
415 rAttrs.SetFamilyType( GetFamilyType() );
416 rAttrs.SetPitch( GetPitch() );
417 rAttrs.SetItalic( GetItalic() );
418 rAttrs.SetWeight( GetWeight() );
419 rAttrs.SetWidthType( WIDTH_DONTKNOW );
420 rAttrs.SetMicrosoftSymbolEncoded( GetCharSet() == RTL_TEXTENCODING_SYMBOL );
423 // tdf#127471 for corrections on EMF/WMF we need the AvgFontWidth in Windows-specific notation
424 tools::Long Font::GetOrCalculateAverageFontWidth() const
426 if(0 == mpImplFont->GetCalculatedAverageFontWidth())
428 // VirtualDevice is not thread safe
429 SolarMutexGuard aGuard;
431 // create unscaled copy of font (this), a VirtualDevice and set it there
432 vcl::Font aUnscaledFont(*this);
433 ScopedVclPtr<VirtualDevice> pTempVirtualDevice(VclPtr<VirtualDevice>::Create());
434 aUnscaledFont.SetAverageFontWidth(0);
435 pTempVirtualDevice->SetFont(aUnscaledFont);
437 #ifdef _WIN32
438 // on Windows systems use FontMetric to get/create AverageFontWidth from system
439 const FontMetric aMetric(pTempVirtualDevice->GetFontMetric());
440 const_cast<Font*>(this)->mpImplFont->SetCalculatedAverageFontWidth(aMetric.GetAverageFontWidth());
441 #else
442 // On non-Windows systems we need to calculate AvgFontWidth
443 // as close as possible (discussion see documentation in task),
444 // so calculate it. For discussion of method used, see task
445 // buffer measure string creation, will always use the same
446 static constexpr OUString aMeasureString
447 = u"\u0020\u0021\u0022\u0023\u0024\u0025\u0026\u0027"
448 "\u0028\u0029\u002A\u002B\u002C\u002D\u002E\u002F"
449 "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037"
450 "\u0038\u0039\u003A\u003B\u003C\u003D\u003E\u003F"
451 "\u0040\u0041\u0042\u0043\u0044\u0045\u0046\u0047"
452 "\u0048\u0049\u004A\u004B\u004C\u004D\u004E\u004F"
453 "\u0050\u0051\u0052\u0053\u0054\u0055\u0056\u0057"
454 "\u0058\u0059\u005A\u005B\u005C\u005D\u005E\u005F"
455 "\u0060\u0061\u0062\u0063\u0064\u0065\u0066\u0067"
456 "\u0068\u0069\u006A\u006B\u006C\u006D\u006E\u006F"
457 "\u0070\u0071\u0072\u0073\u0074\u0075\u0076\u0077"
458 "\u0078\u0079\u007A\u007B\u007C\u007D\u007E"_ustr;
460 const double fAverageFontWidth(
461 pTempVirtualDevice->GetTextWidth(aMeasureString) /
462 static_cast<double>(aMeasureString.getLength()));
463 const_cast<Font*>(this)->mpImplFont->SetCalculatedAverageFontWidth(basegfx::fround(fAverageFontWidth));
464 #endif
467 return mpImplFont->GetCalculatedAverageFontWidth();
470 SvStream& ReadImplFont( SvStream& rIStm, ImplFont& rImplFont, tools::Long& rnNormedFontScaling )
472 VersionCompatRead aCompat( rIStm );
473 sal_uInt16 nTmp16(0);
474 sal_Int16 nTmps16(0);
475 bool bTmp(false);
476 sal_uInt8 nTmp8(0);
478 rImplFont.SetFamilyName( rIStm.ReadUniOrByteString(rIStm.GetStreamCharSet()) );
479 rImplFont.maStyleName = rIStm.ReadUniOrByteString(rIStm.GetStreamCharSet());
480 TypeSerializer aSerializer(rIStm);
481 aSerializer.readSize(rImplFont.maAverageFontSize);
483 static const bool bFuzzing = comphelper::IsFuzzing();
484 if (bFuzzing)
486 if (rImplFont.maAverageFontSize.Width() > 8192)
488 SAL_WARN("vcl.gdi", "suspicious average width of: " << rImplFont.maAverageFontSize.Width());
489 rImplFont.maAverageFontSize.setWidth(8192);
491 if (rImplFont.maAverageFontSize.Height() > 8192)
493 SAL_WARN("vcl.gdi", "suspicious average height of: " << rImplFont.maAverageFontSize.Height());
494 rImplFont.maAverageFontSize.setHeight(8192);
498 rIStm.ReadUInt16( nTmp16 ); rImplFont.SetCharSet( static_cast<rtl_TextEncoding>(nTmp16) );
499 rIStm.ReadUInt16( nTmp16 ); rImplFont.SetFamilyType( static_cast<FontFamily>(nTmp16) );
500 rIStm.ReadUInt16( nTmp16 ); rImplFont.SetPitch( static_cast<FontPitch>(nTmp16) );
501 rIStm.ReadUInt16( nTmp16 ); rImplFont.SetWeight( static_cast<FontWeight>(nTmp16) );
502 rIStm.ReadUInt16( nTmp16 ); rImplFont.meUnderline = static_cast<FontLineStyle>(nTmp16);
503 rIStm.ReadUInt16( nTmp16 ); rImplFont.meStrikeout = static_cast<FontStrikeout>(nTmp16);
504 rIStm.ReadUInt16( nTmp16 ); rImplFont.SetItalic( static_cast<FontItalic>(nTmp16) );
505 rIStm.ReadUInt16( nTmp16 ); rImplFont.maLanguageTag.reset( LanguageType(nTmp16) );
506 rIStm.ReadUInt16( nTmp16 ); rImplFont.meWidthType = static_cast<FontWidth>(nTmp16);
508 rIStm.ReadInt16( nTmps16 ); rImplFont.mnOrientation = Degree10(nTmps16);
510 rIStm.ReadCharAsBool( bTmp ); rImplFont.mbWordLine = bTmp;
511 rIStm.ReadCharAsBool( bTmp ); rImplFont.mbOutline = bTmp;
512 rIStm.ReadCharAsBool( bTmp ); rImplFont.mbShadow = bTmp;
513 rIStm.ReadUChar( nTmp8 ); rImplFont.meKerning = static_cast<FontKerning>(nTmp8);
515 if( aCompat.GetVersion() >= 2 )
517 rIStm.ReadUChar( nTmp8 ); rImplFont.meRelief = static_cast<FontRelief>(nTmp8);
518 rIStm.ReadUInt16( nTmp16 ); rImplFont.maCJKLanguageTag.reset( LanguageType(nTmp16) );
519 rIStm.ReadCharAsBool( bTmp ); rImplFont.mbVertical = bTmp;
520 rIStm.ReadUInt16( nTmp16 );
521 rImplFont.meEmphasisMark = static_cast<FontEmphasisMark>(nTmp16 & o3tl::typed_flags<FontEmphasisMark>::mask);
524 if( aCompat.GetVersion() >= 3 )
526 rIStm.ReadUInt16( nTmp16 ); rImplFont.meOverline = static_cast<FontLineStyle>(nTmp16);
529 // tdf#127471 read NormedFontScaling
530 if( aCompat.GetVersion() >= 4 )
532 sal_Int32 nNormedFontScaling(0);
533 rIStm.ReadInt32(nNormedFontScaling);
534 rnNormedFontScaling = nNormedFontScaling;
537 if( aCompat.GetVersion() >= 5 )
539 rIStm.ReadInt16( nTmps16 );
540 rImplFont.mnSpacing = nTmps16;
543 // Relief
544 // CJKContextLanguage
546 return rIStm;
549 SvStream& WriteImplFont( SvStream& rOStm, const ImplFont& rImplFont, tools::Long nNormedFontScaling )
551 // tdf#127471 increase to version 4
552 // tdf#66819 increase to version 5
553 VersionCompatWrite aCompat( rOStm, 5 );
555 TypeSerializer aSerializer(rOStm);
556 rOStm.WriteUniOrByteString( rImplFont.GetFamilyName(), rOStm.GetStreamCharSet() );
557 rOStm.WriteUniOrByteString( rImplFont.GetStyleName(), rOStm.GetStreamCharSet() );
558 aSerializer.writeSize(rImplFont.maAverageFontSize);
560 rOStm.WriteUInt16( GetStoreCharSet( rImplFont.GetCharSet() ) );
561 rOStm.WriteUInt16( rImplFont.GetFamilyTypeNoAsk() );
562 rOStm.WriteUInt16( rImplFont.GetPitchNoAsk() );
563 rOStm.WriteUInt16( rImplFont.GetWeightNoAsk() );
564 rOStm.WriteUInt16( rImplFont.meUnderline );
565 rOStm.WriteUInt16( rImplFont.meStrikeout );
566 rOStm.WriteUInt16( rImplFont.GetItalicNoAsk() );
567 rOStm.WriteUInt16( static_cast<sal_uInt16>(rImplFont.maLanguageTag.getLanguageType( false)) );
568 rOStm.WriteUInt16( rImplFont.GetWidthTypeNoAsk() );
570 rOStm.WriteInt16( rImplFont.mnOrientation.get() );
572 rOStm.WriteBool( rImplFont.mbWordLine );
573 rOStm.WriteBool( rImplFont.mbOutline );
574 rOStm.WriteBool( rImplFont.mbShadow );
575 rOStm.WriteUChar( static_cast<sal_uInt8>(rImplFont.meKerning) );
577 // new in version 2
578 rOStm.WriteUChar( static_cast<unsigned char>(rImplFont.meRelief) );
579 rOStm.WriteUInt16( static_cast<sal_uInt16>(rImplFont.maCJKLanguageTag.getLanguageType( false)) );
580 rOStm.WriteBool( rImplFont.mbVertical );
581 rOStm.WriteUInt16( static_cast<sal_uInt16>(rImplFont.meEmphasisMark) );
583 // new in version 3
584 rOStm.WriteUInt16( rImplFont.meOverline );
586 // new in version 4, NormedFontScaling
587 rOStm.WriteInt32(nNormedFontScaling);
589 // new in version 5
590 rOStm.WriteInt16( rImplFont.mnSpacing );
591 return rOStm;
594 SvStream& ReadFont( SvStream& rIStm, vcl::Font& rFont )
596 // tdf#127471 try to read NormedFontScaling
597 tools::Long nNormedFontScaling(0);
598 SvStream& rRetval(ReadImplFont( rIStm, *rFont.mpImplFont, nNormedFontScaling ));
600 if (nNormedFontScaling > 0)
602 #ifdef _WIN32
603 // we run on windows and a NormedFontScaling was written
604 if(rFont.GetFontSize().getWidth() == nNormedFontScaling)
606 // the writing producer was running on a non-windows system, adapt to needed windows
607 // system-specific pre-multiply
608 const tools::Long nHeight(std::max<tools::Long>(rFont.GetFontSize().getHeight(), 0));
609 sal_uInt32 nScaledWidth(0);
611 if(nHeight > 0)
613 vcl::Font aUnscaledFont(rFont);
614 aUnscaledFont.SetAverageFontWidth(0);
615 const FontMetric aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aUnscaledFont));
617 if (nHeight > 0)
619 const double fScaleFactor(static_cast<double>(nNormedFontScaling) / static_cast<double>(nHeight));
620 nScaledWidth = basegfx::fround(static_cast<double>(aUnscaledFontMetric.GetAverageFontWidth()) * fScaleFactor);
624 rFont.SetAverageFontWidth(nScaledWidth);
626 else
628 // the writing producer was on a windows system, correct pre-multiplied value
629 // is already set, nothing to do. Ignore 2nd value. Here a check
630 // could be done if adapting the 2nd, NormedFontScaling value would be similar to
631 // the set value for plausibility reasons
633 #else
634 // we do not run on windows and a NormedFontScaling was written
635 if(rFont.GetFontSize().getWidth() == nNormedFontScaling)
637 // the writing producer was not on a windows system, correct value
638 // already set, nothing to do
640 else
642 // the writing producer was on a windows system, correct FontScaling.
643 // The correct non-pre-multiplied value is the 2nd one, use it
644 rFont.SetAverageFontWidth(nNormedFontScaling);
646 #endif
649 return rRetval;
652 SvStream& WriteFont( SvStream& rOStm, const vcl::Font& rFont )
654 // tdf#127471 prepare NormedFontScaling for additional export
655 tools::Long nNormedFontScaling(rFont.GetFontSize().getWidth());
657 // FontScaling usage at vcl-Font is detected by checking that FontWidth != 0
658 if (nNormedFontScaling > 0)
660 const tools::Long nHeight(std::max<tools::Long>(rFont.GetFontSize().getHeight(), 0));
662 // check for negative height
663 if(0 == nHeight)
665 nNormedFontScaling = 0;
667 else
669 #ifdef _WIN32
670 // for WIN32 the value is pre-multiplied with AverageFontWidth
671 // which makes it system-dependent. Turn that back to have the
672 // normed non-windows form of it for export as 2nd value
673 vcl::Font aUnscaledFont(rFont);
674 aUnscaledFont.SetAverageFontWidth(0);
675 const FontMetric aUnscaledFontMetric(
676 Application::GetDefaultDevice()->GetFontMetric(aUnscaledFont));
678 if (aUnscaledFontMetric.GetAverageFontWidth() > 0)
680 const double fScaleFactor(
681 static_cast<double>(nNormedFontScaling)
682 / static_cast<double>(aUnscaledFontMetric.GetAverageFontWidth()));
683 nNormedFontScaling = static_cast<tools::Long>(fScaleFactor * nHeight);
685 #endif
689 return WriteImplFont( rOStm, *rFont.mpImplFont, nNormedFontScaling );
692 namespace
694 bool identifyTrueTypeFont( const void* i_pBuffer, sal_uInt32 i_nSize, Font& o_rResult )
696 bool bResult = false;
697 TrueTypeFont* pTTF = nullptr;
698 if( OpenTTFontBuffer( i_pBuffer, i_nSize, 0, &pTTF ) == SFErrCodes::Ok )
700 TTGlobalFontInfo aInfo;
701 GetTTGlobalFontInfo( pTTF, &aInfo );
702 // most importantly: the family name
703 if( !aInfo.ufamily.isEmpty() )
704 o_rResult.SetFamilyName( aInfo.ufamily );
705 else if( !aInfo.family.isEmpty() )
706 o_rResult.SetFamilyName( OStringToOUString( aInfo.family, RTL_TEXTENCODING_ASCII_US ) );
707 // set weight
708 if( aInfo.weight )
710 if( aInfo.weight < FW_EXTRALIGHT )
711 o_rResult.SetWeight( WEIGHT_THIN );
712 else if( aInfo.weight < FW_LIGHT )
713 o_rResult.SetWeight( WEIGHT_ULTRALIGHT );
714 else if( aInfo.weight < FW_NORMAL )
715 o_rResult.SetWeight( WEIGHT_LIGHT );
716 else if( aInfo.weight < FW_MEDIUM )
717 o_rResult.SetWeight( WEIGHT_NORMAL );
718 else if( aInfo.weight < FW_SEMIBOLD )
719 o_rResult.SetWeight( WEIGHT_MEDIUM );
720 else if( aInfo.weight < FW_BOLD )
721 o_rResult.SetWeight( WEIGHT_SEMIBOLD );
722 else if( aInfo.weight < FW_EXTRABOLD )
723 o_rResult.SetWeight( WEIGHT_BOLD );
724 else if( aInfo.weight < FW_BLACK )
725 o_rResult.SetWeight( WEIGHT_ULTRABOLD );
726 else
727 o_rResult.SetWeight( WEIGHT_BLACK );
729 else
730 o_rResult.SetWeight( (aInfo.macStyle & 1) ? WEIGHT_BOLD : WEIGHT_NORMAL );
731 // set width
732 if( aInfo.width )
734 if( aInfo.width == FWIDTH_ULTRA_CONDENSED )
735 o_rResult.SetAverageFontWidth( WIDTH_ULTRA_CONDENSED );
736 else if( aInfo.width == FWIDTH_EXTRA_CONDENSED )
737 o_rResult.SetAverageFontWidth( WIDTH_EXTRA_CONDENSED );
738 else if( aInfo.width == FWIDTH_CONDENSED )
739 o_rResult.SetAverageFontWidth( WIDTH_CONDENSED );
740 else if( aInfo.width == FWIDTH_SEMI_CONDENSED )
741 o_rResult.SetAverageFontWidth( WIDTH_SEMI_CONDENSED );
742 else if( aInfo.width == FWIDTH_NORMAL )
743 o_rResult.SetAverageFontWidth( WIDTH_NORMAL );
744 else if( aInfo.width == FWIDTH_SEMI_EXPANDED )
745 o_rResult.SetAverageFontWidth( WIDTH_SEMI_EXPANDED );
746 else if( aInfo.width == FWIDTH_EXPANDED )
747 o_rResult.SetAverageFontWidth( WIDTH_EXPANDED );
748 else if( aInfo.width == FWIDTH_EXTRA_EXPANDED )
749 o_rResult.SetAverageFontWidth( WIDTH_EXTRA_EXPANDED );
750 else if( aInfo.width >= FWIDTH_ULTRA_EXPANDED )
751 o_rResult.SetAverageFontWidth( WIDTH_ULTRA_EXPANDED );
753 // set italic
754 o_rResult.SetItalic( (aInfo.italicAngle != 0) ? ITALIC_NORMAL : ITALIC_NONE );
756 // set pitch
757 o_rResult.SetPitch( (aInfo.pitch == 0) ? PITCH_VARIABLE : PITCH_FIXED );
759 // set style name
760 if( !aInfo.usubfamily.isEmpty() )
761 o_rResult.SetStyleName( aInfo.usubfamily );
762 else if( !aInfo.subfamily.isEmpty() )
763 o_rResult.SetStyleName( OUString::createFromAscii( aInfo.subfamily ) );
765 // cleanup
766 CloseTTFont( pTTF );
767 // success
768 bResult = true;
770 return bResult;
773 struct WeightSearchEntry
775 const char* string;
776 int string_len;
777 FontWeight weight;
779 bool operator<( const WeightSearchEntry& rRight ) const
781 return rtl_str_compareIgnoreAsciiCase_WithLength( string, string_len, rRight.string, rRight.string_len ) < 0;
784 const weight_table[] =
786 { "black", 5, WEIGHT_BLACK },
787 { "bold", 4, WEIGHT_BOLD },
788 { "book", 4, WEIGHT_LIGHT },
789 { "demi", 4, WEIGHT_SEMIBOLD },
790 { "heavy", 5, WEIGHT_BLACK },
791 { "light", 5, WEIGHT_LIGHT },
792 { "medium", 6, WEIGHT_MEDIUM },
793 { "regular", 7, WEIGHT_NORMAL },
794 { "super", 5, WEIGHT_ULTRABOLD },
795 { "thin", 4, WEIGHT_THIN }
798 bool identifyType1Font( const char* i_pBuffer, sal_uInt32 i_nSize, Font& o_rResult )
800 // might be a type1, find eexec
801 const char* pStream = i_pBuffer;
802 const char* const pExec = "eexec";
803 const char* pExecPos = std::search( pStream, pStream+i_nSize, pExec, pExec+5 );
804 if( pExecPos != pStream+i_nSize)
806 // find /FamilyName entry
807 static const char* const pFam = "/FamilyName";
808 const char* pFamPos = std::search( pStream, pExecPos, pFam, pFam+11 );
809 if( pFamPos != pExecPos )
811 // extract the string value behind /FamilyName
812 const char* pOpen = pFamPos+11;
813 while( pOpen < pExecPos && *pOpen != '(' )
814 pOpen++;
815 const char* pClose = pOpen;
816 while( pClose < pExecPos && *pClose != ')' )
817 pClose++;
818 if( pClose - pOpen > 1 )
820 o_rResult.SetFamilyName( OStringToOUString( std::string_view( pOpen+1, pClose-pOpen-1 ), RTL_TEXTENCODING_ASCII_US ) );
824 // parse /ItalicAngle
825 static const char* const pItalic = "/ItalicAngle";
826 const char* pItalicPos = std::search( pStream, pExecPos, pItalic, pItalic+12 );
827 if( pItalicPos != pExecPos )
829 const char* pItalicEnd = pItalicPos + 12;
830 auto nItalic = rtl_str_toInt64_WithLength(pItalicEnd, 10, pExecPos - pItalicEnd);
831 o_rResult.SetItalic( (nItalic != 0) ? ITALIC_NORMAL : ITALIC_NONE );
834 // parse /Weight
835 static const char* const pWeight = "/Weight";
836 const char* pWeightPos = std::search( pStream, pExecPos, pWeight, pWeight+7 );
837 if( pWeightPos != pExecPos )
839 // extract the string value behind /Weight
840 const char* pOpen = pWeightPos+7;
841 while( pOpen < pExecPos && *pOpen != '(' )
842 pOpen++;
843 const char* pClose = pOpen;
844 while( pClose < pExecPos && *pClose != ')' )
845 pClose++;
846 if( pClose - pOpen > 1 )
848 WeightSearchEntry aEnt;
849 aEnt.string = pOpen+1;
850 aEnt.string_len = (pClose-pOpen)-1;
851 aEnt.weight = WEIGHT_NORMAL;
852 WeightSearchEntry const * pFound = std::lower_bound( std::begin(weight_table), std::end(weight_table), aEnt );
853 if( pFound != std::end(weight_table) &&
854 rtl_str_compareIgnoreAsciiCase_WithLength( pFound->string, pFound->string_len, aEnt.string, aEnt.string_len) == 0 )
855 o_rResult.SetWeight( pFound->weight );
859 // parse isFixedPitch
860 static const char* const pFixed = "/isFixedPitch";
861 const char* pFixedPos = std::search( pStream, pExecPos, pFixed, pFixed+13 );
862 if( pFixedPos != pExecPos )
864 // skip whitespace
865 while( pFixedPos < pExecPos-4 &&
866 ( *pFixedPos == ' ' ||
867 *pFixedPos == '\t' ||
868 *pFixedPos == '\r' ||
869 *pFixedPos == '\n' ) )
871 pFixedPos++;
873 // find "true" value
874 if( rtl_str_compareIgnoreAsciiCase_WithLength( pFixedPos, 4, "true", 4 ) == 0 )
875 o_rResult.SetPitch( PITCH_FIXED );
876 else
877 o_rResult.SetPitch( PITCH_VARIABLE );
880 return false;
884 Font Font::identifyFont( const void* i_pBuffer, sal_uInt32 i_nSize )
886 Font aResult;
887 if( ! identifyTrueTypeFont( i_pBuffer, i_nSize, aResult ) )
889 const char* pStream = static_cast<const char*>(i_pBuffer);
890 if( pStream && i_nSize > 100 &&
891 *pStream == '%' && pStream[1] == '!' )
893 identifyType1Font( pStream, i_nSize, aResult );
897 return aResult;
900 // The inlines from the font.hxx header are now instantiated for pImpl-ification
901 const Color& Font::GetColor() const { return mpImplFont->maColor; }
902 const Color& Font::GetFillColor() const { return mpImplFont->maFillColor; }
903 bool Font::IsTransparent() const { return mpImplFont->mbTransparent; }
905 TextAlign Font::GetAlignment() const { return mpImplFont->GetAlignment(); }
907 const OUString& Font::GetFamilyName() const { return mpImplFont->GetFamilyName(); }
908 const OUString& Font::GetStyleName() const { return mpImplFont->maStyleName; }
909 const FontFamily& Font::GetFontFamily() const { return mpImplFont->meFamily; }
911 const Size& Font::GetFontSize() const { return mpImplFont->GetFontSize(); }
912 void Font::SetFontHeight( tools::Long nHeight ) { SetFontSize( Size( std::as_const(mpImplFont)->GetFontSize().Width(), nHeight ) ); }
913 tools::Long Font::GetFontHeight() const { return mpImplFont->GetFontSize().Height(); }
914 void Font::SetAverageFontWidth( tools::Long nWidth ) { SetFontSize( Size( nWidth, std::as_const(mpImplFont)->GetFontSize().Height() ) ); }
915 tools::Long Font::GetAverageFontWidth() const { return mpImplFont->GetFontSize().Width(); }
916 const Size& Font::GetAverageFontSize() const { return mpImplFont->maAverageFontSize; }
918 rtl_TextEncoding Font::GetCharSet() const { return mpImplFont->GetCharSet(); }
920 const LanguageTag& Font::GetLanguageTag() const { return mpImplFont->maLanguageTag; }
921 const LanguageTag& Font::GetCJKContextLanguageTag() const { return mpImplFont->maCJKLanguageTag; }
922 LanguageType Font::GetLanguage() const { return mpImplFont->maLanguageTag.getLanguageType( false); }
923 LanguageType Font::GetCJKContextLanguage() const { return mpImplFont->maCJKLanguageTag.getLanguageType( false); }
925 Degree10 Font::GetOrientation() const { return mpImplFont->mnOrientation; }
926 bool Font::IsVertical() const { return mpImplFont->mbVertical; }
927 FontKerning Font::GetKerning() const { return mpImplFont->meKerning; }
929 FontPitch Font::GetPitch() { return mpImplFont->GetPitch(); }
930 FontWeight Font::GetWeight() { return mpImplFont->GetWeight(); }
931 FontWidth Font::GetWidthType() { return mpImplFont->GetWidthType(); }
932 FontItalic Font::GetItalic() { return mpImplFont->GetItalic(); }
933 FontFamily Font::GetFamilyType() { return mpImplFont->GetFamilyType(); }
935 FontPitch Font::GetPitch() const { return mpImplFont->GetPitchNoAsk(); }
936 FontWeight Font::GetWeight() const { return mpImplFont->GetWeightNoAsk(); }
937 FontWidth Font::GetWidthType() const { return mpImplFont->GetWidthTypeNoAsk(); }
938 FontItalic Font::GetItalic() const { return mpImplFont->GetItalicNoAsk(); }
939 FontFamily Font::GetFamilyType() const { return mpImplFont->GetFamilyTypeNoAsk(); }
941 int Font::GetQuality() const { return mpImplFont->GetQuality(); }
942 void Font::SetQuality( int nQuality ) { mpImplFont->SetQuality( nQuality ); }
943 void Font::IncreaseQualityBy( int nQualityAmount ) { mpImplFont->IncreaseQualityBy( nQualityAmount ); }
944 void Font::DecreaseQualityBy( int nQualityAmount ) { mpImplFont->DecreaseQualityBy( nQualityAmount ); }
946 bool Font::IsOutline() const { return mpImplFont->mbOutline; }
947 bool Font::IsShadow() const { return mpImplFont->mbShadow; }
948 FontRelief Font::GetRelief() const { return mpImplFont->meRelief; }
949 FontLineStyle Font::GetUnderline() const { return mpImplFont->meUnderline; }
950 FontLineStyle Font::GetOverline() const { return mpImplFont->meOverline; }
951 FontStrikeout Font::GetStrikeout() const { return mpImplFont->meStrikeout; }
952 FontEmphasisMark Font::GetEmphasisMark() const { return mpImplFont->meEmphasisMark; }
953 bool Font::IsWordLineMode() const { return mpImplFont->mbWordLine; }
954 bool Font::IsSameInstance( const vcl::Font& rFont ) const { return (mpImplFont == rFont.mpImplFont); }
957 ImplFont::ImplFont() :
958 meWeight( WEIGHT_DONTKNOW ),
959 meFamily( FAMILY_DONTKNOW ),
960 mePitch( PITCH_DONTKNOW ),
961 meWidthType( WIDTH_DONTKNOW ),
962 meItalic( ITALIC_NONE ),
963 meAlign( ALIGN_TOP ),
964 meUnderline( LINESTYLE_NONE ),
965 meOverline( LINESTYLE_NONE ),
966 meStrikeout( STRIKEOUT_NONE ),
967 meRelief( FontRelief::NONE ),
968 meEmphasisMark( FontEmphasisMark::NONE ),
969 meKerning( FontKerning::FontSpecific ),
970 mnSpacing( 0 ),
971 meCharSet( RTL_TEXTENCODING_DONTKNOW ),
972 maLanguageTag( LANGUAGE_DONTKNOW ),
973 maCJKLanguageTag( LANGUAGE_DONTKNOW ),
974 mbOutline( false ),
975 mbConfigLookup( false ),
976 mbShadow( false ),
977 mbVertical( false ),
978 mbTransparent( true ),
979 maColor( COL_TRANSPARENT ),
980 maFillColor( COL_TRANSPARENT ),
981 mbWordLine( false ),
982 mnOrientation( 0 ),
983 mnQuality( 0 ),
984 mnCalculatedAverageFontWidth( 0 )
987 ImplFont::ImplFont( const ImplFont& rImplFont ) :
988 maFamilyName( rImplFont.maFamilyName ),
989 maStyleName( rImplFont.maStyleName ),
990 meWeight( rImplFont.meWeight ),
991 meFamily( rImplFont.meFamily ),
992 mePitch( rImplFont.mePitch ),
993 meWidthType( rImplFont.meWidthType ),
994 meItalic( rImplFont.meItalic ),
995 meAlign( rImplFont.meAlign ),
996 meUnderline( rImplFont.meUnderline ),
997 meOverline( rImplFont.meOverline ),
998 meStrikeout( rImplFont.meStrikeout ),
999 meRelief( rImplFont.meRelief ),
1000 meEmphasisMark( rImplFont.meEmphasisMark ),
1001 meKerning( rImplFont.meKerning ),
1002 mnSpacing( rImplFont.mnSpacing ),
1003 maAverageFontSize( rImplFont.maAverageFontSize ),
1004 meCharSet( rImplFont.meCharSet ),
1005 maLanguageTag( rImplFont.maLanguageTag ),
1006 maCJKLanguageTag( rImplFont.maCJKLanguageTag ),
1007 mbOutline( rImplFont.mbOutline ),
1008 mbConfigLookup( rImplFont.mbConfigLookup ),
1009 mbShadow( rImplFont.mbShadow ),
1010 mbVertical( rImplFont.mbVertical ),
1011 mbTransparent( rImplFont.mbTransparent ),
1012 maColor( rImplFont.maColor ),
1013 maFillColor( rImplFont.maFillColor ),
1014 mbWordLine( rImplFont.mbWordLine ),
1015 mnOrientation( rImplFont.mnOrientation ),
1016 mnQuality( rImplFont.mnQuality ),
1017 mnCalculatedAverageFontWidth( rImplFont.mnCalculatedAverageFontWidth )
1020 bool ImplFont::operator==( const ImplFont& rOther ) const
1022 if(!EqualIgnoreColor( rOther ))
1023 return false;
1025 if( (maColor != rOther.maColor)
1026 || (maFillColor != rOther.maFillColor) )
1027 return false;
1029 return true;
1032 bool ImplFont::EqualIgnoreColor( const ImplFont& rOther ) const
1034 // equality tests split up for easier debugging
1035 if( (meWeight != rOther.meWeight)
1036 || (meItalic != rOther.meItalic)
1037 || (meFamily != rOther.meFamily)
1038 || (mePitch != rOther.mePitch) )
1039 return false;
1041 if( (meCharSet != rOther.meCharSet)
1042 || (maLanguageTag != rOther.maLanguageTag)
1043 || (maCJKLanguageTag != rOther.maCJKLanguageTag)
1044 || (meAlign != rOther.meAlign) )
1045 return false;
1047 if( (maAverageFontSize != rOther.maAverageFontSize)
1048 || (mnOrientation != rOther.mnOrientation)
1049 || (mbVertical != rOther.mbVertical) )
1050 return false;
1052 if( (maFamilyName != rOther.maFamilyName)
1053 || (maStyleName != rOther.maStyleName) )
1054 return false;
1056 if( (meUnderline != rOther.meUnderline)
1057 || (meOverline != rOther.meOverline)
1058 || (meStrikeout != rOther.meStrikeout)
1059 || (meRelief != rOther.meRelief)
1060 || (meEmphasisMark != rOther.meEmphasisMark)
1061 || (mbWordLine != rOther.mbWordLine)
1062 || (mbOutline != rOther.mbOutline)
1063 || (mbShadow != rOther.mbShadow)
1064 || (meKerning != rOther.meKerning)
1065 || (mnSpacing != rOther.mnSpacing)
1066 || (mbTransparent != rOther.mbTransparent) )
1067 return false;
1069 return true;
1072 size_t ImplFont::GetHashValue() const
1074 size_t hash = GetHashValueIgnoreColor();
1075 o3tl::hash_combine( hash, static_cast<sal_uInt32>( maColor ));
1076 o3tl::hash_combine( hash, static_cast<sal_uInt32>( maFillColor ));
1077 return hash;
1080 size_t ImplFont::GetHashValueIgnoreColor() const
1082 size_t hash = 0;
1084 o3tl::hash_combine( hash, meWeight );
1085 o3tl::hash_combine( hash, meItalic );
1086 o3tl::hash_combine( hash, meFamily );
1087 o3tl::hash_combine( hash, mePitch );
1089 o3tl::hash_combine( hash, meCharSet );
1090 o3tl::hash_combine( hash, maLanguageTag.getLanguageType( false ).get());
1091 o3tl::hash_combine( hash, maCJKLanguageTag.getLanguageType( false ).get());
1092 o3tl::hash_combine( hash, meAlign );
1094 o3tl::hash_combine( hash, maAverageFontSize.GetHashValue());
1095 o3tl::hash_combine( hash, mnOrientation.get());
1096 o3tl::hash_combine( hash, mbVertical );
1098 o3tl::hash_combine( hash, maFamilyName );
1099 o3tl::hash_combine( hash, maStyleName );
1101 o3tl::hash_combine( hash, meUnderline );
1102 o3tl::hash_combine( hash, meOverline );
1103 o3tl::hash_combine( hash, meStrikeout );
1104 o3tl::hash_combine( hash, meRelief );
1105 o3tl::hash_combine( hash, meEmphasisMark );
1106 o3tl::hash_combine( hash, mbWordLine );
1107 o3tl::hash_combine( hash, mbOutline );
1108 o3tl::hash_combine( hash, mbShadow );
1109 o3tl::hash_combine( hash, meKerning );
1110 o3tl::hash_combine( hash, mnSpacing );
1111 o3tl::hash_combine( hash, mbTransparent );
1113 return hash;
1116 void ImplFont::AskConfig()
1118 if( mbConfigLookup )
1119 return;
1121 mbConfigLookup = true;
1123 // prepare the FontSubst configuration lookup
1124 const utl::FontSubstConfiguration& rFontSubst = utl::FontSubstConfiguration::get();
1126 OUString aShortName;
1127 OUString aFamilyName;
1128 ImplFontAttrs nType = ImplFontAttrs::None;
1129 FontWeight eWeight = WEIGHT_DONTKNOW;
1130 FontWidth eWidthType = WIDTH_DONTKNOW;
1131 OUString aMapName = GetEnglishSearchFontName( maFamilyName );
1133 utl::FontSubstConfiguration::getMapName( aMapName,
1134 aShortName, aFamilyName, eWeight, eWidthType, nType );
1136 // lookup the font name in the configuration
1137 const utl::FontNameAttr* pFontAttr = rFontSubst.getSubstInfo( aMapName );
1139 // if the direct lookup failed try again with an alias name
1140 if ( !pFontAttr && (aShortName != aMapName) )
1141 pFontAttr = rFontSubst.getSubstInfo( aShortName );
1143 if( pFontAttr )
1145 // the font was found in the configuration
1146 if( meFamily == FAMILY_DONTKNOW )
1148 if ( pFontAttr->Type & ImplFontAttrs::Serif )
1149 meFamily = FAMILY_ROMAN;
1150 else if ( pFontAttr->Type & ImplFontAttrs::SansSerif )
1151 meFamily = FAMILY_SWISS;
1152 else if ( pFontAttr->Type & ImplFontAttrs::Typewriter )
1153 meFamily = FAMILY_MODERN;
1154 else if ( pFontAttr->Type & ImplFontAttrs::Italic )
1155 meFamily = FAMILY_SCRIPT;
1156 else if ( pFontAttr->Type & ImplFontAttrs::Decorative )
1157 meFamily = FAMILY_DECORATIVE;
1160 if( mePitch == PITCH_DONTKNOW )
1162 if ( pFontAttr->Type & ImplFontAttrs::Fixed )
1163 mePitch = PITCH_FIXED;
1167 // if some attributes are still unknown then use the FontSubst magic
1168 if( meFamily == FAMILY_DONTKNOW )
1170 if( nType & ImplFontAttrs::Serif )
1171 meFamily = FAMILY_ROMAN;
1172 else if( nType & ImplFontAttrs::SansSerif )
1173 meFamily = FAMILY_SWISS;
1174 else if( nType & ImplFontAttrs::Typewriter )
1175 meFamily = FAMILY_MODERN;
1176 else if( nType & ImplFontAttrs::Italic )
1177 meFamily = FAMILY_SCRIPT;
1178 else if( nType & ImplFontAttrs::Decorative )
1179 meFamily = FAMILY_DECORATIVE;
1182 if( GetWeight() == WEIGHT_DONTKNOW )
1183 SetWeight( eWeight );
1184 if( meWidthType == WIDTH_DONTKNOW )
1185 meWidthType = eWidthType;
1188 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */