tdf#119302 WIN better font scale handling

Moves the scale factor into the LogicalFontInstance and uses the
Glyphs font fallback level to use the correct font and scale.

Probably the glyphs should be using a rtl::Reference to the
LogcalFontInstance instead of the fallback level. I don't know if
glyphs are evicted from the cache, if the fallback changes. There
is now an assert and all places will use 1.0 as the default
scaling factor, so LO should at least not crash.

Reviewed-on: https://gerrit.libreoffice.org/60091
Tested-by: Jenkins
Reviewed-by: Jan-Marek Glogowski <glogow@fbihome.de>
(cherry picked from commit c177c305fc839e7a64d228ec56209d133588572b)

Conflicts:
	vcl/inc/win/salgdi.h
	vcl/win/gdi/salfont.cxx

Change-Id: I9dd4fc3a5b5924fc379b48a7f71c9eed26b4779d
Reviewed-on: https://gerrit.libreoffice.org/60722
Reviewed-by: Michael Stahl <Michael.Stahl@cib.de>
Tested-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index fe4f4b8..d43a1b2 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -172,7 +172,6 @@ private:
    HFONT                   mhFonts[ MAX_FALLBACK ];        // Font + Fallbacks
    WinFontInstance*       mpWinFontEntry[ MAX_FALLBACK ]; // pointer to the most recent font instance
    float                   mfFontScale[ MAX_FALLBACK ];        // allows metrics emulation of huge font sizes
    float                   mfCurrentFontScale;
    HRGN                    mhRegion;           // vcl::Region Handle
    HPEN                    mhDefPen;           // DefaultPen
    HBRUSH                  mhDefBrush;         // DefaultBrush
diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx
index 2e22834..0c44715 100644
--- a/vcl/inc/win/winlayout.hxx
+++ b/vcl/inc/win/winlayout.hxx
@@ -156,6 +156,8 @@ public:

    void SetHFONT(const HFONT);
    HFONT GetHFONT() const { return m_hFont; }
    void SetScale(float fScale) { m_fScale = fScale; }
    float GetScale() const { return m_fScale; }

    // Prevend deletion of the HFONT in the WinFontInstance destructor
    // Used for the ScopedFont handling
@@ -167,6 +169,7 @@ private:
    virtual hb_font_t* ImplInitHbFont() override;

    HFONT m_hFont;
    float m_fScale;
    GlyphCache maGlyphCache;
};

diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx
index 81c8d3a..8056b46 100644
--- a/vcl/win/gdi/salfont.cxx
+++ b/vcl/win/gdi/salfont.cxx
@@ -925,7 +925,6 @@ void WinSalGraphics::SetFont( const FontSelectPattern* pFont, int nFallbackLevel
            ::SelectFont(getHDC(), mhDefFont);
            mhDefFont = nullptr;
        }
        mfCurrentFontScale = mfFontScale[nFallbackLevel];
        // release no longer referenced font handles
        for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
        {
@@ -939,6 +938,7 @@ void WinSalGraphics::SetFont( const FontSelectPattern* pFont, int nFallbackLevel
                GetWinFontEntry(i)->Release();
                mpWinFontEntry[i] = nullptr;
            }
            mfFontScale[i] = 1.0;
        }
        return;
    }
@@ -953,52 +953,61 @@ void WinSalGraphics::SetFont( const FontSelectPattern* pFont, int nFallbackLevel
    {
        pFont->mpFontInstance->Acquire();
    }
    mpWinFontEntry[ nFallbackLevel ] = reinterpret_cast<WinFontInstance*>( pFont->mpFontInstance );

    WinFontInstance *pFontInstance = static_cast<WinFontInstance*>(pFont->mpFontInstance);
    mpWinFontEntry[ nFallbackLevel ] = pFontInstance;

    HFONT hOldFont = nullptr;
    HFONT hNewFont = mpWinFontEntry[ nFallbackLevel ] ? mpWinFontEntry[ nFallbackLevel ]->GetHFONT() : nullptr;
    HFONT hNewFont = pFontInstance ? pFontInstance->GetHFONT() : nullptr;
    if (!hNewFont)
    {
        hNewFont = ImplDoSetFont(pFont->GetFontSelectPattern(), pFont->GetFontFace(), mfFontScale[ nFallbackLevel ], hOldFont);
        mpWinFontEntry[ nFallbackLevel ]->SetHFONT(hNewFont);
        float fFontScale = 1.0;
        hNewFont = ImplDoSetFont(pFont, nullptr, fFontScale, hOldFont);
        if (pFontInstance)
        {
            pFontInstance->SetHFONT(hNewFont);
            pFontInstance->SetScale(fFontScale);
        }
        else
        {
            if (mhFonts[nFallbackLevel])
                ::DeleteFont(mhFonts[nFallbackLevel]);
            mhFonts[nFallbackLevel] = hNewFont;
            mfFontScale[nFallbackLevel] = fFontScale;
        }
    }
    else
        hOldFont = ::SelectFont( getHDC(), hNewFont );

    mfCurrentFontScale = mfFontScale[nFallbackLevel];

    // keep default font
    if( !mhDefFont )
    {
        // keep default font
        mhDefFont = hOldFont;
    }
    else
    {
        // release no longer referenced font handles
        for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
        for (int i = nFallbackLevel + 1; i < MAX_FALLBACK; ++i)
        {
            if( mhFonts[i] )
            if (mhFonts[i])
            {
                ::DeleteFont( mhFonts[i] );
                mhFonts[i] = nullptr;
            }
            if (i > nFallbackLevel && mpWinFontEntry[i])
            if (mpWinFontEntry[i])
            {
                GetWinFontEntry(i)->Release();
                mpWinFontEntry[i] = nullptr;
            }
            mfFontScale[i] = 1.0;
        }
    }

    // store new font in correct layer
    if (mpWinFontEntry[nFallbackLevel])
    if (pFontInstance)
    {
        // now the font is live => update font face
        const WinFontFace* pFontFace = static_cast<const WinFontFace*>(mpWinFontEntry[nFallbackLevel]->GetFontFace());
        const WinFontFace* pFontFace = static_cast<const WinFontFace*>(pFontInstance->GetFontFace());
        pFontFace->UpdateFromHDC(getHDC());
    }
    else
        mhFonts[ nFallbackLevel ] = hNewFont;
}

