1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <tools/stream.hxx>
21 #include <tools/vcompat.hxx>
22 #include <tools/gen.hxx>
23 #include <unotools/fontcfg.hxx>
24 #include <unotools/fontdefs.hxx>
26 #include <vcl/font.hxx>
28 #include <impfont.hxx>
29 #include <fontattributes.hxx>
34 #include <rtl/instance.hxx>
35 #include <TypeSerializer.hxx>
36 #include <vcl/svapp.hxx>
39 #include <vcl/metric.hxx>
41 #include <vcl/virdev.hxx>
48 struct theGlobalDefault
:
49 public rtl::Static
< Font::ImplType
, theGlobalDefault
> {};
52 Font::Font() : mpImplFont(theGlobalDefault::get())
56 Font::Font( const vcl::Font
& rFont
) : mpImplFont( rFont
.mpImplFont
)
60 Font::Font( vcl::Font
&& rFont
) noexcept
: mpImplFont( std::move(rFont
.mpImplFont
) )
64 Font::Font( const OUString
& rFamilyName
, const Size
& rSize
) : mpImplFont()
66 mpImplFont
->SetFamilyName( rFamilyName
);
67 mpImplFont
->SetFontSize( rSize
);
70 Font::Font( const OUString
& rFamilyName
, const OUString
& rStyleName
, const Size
& rSize
) : mpImplFont()
72 mpImplFont
->SetFamilyName( rFamilyName
);
73 mpImplFont
->SetStyleName( rStyleName
);
74 mpImplFont
->SetFontSize( rSize
);
77 Font::Font( FontFamily eFamily
, const Size
& rSize
) : mpImplFont()
79 mpImplFont
->SetFamilyType( eFamily
);
80 mpImplFont
->SetFontSize( rSize
);
87 void Font::SetColor( const Color
& rColor
)
89 if (const_cast<const ImplType
&>(mpImplFont
)->maColor
!= rColor
)
91 mpImplFont
->maColor
= rColor
;
95 void Font::SetFillColor( const Color
& rColor
)
97 mpImplFont
->maFillColor
= rColor
;
98 if ( rColor
.GetTransparency() )
99 mpImplFont
->mbTransparent
= true;
102 void Font::SetTransparent( bool bTransparent
)
104 if (const_cast<const ImplType
&>(mpImplFont
)->mbTransparent
!= bTransparent
)
105 mpImplFont
->mbTransparent
= bTransparent
;
108 void Font::SetAlignment( FontAlign eAlign
)
110 if (const_cast<const ImplType
&>(mpImplFont
)->meAlign
!= eAlign
)
111 mpImplFont
->SetAlignment(eAlign
);
114 void Font::SetFamilyName( const OUString
& rFamilyName
)
116 mpImplFont
->SetFamilyName( rFamilyName
);
119 void Font::SetStyleName( const OUString
& rStyleName
)
121 mpImplFont
->maStyleName
= rStyleName
;
124 void Font::SetFontSize( const Size
& rSize
)
126 if (const_cast<const ImplType
&>(mpImplFont
)->GetFontSize() != rSize
)
127 mpImplFont
->SetFontSize( rSize
);
130 void Font::SetFamily( FontFamily eFamily
)
132 if (const_cast<const ImplType
&>(mpImplFont
)->GetFamilyTypeNoAsk() != eFamily
)
133 mpImplFont
->SetFamilyType( eFamily
);
136 void Font::SetCharSet( rtl_TextEncoding eCharSet
)
138 if (const_cast<const ImplType
&>(mpImplFont
)->GetCharSet() != eCharSet
)
140 mpImplFont
->SetCharSet( eCharSet
);
142 if ( eCharSet
== RTL_TEXTENCODING_SYMBOL
)
143 mpImplFont
->SetSymbolFlag( true );
145 mpImplFont
->SetSymbolFlag( false );
149 bool Font::IsSymbolFont() const
151 return mpImplFont
->IsSymbolFont();
154 void Font::SetSymbolFlag( bool bSymbol
)
156 mpImplFont
->SetSymbolFlag( bSymbol
);
158 if ( IsSymbolFont() )
160 mpImplFont
->SetCharSet( RTL_TEXTENCODING_SYMBOL
);
164 if ( mpImplFont
->GetCharSet() == RTL_TEXTENCODING_SYMBOL
)
165 mpImplFont
->SetCharSet( RTL_TEXTENCODING_DONTKNOW
);
169 void Font::SetLanguageTag( const LanguageTag
& rLanguageTag
)
171 if (const_cast<const ImplType
&>(mpImplFont
)->maLanguageTag
!= rLanguageTag
)
172 mpImplFont
->maLanguageTag
= rLanguageTag
;
175 void Font::SetCJKContextLanguageTag( const LanguageTag
& rLanguageTag
)
177 if (const_cast<const ImplType
&>(mpImplFont
)->maCJKLanguageTag
!= rLanguageTag
)
178 mpImplFont
->maCJKLanguageTag
= rLanguageTag
;
181 void Font::SetLanguage( LanguageType eLanguage
)
183 if (const_cast<const ImplType
&>(mpImplFont
)->maLanguageTag
.getLanguageType(false) != eLanguage
)
184 mpImplFont
->maLanguageTag
.reset( eLanguage
);
187 void Font::SetCJKContextLanguage( LanguageType eLanguage
)
189 if (const_cast<const ImplType
&>(mpImplFont
)->maCJKLanguageTag
.getLanguageType(false) != eLanguage
)
190 mpImplFont
->maCJKLanguageTag
.reset( eLanguage
);
193 void Font::SetPitch( FontPitch ePitch
)
195 if (const_cast<const ImplType
&>(mpImplFont
)->GetPitchNoAsk() != ePitch
)
196 mpImplFont
->SetPitch( ePitch
);
199 void Font::SetOrientation( Degree10 nOrientation
)
201 if (const_cast<const ImplType
&>(mpImplFont
)->mnOrientation
!= nOrientation
)
202 mpImplFont
->mnOrientation
= nOrientation
;
205 void Font::SetVertical( bool bVertical
)
207 if (const_cast<const ImplType
&>(mpImplFont
)->mbVertical
!= bVertical
)
208 mpImplFont
->mbVertical
= bVertical
;
211 void Font::SetKerning( FontKerning eKerning
)
213 if (const_cast<const ImplType
&>(mpImplFont
)->meKerning
!= eKerning
)
214 mpImplFont
->meKerning
= eKerning
;
217 bool Font::IsKerning() const
219 return mpImplFont
->meKerning
!= FontKerning::NONE
;
222 void Font::SetWeight( FontWeight eWeight
)
224 if (const_cast<const ImplType
&>(mpImplFont
)->GetWeightNoAsk() != eWeight
)
225 mpImplFont
->SetWeight( eWeight
);
228 void Font::SetWidthType( FontWidth eWidth
)
230 if (const_cast<const ImplType
&>(mpImplFont
)->GetWidthTypeNoAsk() != eWidth
)
231 mpImplFont
->SetWidthType( eWidth
);
234 void Font::SetItalic( FontItalic eItalic
)
236 if (const_cast<const ImplType
&>(mpImplFont
)->GetItalicNoAsk() != eItalic
)
237 mpImplFont
->SetItalic( eItalic
);
240 void Font::SetOutline( bool bOutline
)
242 if (const_cast<const ImplType
&>(mpImplFont
)->mbOutline
!= bOutline
)
243 mpImplFont
->mbOutline
= bOutline
;
246 void Font::SetShadow( bool bShadow
)
248 if (const_cast<const ImplType
&>(mpImplFont
)->mbShadow
!= bShadow
)
249 mpImplFont
->mbShadow
= bShadow
;
252 void Font::SetUnderline( FontLineStyle eUnderline
)
254 if (const_cast<const ImplType
&>(mpImplFont
)->meUnderline
!= eUnderline
)
255 mpImplFont
->meUnderline
= eUnderline
;
258 void Font::SetOverline( FontLineStyle eOverline
)
260 if (const_cast<const ImplType
&>(mpImplFont
)->meOverline
!= eOverline
)
261 mpImplFont
->meOverline
= eOverline
;
264 void Font::SetStrikeout( FontStrikeout eStrikeout
)
266 if (const_cast<const ImplType
&>(mpImplFont
)->meStrikeout
!= eStrikeout
)
267 mpImplFont
->meStrikeout
= eStrikeout
;
270 void Font::SetRelief( FontRelief eRelief
)
272 if (const_cast<const ImplType
&>(mpImplFont
)->meRelief
!= eRelief
)
273 mpImplFont
->meRelief
= eRelief
;
276 void Font::SetEmphasisMark( FontEmphasisMark eEmphasisMark
)
278 if (const_cast<const ImplType
&>(mpImplFont
)->meEmphasisMark
!= eEmphasisMark
)
279 mpImplFont
->meEmphasisMark
= eEmphasisMark
;
282 void Font::SetWordLineMode( bool bWordLine
)
284 if (const_cast<const ImplType
&>(mpImplFont
)->mbWordLine
!= bWordLine
)
285 mpImplFont
->mbWordLine
= bWordLine
;
288 Font
& Font::operator=( const vcl::Font
& rFont
)
290 mpImplFont
= rFont
.mpImplFont
;
294 Font
& Font::operator=( vcl::Font
&& rFont
) noexcept
296 mpImplFont
= std::move(rFont
.mpImplFont
);
300 bool Font::operator==( const vcl::Font
& rFont
) const
302 return mpImplFont
== rFont
.mpImplFont
;
305 void Font::Merge( const vcl::Font
& rFont
)
307 if ( !rFont
.GetFamilyName().isEmpty() )
309 SetFamilyName( rFont
.GetFamilyName() );
310 SetStyleName( rFont
.GetStyleName() );
311 SetCharSet( GetCharSet() );
312 SetLanguageTag( rFont
.GetLanguageTag() );
313 SetCJKContextLanguageTag( rFont
.GetCJKContextLanguageTag() );
314 // don't use access methods here, might lead to AskConfig(), if DONTKNOW
315 SetFamily( rFont
.mpImplFont
->GetFamilyTypeNoAsk() );
316 SetPitch( rFont
.mpImplFont
->GetPitchNoAsk() );
319 // don't use access methods here, might lead to AskConfig(), if DONTKNOW
320 if ( rFont
.mpImplFont
->GetWeightNoAsk() != WEIGHT_DONTKNOW
)
321 SetWeight( rFont
.GetWeight() );
322 if ( rFont
.mpImplFont
->GetItalicNoAsk() != ITALIC_DONTKNOW
)
323 SetItalic( rFont
.GetItalic() );
324 if ( rFont
.mpImplFont
->GetWidthTypeNoAsk() != WIDTH_DONTKNOW
)
325 SetWidthType( rFont
.GetWidthType() );
327 if ( rFont
.GetFontSize().Height() )
328 SetFontSize( rFont
.GetFontSize() );
329 if ( rFont
.GetUnderline() != LINESTYLE_DONTKNOW
)
331 SetUnderline( rFont
.GetUnderline() );
332 SetWordLineMode( rFont
.IsWordLineMode() );
334 if ( rFont
.GetOverline() != LINESTYLE_DONTKNOW
)
336 SetOverline( rFont
.GetOverline() );
337 SetWordLineMode( rFont
.IsWordLineMode() );
339 if ( rFont
.GetStrikeout() != STRIKEOUT_DONTKNOW
)
341 SetStrikeout( rFont
.GetStrikeout() );
342 SetWordLineMode( rFont
.IsWordLineMode() );
346 SetOrientation( rFont
.GetOrientation() );
347 SetVertical( rFont
.IsVertical() );
348 SetEmphasisMark( rFont
.GetEmphasisMark() );
349 SetKerning( rFont
.IsKerning() ? FontKerning::FontSpecific
: FontKerning::NONE
);
350 SetOutline( rFont
.IsOutline() );
351 SetShadow( rFont
.IsShadow() );
352 SetRelief( rFont
.GetRelief() );
355 void Font::GetFontAttributes( FontAttributes
& rAttrs
) const
357 rAttrs
.SetFamilyName( mpImplFont
->GetFamilyName() );
358 rAttrs
.SetStyleName( mpImplFont
->maStyleName
);
359 rAttrs
.SetFamilyType( mpImplFont
->GetFamilyTypeNoAsk() );
360 rAttrs
.SetPitch( mpImplFont
->GetPitchNoAsk() );
361 rAttrs
.SetItalic( mpImplFont
->GetItalicNoAsk() );
362 rAttrs
.SetWeight( mpImplFont
->GetWeightNoAsk() );
363 rAttrs
.SetWidthType( WIDTH_DONTKNOW
);
364 rAttrs
.SetSymbolFlag( mpImplFont
->GetCharSet() == RTL_TEXTENCODING_SYMBOL
);
367 // tdf#127471 for corrections on EMF/WMF we need the AvgFontWidth in Windows-specific notation
368 tools::Long
Font::GetOrCalculateAverageFontWidth() const
370 if(0 == mpImplFont
->GetCalculatedAverageFontWidth())
372 // VirtualDevice is not thread safe
373 SolarMutexGuard aGuard
;
375 // create unscaled copy of font (this), a VirtualDevice and set it there
376 vcl::Font
aUnscaledFont(*this);
377 ScopedVclPtr
<VirtualDevice
> pTempVirtualDevice(VclPtr
<VirtualDevice
>::Create());
378 aUnscaledFont
.SetAverageFontWidth(0);
379 pTempVirtualDevice
->SetFont(aUnscaledFont
);
382 // on Windows systems use FontMetric to get/create AverageFontWidth from system
383 const FontMetric
aMetric(pTempVirtualDevice
->GetFontMetric());
384 const_cast<Font
*>(this)->mpImplFont
->SetCalculatedAverageFontWidth(aMetric
.GetAverageFontWidth());
386 // On non-Windows systems we need to calculate AvgFontWidth
387 // as close as possible (discussion see documentation in task),
388 // so calculate it. For discussion of method used, see task
389 // buffer measure string creation, will always use the same
390 static OUString aMeasureString
;
392 if(!aMeasureString
.getLength())
394 const std::size_t nSize(127 - 32);
395 std::array
<sal_Unicode
, nSize
> aArray
;
397 for(sal_Unicode
a(0); a
< nSize
; a
++)
402 aMeasureString
= OUString(aArray
.data());
405 const double fAverageFontWidth(
406 pTempVirtualDevice
->GetTextWidth(aMeasureString
, 0, aMeasureString
.getLength()) /
407 static_cast<double>(aMeasureString
.getLength()));
408 const_cast<Font
*>(this)->mpImplFont
->SetCalculatedAverageFontWidth(basegfx::fround(fAverageFontWidth
));
412 return mpImplFont
->GetCalculatedAverageFontWidth();
415 SvStream
& ReadImplFont( SvStream
& rIStm
, ImplFont
& rImplFont
, tools::Long
& rnNormedFontScaling
)
417 VersionCompat
aCompat( rIStm
, StreamMode::READ
);
418 sal_uInt16
nTmp16(0);
419 sal_Int16
nTmps16(0);
423 rImplFont
.SetFamilyName( rIStm
.ReadUniOrByteString(rIStm
.GetStreamCharSet()) );
424 rImplFont
.maStyleName
= rIStm
.ReadUniOrByteString(rIStm
.GetStreamCharSet());
425 TypeSerializer
aSerializer(rIStm
);
426 aSerializer
.readSize(rImplFont
.maAverageFontSize
);
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
);
438 rIStm
.ReadInt16( nTmps16
); rImplFont
.mnOrientation
= Degree10(nTmps16
);
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
);
445 if( aCompat
.GetVersion() >= 2 )
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
);
453 if( aCompat
.GetVersion() >= 3 )
455 rIStm
.ReadUInt16( nTmp16
); rImplFont
.meOverline
= static_cast<FontLineStyle
>(nTmp16
);
458 // tdf#127471 read NormedFontScaling
459 if( aCompat
.GetVersion() >= 4 )
461 sal_Int32
nNormedFontScaling(0);
462 rIStm
.ReadInt32(nNormedFontScaling
);
463 rnNormedFontScaling
= nNormedFontScaling
;
467 // CJKContextLanguage
472 SvStream
& WriteImplFont( SvStream
& rOStm
, const ImplFont
& rImplFont
, const tools::Long
& rnNormedFontScaling
)
474 // tdf#127471 increase to version 4
475 VersionCompat
aCompat( rOStm
, StreamMode::WRITE
, 4 );
477 TypeSerializer
aSerializer(rOStm
);
478 rOStm
.WriteUniOrByteString( rImplFont
.GetFamilyName(), rOStm
.GetStreamCharSet() );
479 rOStm
.WriteUniOrByteString( rImplFont
.GetStyleName(), rOStm
.GetStreamCharSet() );
480 aSerializer
.writeSize(rImplFont
.maAverageFontSize
);
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() );
492 rOStm
.WriteInt16( rImplFont
.mnOrientation
.get() );
494 rOStm
.WriteBool( rImplFont
.mbWordLine
);
495 rOStm
.WriteBool( rImplFont
.mbOutline
);
496 rOStm
.WriteBool( rImplFont
.mbShadow
);
497 rOStm
.WriteUChar( static_cast<sal_uInt8
>(rImplFont
.meKerning
) );
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
) );
506 rOStm
.WriteUInt16( rImplFont
.meOverline
);
508 // new in version 4, NormedFontScaling
509 rOStm
.WriteInt32(rnNormedFontScaling
);
514 SvStream
& ReadFont( SvStream
& rIStm
, vcl::Font
& rFont
)
516 // tdf#127471 try to read NormedFontScaling
517 tools::Long
nNormedFontScaling(0);
518 SvStream
& rRetval(ReadImplFont( rIStm
, *rFont
.mpImplFont
, nNormedFontScaling
));
520 if (nNormedFontScaling
> 0)
523 // we run on windows and a NormedFontScaling was written
524 if(rFont
.GetFontSize().getWidth() == nNormedFontScaling
)
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);
533 vcl::Font
aUnscaledFont(rFont
);
534 aUnscaledFont
.SetAverageFontWidth(0);
535 const FontMetric
aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aUnscaledFont
));
539 const double fScaleFactor(static_cast<double>(nNormedFontScaling
) / static_cast<double>(nHeight
));
540 nScaledWidth
= basegfx::fround(static_cast<double>(aUnscaledFontMetric
.GetAverageFontWidth()) * fScaleFactor
);
544 rFont
.SetAverageFontWidth(nScaledWidth
);
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 plausability reasons
554 // we do not run on windows and a NormedFontScaling was written
555 if(rFont
.GetFontSize().getWidth() == nNormedFontScaling
)
557 // the writing producer was not on a windows system, correct value
558 // already set, nothing to do
562 // the writing producer was on a windows system, correct FontScvaling.
563 // The correct non-pre-multiplied value is the 2nd one, use it
564 rFont
.SetAverageFontWidth(nNormedFontScaling
);
572 SvStream
& WriteFont( SvStream
& rOStm
, const vcl::Font
& rFont
)
574 // tdf#127471 prepare NormedFontScaling for additional export
575 tools::Long
nNormedFontScaling(rFont
.GetFontSize().getWidth());
577 // FontScaling usage at vcl-Font is detected by checking that FontWidth != 0
578 if (nNormedFontScaling
> 0)
580 const tools::Long
nHeight(std::max
<tools::Long
>(rFont
.GetFontSize().getHeight(), 0));
582 // check for negative height
585 nNormedFontScaling
= 0;
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
));
598 if (aUnscaledFontMetric
.GetAverageFontWidth() > 0)
600 const double fScaleFactor(
601 static_cast<double>(nNormedFontScaling
)
602 / static_cast<double>(aUnscaledFontMetric
.GetAverageFontWidth()));
603 nNormedFontScaling
= static_cast<tools::Long
>(fScaleFactor
* nHeight
);
609 return WriteImplFont( rOStm
, *rFont
.mpImplFont
, nNormedFontScaling
);
614 bool identifyTrueTypeFont( const void* i_pBuffer
, sal_uInt32 i_nSize
, Font
& o_rResult
)
616 bool bResult
= false;
617 TrueTypeFont
* pTTF
= nullptr;
618 if( OpenTTFontBuffer( i_pBuffer
, i_nSize
, 0, &pTTF
) == SFErrCodes::Ok
)
620 TTGlobalFontInfo aInfo
;
621 GetTTGlobalFontInfo( pTTF
, &aInfo
);
622 // most importantly: the family name
624 o_rResult
.SetFamilyName( OUString(aInfo
.ufamily
) );
625 else if( aInfo
.family
)
626 o_rResult
.SetFamilyName( OStringToOUString( aInfo
.family
, RTL_TEXTENCODING_ASCII_US
) );
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
);
647 o_rResult
.SetWeight( WEIGHT_BLACK
);
650 o_rResult
.SetWeight( (aInfo
.macStyle
& 1) ? WEIGHT_BOLD
: WEIGHT_NORMAL
);
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
);
674 o_rResult
.SetItalic( (aInfo
.italicAngle
!= 0) ? ITALIC_NORMAL
: ITALIC_NONE
);
677 o_rResult
.SetPitch( (aInfo
.pitch
== 0) ? PITCH_VARIABLE
: PITCH_FIXED
);
680 if( aInfo
.usubfamily
)
681 o_rResult
.SetStyleName( OUString( aInfo
.usubfamily
) );
682 else if( aInfo
.subfamily
)
683 o_rResult
.SetStyleName( OUString::createFromAscii( aInfo
.subfamily
) );
693 struct WeightSearchEntry
699 bool operator<( const WeightSearchEntry
& rRight
) const
701 return rtl_str_compareIgnoreAsciiCase_WithLength( string
, string_len
, rRight
.string
, rRight
.string_len
) < 0;
704 const weight_table
[] =
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
}
718 bool identifyType1Font( const char* i_pBuffer
, sal_uInt32 i_nSize
, Font
& o_rResult
)
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
)
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
)
731 // extract the string value behind /FamilyName
732 const char* pOpen
= pFamPos
+11;
733 while( pOpen
< pExecPos
&& *pOpen
!= '(' )
735 const char* pClose
= pOpen
;
736 while( pClose
< pExecPos
&& *pClose
!= ')' )
738 if( pClose
- pOpen
> 1 )
740 o_rResult
.SetFamilyName( OStringToOUString( OString( pOpen
+1, pClose
-pOpen
-1 ), RTL_TEXTENCODING_ASCII_US
) );
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
)
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
);
755 static const char* const pWeight
= "/Weight";
756 const char* pWeightPos
= std::search( pStream
, pExecPos
, pWeight
, pWeight
+7 );
757 if( pWeightPos
!= pExecPos
)
759 // extract the string value behind /Weight
760 const char* pOpen
= pWeightPos
+7;
761 while( pOpen
< pExecPos
&& *pOpen
!= '(' )
763 const char* pClose
= pOpen
;
764 while( pClose
< pExecPos
&& *pClose
!= ')' )
766 if( pClose
- pOpen
> 1 )
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
);
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
)
785 while( pFixedPos
< pExecPos
-4 &&
786 ( *pFixedPos
== ' ' ||
787 *pFixedPos
== '\t' ||
788 *pFixedPos
== '\r' ||
789 *pFixedPos
== '\n' ) )
794 if( rtl_str_compareIgnoreAsciiCase_WithLength( pFixedPos
, 4, "true", 4 ) == 0 )
795 o_rResult
.SetPitch( PITCH_FIXED
);
797 o_rResult
.SetPitch( PITCH_VARIABLE
);
804 Font
Font::identifyFont( const void* i_pBuffer
, sal_uInt32 i_nSize
)
807 if( ! identifyTrueTypeFont( i_pBuffer
, i_nSize
, aResult
) )
809 const char* pStream
= static_cast<const char*>(i_pBuffer
);
810 if( pStream
&& i_nSize
> 100 &&
811 *pStream
== '%' && pStream
[1] == '!' )
813 identifyType1Font( pStream
, i_nSize
, aResult
);
820 // The inlines from the font.hxx header are now instantiated for pImpl-ification
821 const Color
& Font::GetColor() const { return mpImplFont
->maColor
; }
822 const Color
& Font::GetFillColor() const { return mpImplFont
->maFillColor
; }
823 bool Font::IsTransparent() const { return mpImplFont
->mbTransparent
; }
825 FontAlign
Font::GetAlignment() const { return mpImplFont
->GetAlignment(); }
827 const OUString
& Font::GetFamilyName() const { return mpImplFont
->GetFamilyName(); }
828 const OUString
& Font::GetStyleName() const { return mpImplFont
->maStyleName
; }
830 const Size
& Font::GetFontSize() const { return mpImplFont
->GetFontSize(); }
831 void Font::SetFontHeight( tools::Long nHeight
) { SetFontSize( Size( mpImplFont
->GetFontSize().Width(), nHeight
) ); }
832 tools::Long
Font::GetFontHeight() const { return mpImplFont
->GetFontSize().Height(); }
833 void Font::SetAverageFontWidth( tools::Long nWidth
) { SetFontSize( Size( nWidth
, mpImplFont
->GetFontSize().Height() ) ); }
834 tools::Long
Font::GetAverageFontWidth() const { return mpImplFont
->GetFontSize().Width(); }
836 rtl_TextEncoding
Font::GetCharSet() const { return mpImplFont
->GetCharSet(); }
838 const LanguageTag
& Font::GetLanguageTag() const { return mpImplFont
->maLanguageTag
; }
839 const LanguageTag
& Font::GetCJKContextLanguageTag() const { return mpImplFont
->maCJKLanguageTag
; }
840 LanguageType
Font::GetLanguage() const { return mpImplFont
->maLanguageTag
.getLanguageType( false); }
841 LanguageType
Font::GetCJKContextLanguage() const { return mpImplFont
->maCJKLanguageTag
.getLanguageType( false); }
843 Degree10
Font::GetOrientation() const { return mpImplFont
->mnOrientation
; }
844 bool Font::IsVertical() const { return mpImplFont
->mbVertical
; }
845 FontKerning
Font::GetKerning() const { return mpImplFont
->meKerning
; }
847 FontPitch
Font::GetPitch() { return mpImplFont
->GetPitch(); }
848 FontWeight
Font::GetWeight() { return mpImplFont
->GetWeight(); }
849 FontWidth
Font::GetWidthType() { return mpImplFont
->GetWidthType(); }
850 FontItalic
Font::GetItalic() { return mpImplFont
->GetItalic(); }
851 FontFamily
Font::GetFamilyType() { return mpImplFont
->GetFamilyType(); }
853 FontPitch
Font::GetPitch() const { return mpImplFont
->GetPitchNoAsk(); }
854 FontWeight
Font::GetWeight() const { return mpImplFont
->GetWeightNoAsk(); }
855 FontWidth
Font::GetWidthType() const { return mpImplFont
->GetWidthTypeNoAsk(); }
856 FontItalic
Font::GetItalic() const { return mpImplFont
->GetItalicNoAsk(); }
857 FontFamily
Font::GetFamilyType() const { return mpImplFont
->GetFamilyTypeNoAsk(); }
859 int Font::GetQuality() const { return mpImplFont
->GetQuality(); }
860 void Font::SetQuality( int nQuality
) { mpImplFont
->SetQuality( nQuality
); }
861 void Font::IncreaseQualityBy( int nQualityAmount
) { mpImplFont
->IncreaseQualityBy( nQualityAmount
); }
862 void Font::DecreaseQualityBy( int nQualityAmount
) { mpImplFont
->DecreaseQualityBy( nQualityAmount
); }
864 bool Font::IsOutline() const { return mpImplFont
->mbOutline
; }
865 bool Font::IsShadow() const { return mpImplFont
->mbShadow
; }
866 FontRelief
Font::GetRelief() const { return mpImplFont
->meRelief
; }
867 FontLineStyle
Font::GetUnderline() const { return mpImplFont
->meUnderline
; }
868 FontLineStyle
Font::GetOverline() const { return mpImplFont
->meOverline
; }
869 FontStrikeout
Font::GetStrikeout() const { return mpImplFont
->meStrikeout
; }
870 FontEmphasisMark
Font::GetEmphasisMark() const { return mpImplFont
->meEmphasisMark
; }
871 bool Font::IsWordLineMode() const { return mpImplFont
->mbWordLine
; }
872 bool Font::IsSameInstance( const vcl::Font
& rFont
) const { return (mpImplFont
== rFont
.mpImplFont
); }
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 ),
893 mbConfigLookup( false ),
896 mbTransparent( true ),
897 maColor( COL_TRANSPARENT
),
898 maFillColor( COL_TRANSPARENT
),
902 mnCalculatedAverageFontWidth( 0 )
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
)
938 bool ImplFont::operator==( const ImplFont
& rOther
) const
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
) )
947 if( (meCharSet
!= rOther
.meCharSet
)
948 || (maLanguageTag
!= rOther
.maLanguageTag
)
949 || (maCJKLanguageTag
!= rOther
.maCJKLanguageTag
)
950 || (meAlign
!= rOther
.meAlign
) )
953 if( (maAverageFontSize
!= rOther
.maAverageFontSize
)
954 || (mnOrientation
!= rOther
.mnOrientation
)
955 || (mbVertical
!= rOther
.mbVertical
) )
958 if( (maFamilyName
!= rOther
.maFamilyName
)
959 || (maStyleName
!= rOther
.maStyleName
) )
962 if( (maColor
!= rOther
.maColor
)
963 || (maFillColor
!= rOther
.maFillColor
) )
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
) )
981 void ImplFont::AskConfig()
986 mbConfigLookup
= true;
988 // prepare the FontSubst configuration lookup
989 const utl::FontSubstConfiguration
& rFontSubst
= utl::FontSubstConfiguration::get();
992 OUString aFamilyName
;
993 ImplFontAttrs nType
= ImplFontAttrs::None
;
994 FontWeight eWeight
= WEIGHT_DONTKNOW
;
995 FontWidth eWidthType
= WIDTH_DONTKNOW
;
996 OUString aMapName
= GetEnglishSearchFontName( maFamilyName
);
998 utl::FontSubstConfiguration::getMapName( aMapName
,
999 aShortName
, aFamilyName
, eWeight
, eWidthType
, nType
);
1001 // lookup the font name in the configuration
1002 const utl::FontNameAttr
* pFontAttr
= rFontSubst
.getSubstInfo( aMapName
);
1004 // if the direct lookup failed try again with an alias name
1005 if ( !pFontAttr
&& (aShortName
!= aMapName
) )
1006 pFontAttr
= rFontSubst
.getSubstInfo( aShortName
);
1010 // the font was found in the configuration
1011 if( meFamily
== FAMILY_DONTKNOW
)
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
;
1025 if( mePitch
== PITCH_DONTKNOW
)
1027 if ( pFontAttr
->Type
& ImplFontAttrs::Fixed
)
1028 mePitch
= PITCH_FIXED
;
1032 // if some attributes are still unknown then use the FontSubst magic
1033 if( meFamily
== FAMILY_DONTKNOW
)
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
;
1047 if( GetWeight() == WEIGHT_DONTKNOW
)
1048 SetWeight( eWeight
);
1049 if( meWidthType
== WIDTH_DONTKNOW
)
1050 meWidthType
= eWidthType
;
1053 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */