tdf#127471 improve SVM FontScaling im/export

Due to svg::Font Width and it's expression of
FontScaling being system-dependent the FontScaling
when exchanging beween win-based SVM creators and
others was creating errors.
Corrected this to work now with newly created SVM
files in both directions. For more aspects see
discussion in task.

Change-Id: I326e4e7e895a9dfc3cdfc5323174ca81e22795e8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110330
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
diff --git a/vcl/inc/impfont.hxx b/vcl/inc/impfont.hxx
index caa917a..ba1ea368 100644
--- a/vcl/inc/impfont.hxx
+++ b/vcl/inc/impfont.hxx
@@ -84,8 +84,8 @@ public:

private:
    friend class vcl::Font;
    friend SvStream&    ReadImplFont( SvStream& rIStm, ImplFont& );
    friend SvStream&    WriteImplFont( SvStream& rOStm, const ImplFont& );
    friend SvStream&    ReadImplFont( SvStream& rIStm, ImplFont&, tools::Long& );
    friend SvStream&    WriteImplFont( SvStream& rOStm, const ImplFont&, const tools::Long& );

    void                AskConfig();

diff --git a/vcl/source/font/font.cxx b/vcl/source/font/font.cxx
index 2c64a4a..891f1be 100644
--- a/vcl/source/font/font.cxx
+++ b/vcl/source/font/font.cxx
@@ -35,6 +35,10 @@
#include <rtl/instance.hxx>
#include <vcl/TypeSerializer.hxx>

#ifdef _WIN32
#include <vcl/metric.hxx>
#endif

using namespace vcl;

namespace
@@ -358,7 +362,7 @@ void Font::GetFontAttributes( FontAttributes& rAttrs ) const
    rAttrs.SetSymbolFlag( mpImplFont->GetCharSet() == RTL_TEXTENCODING_SYMBOL );
}

SvStream& ReadImplFont( SvStream& rIStm, ImplFont& rImplFont )
SvStream& ReadImplFont( SvStream& rIStm, ImplFont& rImplFont, tools::Long& rnNormedFontScaling )
{
    VersionCompatRead aCompat( rIStm );
    sal_uInt16      nTmp16(0);
@@ -401,15 +405,25 @@ SvStream& ReadImplFont( SvStream& rIStm, ImplFont& rImplFont )
        rIStm.ReadUInt16( nTmp16 ); rImplFont.meOverline = static_cast<FontLineStyle>(nTmp16);
    }

    // tdf#127471 read NormedFontScaling
    if( aCompat.GetVersion() >= 4 )
    {
        sal_Int32 nNormedFontScaling(0);
        rIStm.ReadInt32(nNormedFontScaling);
        rnNormedFontScaling = nNormedFontScaling;
    }

    // Relief
    // CJKContextLanguage

    return rIStm;
}

SvStream& WriteImplFont( SvStream& rOStm, const ImplFont& rImplFont )
SvStream& WriteImplFont( SvStream& rOStm, const ImplFont& rImplFont, const tools::Long& rnNormedFontScaling )
{
    VersionCompatWrite aCompat( rOStm, 3 );
    // tdf#127471 increase to version 4
    VersionCompatWrite aCompat( rOStm, 4 );

    TypeSerializer aSerializer(rOStm);
    rOStm.WriteUniOrByteString( rImplFont.GetFamilyName(), rOStm.GetStreamCharSet() );
    rOStm.WriteUniOrByteString( rImplFont.GetStyleName(), rOStm.GetStreamCharSet() );
@@ -441,17 +455,108 @@ SvStream& WriteImplFont( SvStream& rOStm, const ImplFont& rImplFont )
    // new in version 3
    rOStm.WriteUInt16( rImplFont.meOverline );

    // new in version 4, NormedFontScaling
    rOStm.WriteInt32(rnNormedFontScaling);

    return rOStm;
}