void WinSalGraphics::GetFontMetric( ImplFontMetricDataRef& rxFontMetric, int nFallbackLevel )
@@ -1037,7 +1046,7 @@ void WinSalGraphics::GetFontMetric( ImplFontMetricDataRef& rxFontMetric, int nFa
    rxFontMetric->SetSlant( 0 );

    // transformation dependent font metrics
    rxFontMetric->SetWidth(static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmAveCharWidth ));
    rxFontMetric->SetWidth(static_cast<int>(mpWinFontEntry[nFallbackLevel]->GetScale() * aWinMetric.tmAveCharWidth));

    const std::vector<uint8_t> rHhea(aHheaRawData.get(), aHheaRawData.get() + aHheaRawData.size());
    const std::vector<uint8_t> rOS2(aOS2RawData.get(), aOS2RawData.get() + aOS2RawData.size());
@@ -1385,7 +1394,14 @@ bool WinSalGraphics::GetGlyphBoundRect(const GlyphItem& rGlyph, tools::Rectangle
        return true;
    }

    WinFontInstance* pFont = mpWinFontEntry[rGlyph.mnFallbackLevel];
    HFONT hNewFont = pFont ? pFont->GetHFONT() : mhFonts[rGlyph.mnFallbackLevel];
    float fFontScale = pFont ? pFont->GetScale() : mfFontScale[rGlyph.mnFallbackLevel];

    HDC hDC = getHDC();
    HFONT hFont = static_cast<HFONT>(GetCurrentObject(hDC, OBJ_FONT));
    if (hNewFont && (hFont != hNewFont))
        SelectObject(hDC, hNewFont);

    // use unity matrix
    MAT2 aMat;
@@ -1399,15 +1415,17 @@ bool WinSalGraphics::GetGlyphBoundRect(const GlyphItem& rGlyph, tools::Rectangle
    aGM.gmptGlyphOrigin.x = aGM.gmptGlyphOrigin.y = 0;
    aGM.gmBlackBoxX = aGM.gmBlackBoxY = 0;
    DWORD nSize = ::GetGlyphOutlineW(hDC, rGlyph.maGlyphId, nGGOFlags, &aGM, 0, nullptr, &aMat);
    if (hNewFont && (hFont != hNewFont))
        SelectObject(hDC, hFont);
    if( nSize == GDI_ERROR )
        return false;

    rRect = tools::Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ),
        Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) );
    rRect.SetLeft(static_cast<int>( mfCurrentFontScale * rRect.Left() ));
    rRect.SetRight(static_cast<int>( mfCurrentFontScale * rRect.Right() ) + 1);
    rRect.SetTop(static_cast<int>( mfCurrentFontScale * rRect.Top() ));
    rRect.SetBottom(static_cast<int>( mfCurrentFontScale * rRect.Bottom() ) + 1);
    rRect.SetLeft(static_cast<int>( fFontScale * rRect.Left() ));
    rRect.SetRight(static_cast<int>( fFontScale * rRect.Right() ) + 1);
    rRect.SetTop(static_cast<int>( fFontScale * rRect.Top() ));
    rRect.SetBottom(static_cast<int>( fFontScale * rRect.Bottom() ) + 1);

    g_BoundRectCache.insert({rGlyph.maGlyphId, rRect});

@@ -1587,7 +1605,9 @@ bool WinSalGraphics::GetGlyphOutline(const GlyphItem& rGlyph,
    // rescaling needed for the tools::PolyPolygon conversion
    if( rB2DPolyPoly.count() )
    {
        const double fFactor(mfCurrentFontScale/256);
        WinFontInstance *pFont = mpWinFontEntry[rGlyph.mnFallbackLevel];
        float fFontScale = pFont ? pFont->GetScale() : mfFontScale[rGlyph.mnFallbackLevel];
        const double fFactor(fFontScale/256);
        rB2DPolyPoly.transform(basegfx::utils::createScaleB2DHomMatrix(fFactor, fFactor));
    }

diff --git a/vcl/win/gdi/salgdi.cxx b/vcl/win/gdi/salgdi.cxx
index d38337b..aba0d6e 100644
--- a/vcl/win/gdi/salgdi.cxx
+++ b/vcl/win/gdi/salgdi.cxx
@@ -607,7 +607,6 @@ WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hW
    mbWindow(eType == WinSalGraphics::WINDOW),
    mbScreen(bScreen),
    mhWnd(hWnd),
    mfCurrentFontScale(1.0),
    mhRegion(nullptr),
    mhDefPen(nullptr),
    mhDefBrush(nullptr),