aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Le Grand (Allotropia) <armin.le.grand@me.com>2021-02-16 18:20:32 +0100
committerThorsten Behrens <thorsten.behrens@allotropia.de>2021-02-22 09:32:00 +0100
commit75d5db29f2ad2ff4f7944d47efc4ee001be7a1e7 (patch)
tree648f334825665a32858e3761ba0f21721bd89e0b
parent7d974de2ad79cccea69b1bd54eea3c72821e6b49 (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> (cherry picked from commit 9d161857f1d4afcb772b477455797a2da0e47a9b) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111148 Tested-by: Thorsten Behrens <thorsten.behrens@allotropia.de> Reviewed-by: Thorsten Behrens <thorsten.behrens@allotropia.de>
-rw-r--r--emfio/source/reader/mtftools.cxx20
-rw-r--r--include/vcl/font.hxx3
-rw-r--r--vcl/inc/impfont.hxx21
-rw-r--r--vcl/source/filter/wmf/emfwr.cxx27
-rw-r--r--vcl/source/font/font.cxx43
5 files changed, 108 insertions, 6 deletions
diff --git a/emfio/source/reader/mtftools.cxx b/emfio/source/reader/mtftools.cxx
index 4de2dd4c1fe2..3053d3878e13 100644
--- a/emfio/source/reader/mtftools.cxx
+++ b/emfio/source/reader/mtftools.cxx
@@ -296,8 +296,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 ac8c6d4c2153..53630b30e1dc 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 5e7e75a69246..624707839f40 100644
--- a/vcl/inc/impfont.hxx
+++ b/vcl/inc/impfont.hxx
@@ -62,7 +62,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; }
@@ -80,6 +91,11 @@ public:
void IncreaseQualityBy( int nQualityAmount ) { mnQuality += nQualityAmount; }
void DecreaseQualityBy( int nQualityAmount ) { mnQuality -= nQualityAmount; }
+#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 0204999672dc..58f0e550a9ae 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 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 87514537425d..2ac9a032bb30 100644
--- a/vcl/source/font/font.cxx
+++ b/vcl/source/font/font.cxx
@@ -36,8 +36,8 @@
#ifdef _WIN32
#include <vcl/metric.hxx>
-#include <vcl/outdev.hxx>
-#include <vcl/svapp.hxx>
+#else
+#include <vcl/virdev.hxx>
#endif
using namespace vcl;
@@ -363,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
+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 ) :
@@ -881,6 +917,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