SvStream& ReadFont( SvStream& rIStm, vcl::Font& rFont )
{
    return ReadImplFont( rIStm, *rFont.mpImplFont );
    // tdf#127471 try to read NormedFontScaling
    tools::Long nNormedFontScaling(0);
    SvStream& rRetval(ReadImplFont( rIStm, *rFont.mpImplFont, nNormedFontScaling ));

    if (nNormedFontScaling > 0)
    {
#ifdef _WIN32
        // we run on windows and a NormedFontScaling was written
        if(rFont.GetFontSize().getWidth() == nNormedFontScaling)
        {
            // the writing producer was running on a non-windows system, adapt to needed windows
            // system-specific pre-multiply
            const tools::Long nHeight(std::max<tools::Long>(rFont.GetFontSize().getHeight(), 0));
            sal_uInt32 nScaledWidth(0);

            if(nHeight > 0)
            {
                vcl::Font aUnscaledFont(rFont);
                aUnscaledFont.SetAverageFontWidth(0);
                const FontMetric aUnscaledFontMetric(Application::GetDefaultDevice()->GetFontMetric(aUnscaledFont));

                if (aUnscaledFontMetric.GetAverageFontWidth() > 0)
                {
                    const double fScaleFactor(static_cast<double>(nNormedFontScaling) / static_cast<double>(nHeight));
                    nScaledWidth = basegfx::fround(static_cast<double>(aUnscaledFontMetric.GetAverageFontWidth()) * fScaleFactor);
                }
            }

            rFont.SetAverageFontWidth(nScaledWidth);
        }
        else
        {
            // the writing producer was on a windows system, correct pre-multiplied value
            // is already set, nothing to do. Ignore 2nd value. Here a check
            // could be done if adapting the 2nd, NormedFontScaling value would be similar to
            // the set value for plausability reasons
        }
#else
        // we do not run on windows and a NormedFontScaling was written
        if(rFont.GetFontSize().getWidth() == nNormedFontScaling)
        {
            // the writing producer was not on a windows system, correct value
            // already set, nothing to do
        }
        else
        {
            // the writing producer was on a windows system, correct FontScvaling.
            // The correct non-pre-multiplied value is the 2nd one, use it
            rFont.SetAverageFontWidth(nNormedFontScaling);
        }
#endif
    }

    return rRetval;
}

SvStream& WriteFont( SvStream& rOStm, const vcl::Font& rFont )
{
    return WriteImplFont( rOStm, *rFont.mpImplFont );
    // tdf#127471 prepare NormedFontScaling for additional export
    tools::Long nNormedFontScaling(rFont.GetFontSize().getWidth());

    // FontScaling usage at vcl-Font is detected by checking that FontWidth != 0
    if (nNormedFontScaling > 0)
    {
        const tools::Long nHeight(std::max<tools::Long>(rFont.GetFontSize().getHeight(), 0));

        // check for negative height
        if(0 == nHeight)
        {
            nNormedFontScaling = 0;
        }
        else
        {
#ifdef _WIN32
            // for WIN32 the value is pre-multiplied with AverageFontWidth
            // which makes it system-dependent. Turn that back to have the
            // normed non-windows form of it for export as 2nd value
            vcl::Font aUnscaledFont(rFont);
            aUnscaledFont.SetAverageFontWidth(0);
            const FontMetric aUnscaledFontMetric(
                Application::GetDefaultDevice()->GetFontMetric(aUnscaledFont));

            if (aUnscaledFontMetric.GetAverageFontWidth() > 0)
            {
                const double fScaleFactor(
                    static_cast<double>(nNormedFontScaling)
                    / static_cast<double>(aUnscaledFontMetric.GetAverageFontWidth()));
                nNormedFontScaling = static_cast<tools::Long>(fScaleFactor * nHeight);
            }
#endif
        }
    }

    return WriteImplFont( rOStm, *rFont.mpImplFont, nNormedFontScaling );
}

namespace