diff options
author | Armin Le Grand (Allotropia) <armin.le.grand@me.com> | 2021-02-16 18:20:32 +0100 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@me.com> | 2021-03-10 09:41:39 +0100 |
commit | 125efab4d8573fda1882a542f6fb669c7fc12b56 (patch) | |
tree | 8659bc4e9f637e269986c5e2b6f96c1e9d9146fe /vcl/source | |
parent | c4dddad19640dfefde52d04c3a7cf7064afe05b5 (diff) |
tdf#127471 correct EMF/WMF im/export for scaled font
If FontScaling is used, system-dependent data is held at
vcl::Font Width(). Already if not scaled, we have three
definitions: Width is zero, Width is equal to Height (unx)
or - on Windows - Width equals avgFontWidth.
If used it is W!=H where on unx Width equals Height multiplied
with the scale factor. On Windows, this is Width multiplied
with the only there existing avgFontWidth.
Unfortunately that is ex/imported (since ever) undetected
to EMF/WMF thus making EMF/WMF files containing FontScaling
system-dependent - on which system was LO running when
creating the file? The error can be seen when loading such
a EMF/WMF on the vice-versa system, the FontScale is very
ugly and wrong.
Since EMF/WMF *are* Windows-specific formats the Windows-like
definition is the correct one. This change makes all other
systems export that now, and adapt on import to their system-
specific definition (assuming coming from Windows).
As can be seen, the difficulty is that these adaptions are
necessary on non-Windows plattforms, but these do not have
that avgFontWidth available. Thus I made a deep-dive
investigation and multiple experiments to create a as
similar as possible value to apply the needed calculations.
For details and discussion refer to the bug description.
Change-Id: I983fb6d882e2e8fccf9c8460f01509201d8157f9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111000
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112089
Diffstat (limited to 'vcl/source')
-rw-r--r-- | vcl/source/filter/wmf/emfwr.cxx | 27 | ||||
-rw-r--r-- | vcl/source/font/font.cxx | 41 |
2 files changed, 66 insertions, 2 deletions
diff --git a/vcl/source/filter/wmf/emfwr.cxx b/vcl/source/filter/wmf/emfwr.cxx index b2d692e339dd..51e24469e3d7 100644 --- a/vcl/source/filter/wmf/emfwr.cxx +++ b/vcl/source/filter/wmf/emfwr.cxx @@ -459,10 +459,33 @@ void EMFWriter::ImplCheckTextAttr() sal_uInt16 i; sal_uInt8 nPitchAndFamily; + // tdf#127471 adapt nFontWidth from NormedFontScaling to + // Windows-like notation if used for text scaling + const tools::Long nFontHeight(rFont.GetFontSize().Height()); + tools::Long nFontWidth(rFont.GetFontSize().Width()); + +#ifndef _WIN32 + const bool bFontScaledHorizontally(nFontWidth != 0 && nFontWidth != nFontHeight); + + if(bFontScaledHorizontally) + { + // tdf#127471 nFontWidth is the non-Windows NormedFontScaling, need to convert to + // Windows-like notation with pre-multiplied AvgFontWidth since EMF/WMF are Windows + // specific formats. + const tools::Long nAverageFontWidth(rFont.GetOrCalculateAverageFontWidth()); + + if(nAverageFontWidth > 0) + { + const double fScaleFactor(static_cast<double>(nAverageFontWidth) / static_cast<double>(nFontHeight)); + nFontWidth = static_cast<tools::Long>(static_cast<double>(nFontWidth) * fScaleFactor); + } + } +#endif + ImplBeginRecord( WIN_EMR_EXTCREATEFONTINDIRECTW ); m_rStm.WriteUInt32( mnTextHandle ); - ImplWriteExtent( -rFont.GetFontSize().Height() ); - ImplWriteExtent( rFont.GetFontSize().Width() ); + ImplWriteExtent( -nFontHeight ); + ImplWriteExtent( nFontWidth ); m_rStm.WriteInt32( rFont.GetOrientation().get() ).WriteInt32( rFont.GetOrientation().get() ); switch( rFont.GetWeight() ) diff --git a/vcl/source/font/font.cxx b/vcl/source/font/font.cxx index 180f5bbf122b..4017a5347e75 100644 --- a/vcl/source/font/font.cxx +++ b/vcl/source/font/font.cxx @@ -36,6 +36,8 @@ #ifdef _WIN32 #include <vcl/metric.hxx> +#else +#include <vcl/virdev.hxx> #endif using namespace vcl; @@ -361,6 +363,39 @@ void Font::GetFontAttributes( FontAttributes& rAttrs ) const rAttrs.SetSymbolFlag( mpImplFont->GetCharSet() == RTL_TEXTENCODING_SYMBOL ); } +// tdf#127471 for corrections on EMF/WMF we need the AvgFontWidth in Windows-specific notation +tools::Long Font::GetOrCalculateAverageFontWidth() const +{ +#ifdef _WIN32 + // on windows we just have it available + return GetAverageFontWidth(); +#else + // On non-Windows systems we need to calculate AvgFontWidth + // as close as possible (discussion see documentation in task) + if(0 == mpImplFont->GetCalculatedAverageFontWidth()) + { + // calculate it. For discussion of method used, see task + const std::size_t nSize(127 - 32); + std::array<sal_Unicode, nSize> aArray; + + for(sal_Unicode a(0); a < nSize; a++) + { + aArray[a] = a + 32; + } + + vcl::Font aUnscaledFont(*this); + ScopedVclPtr<VirtualDevice> pVirDev(VclPtr<VirtualDevice>::Create()); + aUnscaledFont.SetAverageFontWidth(0); + pVirDev->SetFont(aUnscaledFont); + const double fAverageFontWidth( + pVirDev->GetTextWidth(OUString(aArray.data())) / static_cast<double>(nSize)); + const_cast<Font*>(this)->mpImplFont->SetCalculatedAverageFontWidth(basegfx::fround(fAverageFontWidth)); + } + + return mpImplFont->GetCalculatedAverageFontWidth(); +#endif +} + SvStream& ReadImplFont( SvStream& rIStm, ImplFont& rImplFont, tools::Long& rnNormedFontScaling ) { VersionCompat aCompat( rIStm, StreamMode::READ ); @@ -848,6 +883,9 @@ ImplFont::ImplFont() : mbWordLine( false ), mnOrientation( 0 ), mnQuality( 0 ) +#ifndef _WIN32 + , mnCalculatedAverageFontWidth(0) +#endif {} ImplFont::ImplFont( const ImplFont& rImplFont ) : @@ -880,6 +918,9 @@ ImplFont::ImplFont( const ImplFont& rImplFont ) : mbWordLine( rImplFont.mbWordLine ), mnOrientation( rImplFont.mnOrientation ), mnQuality( rImplFont.mnQuality ) +#ifndef _WIN32 + , mnCalculatedAverageFontWidth(rImplFont.mnCalculatedAverageFontWidth) +#endif {} bool ImplFont::operator==( const ImplFont& rOther ) const |