[Libreoffice-commits] core.git: emfio/source include/vcl vcl/inc vcl/source

Armin Le Grand (Allotropia) (via logerrit) logerrit at kemper.freedesktop.org
Wed Feb 17 08:31:48 UTC 2021


 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 9d161857f1d4afcb772b477455797a2da0e47a9b
Author:     Armin Le Grand (Allotropia) <armin.le.grand at me.com>
AuthorDate: Tue Feb 16 18:20:32 2021 +0100
Commit:     Armin Le Grand <Armin.Le.Grand at me.com>
CommitDate: Wed Feb 17 09:31:09 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.Grand at me.com>

diff --git a/emfio/source/reader/mtftools.cxx b/emfio/source/reader/mtftools.cxx
index b05beeb2a9dc..6064ca937a16 100644
--- a/emfio/source/reader/mtftools.cxx
+++ b/emfio/source/reader/mtftools.cxx
@@ -277,8 +277,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 tools::Long nAverageFontWidth(aFont.GetOrCalculateAverageFontWidth());
+
+            if(nAverageFontWidth > 0)
+            {
+                const double fScaleFactor(static_cast<double>(aFontSize.Height()) / static_cast<double>(nAverageFontWidth));
+                aFont.SetAverageFontWidth(static_cast<tools::Long>(static_cast<double>(aFontSize.Width()) * fScaleFactor));
+            }
+        }
+#endif
     };
 
     Color MtfTools::ReadColor()
diff --git a/include/vcl/font.hxx b/include/vcl/font.hxx
index 2d437c5b3da0..3147f57aba14 100644
--- a/include/vcl/font.hxx
+++ b/include/vcl/font.hxx
@@ -113,6 +113,9 @@ public:
     void                SetAverageFontWidth( tools::Long nWidth );
     tools::Long                GetAverageFontWidth() const;
 
+    // tdf#127471 for corrections on EMF/WMF we need the AvgFontWidth in Windows-specific notation
+    tools::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 ba1ea3683926..14a2189d3921 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
+    tools::Long         GetCalculatedAverageFontWidth() const           { return mnCalculatedAverageFontWidth; }
+    void                SetCalculatedAverageFontWidth(tools::Long nNew) { mnCalculatedAverageFontWidth = nNew; }
+#endif
+
     bool                operator==( const ImplFont& ) const;
 
 private:
@@ -130,6 +146,9 @@ private:
 
     int                 mnQuality;
 
+#ifndef _WIN32
+    tools::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 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 b4f685e63967..67fc3e7bc633 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
+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 )
 {
     VersionCompatRead aCompat( rIStm );
@@ -851,6 +884,9 @@ ImplFont::ImplFont() :
     mbWordLine( false ),
     mnOrientation( 0 ),
     mnQuality( 0 )
+#ifndef _WIN32
+    , mnCalculatedAverageFontWidth(0)
+#endif
 {}
 
 ImplFont::ImplFont( const ImplFont& rImplFont ) :
@@ -883,6 +919,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


More information about the Libreoffice-commits mailing list