emfio/source/reader/mtftools.cxx | 20 +++++++++++++++++- include/vcl/font.hxx | 3 ++ vcl/inc/impfont.hxx | 21 ++++++++++++++++++- vcl/source/filter/wmf/emfwr.cxx | 27 ++++++++++++++++++++++-- vcl/source/font/font.cxx | 43 +++++++++++++++++++++++++++++++++++++-- 5 files changed, 108 insertions(+), 6 deletions(-)
New commits: commit 0ce79d8efd63a9fb64bae73dde2f5af266c2f9f9 Author: Armin Le Grand (Allotropia) <armin.le.gr...@me.com> AuthorDate: Tue Feb 16 18:20:32 2021 +0100 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Mon Feb 22 09:32:36 2021 +0100 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.gr...@me.com> (cherry picked from commit 9d161857f1d4afcb772b477455797a2da0e47a9b) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111147 Tested-by: Thorsten Behrens <thorsten.behr...@allotropia.de> Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de> diff --git a/emfio/source/reader/mtftools.cxx b/emfio/source/reader/mtftools.cxx index 89ca286a9501..b307a18ca1f7 100644 --- a/emfio/source/reader/mtftools.cxx +++ b/emfio/source/reader/mtftools.cxx @@ -295,8 +295,26 @@ namespace emfio // Convert height to positive aFontSize.setHeight( std::abs(aFontSize.Height()) ); - aFont.SetFontSize(aFontSize); + + // tdf#127471 adapt nFontWidth from Windows-like notation to + // NormedFontScaling if used for text scaling +#ifndef _WIN32 + const bool bFontScaledHorizontally(aFontSize.Width() != 0 && aFontSize.Width() != aFontSize.Height()); + + if(bFontScaledHorizontally) + { + // tdf#127471 nFontWidth is the Windows FontScaling, need to convert to + // Non-Windowslike notation relative to FontHeight. + const long nAverageFontWidth(aFont.GetOrCalculateAverageFontWidth()); + + if(nAverageFontWidth > 0) + { + const double fScaleFactor(static_cast<double>(aFontSize.Height()) / static_cast<double>(nAverageFontWidth)); + aFont.SetAverageFontWidth(static_cast<long>(static_cast<double>(aFontSize.Width()) * fScaleFactor)); + } + } +#endif }; Color MtfTools::ReadColor() diff --git a/include/vcl/font.hxx b/include/vcl/font.hxx index 2dc0a5b326cd..abc41584f40a 100644 --- a/include/vcl/font.hxx +++ b/include/vcl/font.hxx @@ -111,6 +111,9 @@ public: void SetAverageFontWidth( long nWidth ); long GetAverageFontWidth() const; + // tdf#127471 for corrections on EMF/WMF we need the AvgFontWidth in Windows-specific notation + long GetOrCalculateAverageFontWidth() const; + // Prefer LanguageTag over LanguageType void SetLanguageTag( const LanguageTag & ); const LanguageTag& GetLanguageTag() const; diff --git a/vcl/inc/impfont.hxx b/vcl/inc/impfont.hxx index d2933b63a5f0..af9e462a513b 100644 --- a/vcl/inc/impfont.hxx +++ b/vcl/inc/impfont.hxx @@ -60,7 +60,18 @@ public: void SetWidthType( const FontWidth eWidthType ) { meWidthType = eWidthType; } void SetAlignment( const TextAlign eAlignment ) { meAlign = eAlignment; } void SetCharSet( const rtl_TextEncoding eCharSet ) { meCharSet = eCharSet; } - void SetFontSize( const Size& rSize ) { maAverageFontSize = rSize; } + void SetFontSize( const Size& rSize ) + { +#ifndef _WIN32 + if(rSize.Height() != maAverageFontSize.Height()) + { + // reset evtl. buffered calculated AverageFontSize, it depends + // on Font::Height + mnCalculatedAverageFontWidth = 0; + } +#endif + maAverageFontSize = rSize; + } void SetSymbolFlag( const bool bSymbolFlag ) { mbSymbolFlag = bSymbolFlag; } @@ -79,6 +90,11 @@ public: void DecreaseQualityBy( int nQualityAmount ) { mnQuality -= nQualityAmount; } void SetMapNames( OUString const & aMapNames ) { maMapNames = aMapNames; } +#ifndef _WIN32 + long GetCalculatedAverageFontWidth() const { return mnCalculatedAverageFontWidth; } + void SetCalculatedAverageFontWidth(long nNew) { mnCalculatedAverageFontWidth = nNew; } +#endif + bool operator==( const ImplFont& ) const; private: @@ -130,6 +146,9 @@ private: int mnQuality; +#ifndef _WIN32 + long mnCalculatedAverageFontWidth; +#endif }; #endif // INCLUDED_VCL_INC_IMPFONT_HXX diff --git a/vcl/source/filter/wmf/emfwr.cxx b/vcl/source/filter/wmf/emfwr.cxx index ed02add407cc..a6f2f149dca0 100644 --- a/vcl/source/filter/wmf/emfwr.cxx +++ b/vcl/source/filter/wmf/emfwr.cxx @@ -457,10 +457,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 long nFontHeight(rFont.GetFontSize().Height()); + 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 long nAverageFontWidth(rFont.GetOrCalculateAverageFontWidth()); + + if(nAverageFontWidth > 0) + { + const double fScaleFactor(static_cast<double>(nAverageFontWidth) / static_cast<double>(nFontHeight)); + nFontWidth = static_cast<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() ).WriteInt32( rFont.GetOrientation() ); switch( rFont.GetWeight() ) diff --git a/vcl/source/font/font.cxx b/vcl/source/font/font.cxx index be5fa5e1c719..4ea1a19612cf 100644 --- a/vcl/source/font/font.cxx +++ b/vcl/source/font/font.cxx @@ -37,8 +37,8 @@ #ifdef _WIN32 #include <vcl/metric.hxx> -#include <vcl/outdev.hxx> -#include <vcl/svapp.hxx> +#else +#include <vcl/virdev.hxx> #endif using namespace vcl; @@ -364,6 +364,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 +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, long& rnNormedFontScaling ) { VersionCompat aCompat( rIStm, StreamMode::READ ); @@ -849,6 +882,9 @@ ImplFont::ImplFont() : mbWordLine( false ), mnOrientation( 0 ), mnQuality( 0 ) +#ifndef _WIN32 + , mnCalculatedAverageFontWidth(0) +#endif {} ImplFont::ImplFont( const ImplFont& rImplFont ) : @@ -882,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 _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits