Related: tdf#131725 match the basegfx translation to the mirror logic

that is used in the traditional code path, this will fix vcl RTL
scrollbars in otherwise LTR UI

Change-Id: I1451f7e17b93b0339ded6d33147df6415274ebfc
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133780
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx
index eed8ab7..75938afe 100644
--- a/vcl/inc/salgdi.hxx
+++ b/vcl/inc/salgdi.hxx
@@ -638,10 +638,18 @@ private:
    SalLayoutFlags              m_nLayout; //< 0: mirroring off, 1: mirror x-axis

    // for buffering the Mirror-Matrix, see ::getMirror
    enum class MirrorMode
    {
        NONE,
        Antiparallel,
        AntiparallelBiDi,
        BiDi
    };
    MirrorMode                  m_eLastMirrorMode;
    tools::Long                 m_nLastMirrorTranslation;
    basegfx::B2DHomMatrix       m_aLastMirror;
    tools::Long                 m_aLastMirrorW;
    tools::Long                 m_nLastMirrorDeviceLTRButBiDiRtlTranslate;
    bool                        m_bLastMirrorDeviceLTRButBiDiRtlSet;

    MirrorMode GetMirrorMode(const OutputDevice& rOutDev) const;

protected:
    /// flags which hold the SetAntialiasing() value from OutputDevice
diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx
index 89f9d032..a998a74 100644
--- a/vcl/source/gdi/salgdilayout.cxx
+++ b/vcl/source/gdi/salgdilayout.cxx
@@ -53,9 +53,8 @@ SalFrameGeometry SalFrame::GetGeometry() const

SalGraphics::SalGraphics()
:   m_nLayout( SalLayoutFlags::NONE ),
    m_aLastMirrorW(0),
    m_nLastMirrorDeviceLTRButBiDiRtlTranslate(0),
    m_bLastMirrorDeviceLTRButBiDiRtlSet(false),
    m_eLastMirrorMode(MirrorMode::NONE),
    m_nLastMirrorTranslation(0),
    m_bAntiAlias(false),
    m_bTextRenderModeForResolutionIndependentLayout(false)
{
@@ -271,50 +270,90 @@ basegfx::B2DPolyPolygon SalGraphics::mirror( const basegfx::B2DPolyPolygon& i_rP
    }
}

SalGraphics::MirrorMode SalGraphics::GetMirrorMode(const OutputDevice& rOutDev) const
{
    if (rOutDev.ImplIsAntiparallel())
    {
        if (m_nLayout & SalLayoutFlags::BiDiRtl)
            return MirrorMode::AntiparallelBiDi;
        else
            return MirrorMode::Antiparallel;
    }
    else if (m_nLayout & SalLayoutFlags::BiDiRtl)
        return MirrorMode::BiDi;
    return MirrorMode::NONE;
}

const basegfx::B2DHomMatrix& SalGraphics::getMirror( const OutputDevice& i_rOutDev ) const
{
    // get mirroring transformation
    const tools::Long w = GetDeviceWidth(i_rOutDev);
    SAL_WARN_IF( !w, "vcl", "missing graphics width" );
    MirrorMode eNewMirrorMode = GetMirrorMode(i_rOutDev);
    tools::Long nTranslate(0);

    const bool bMirrorDeviceLTRButBiDiRtlSet = !i_rOutDev.IsRTLEnabled();
    tools::Long nMirrorDeviceLTRButBiDiRtlTranslate(0);
    if (bMirrorDeviceLTRButBiDiRtlSet)
        nMirrorDeviceLTRButBiDiRtlTranslate = w - i_rOutDev.GetOutputWidthPixel() - (2 * i_rOutDev.GetOutOffXPixel());

    // if the device width, or mirror state of the device changed, then m_aLastMirror is invalid
    bool bLastMirrorValid = w == m_aLastMirrorW && bMirrorDeviceLTRButBiDiRtlSet == m_bLastMirrorDeviceLTRButBiDiRtlSet;
    if (bLastMirrorValid && bMirrorDeviceLTRButBiDiRtlSet)
    switch (eNewMirrorMode)
    {
        // if the device is in the unusual mode of a LTR device, but layout flags of SalLayoutFlags::BiDiRtl are
        // in use, then the m_aLastMirror is invalid if the distance it should translate has changed
        bLastMirrorValid = nMirrorDeviceLTRButBiDiRtlTranslate == m_nLastMirrorDeviceLTRButBiDiRtlTranslate;
        case MirrorMode::AntiparallelBiDi:
        {
            const tools::Long w = GetDeviceWidth(i_rOutDev);
            SAL_WARN_IF(!w, "vcl", "missing graphics width");
            nTranslate = w - i_rOutDev.GetOutputWidthPixel() - (2 * i_rOutDev.GetOutOffXPixel());
            break;
        }
        case MirrorMode::Antiparallel:
        {
            nTranslate = i_rOutDev.GetOutputWidthPixel() + (2 * i_rOutDev.GetOutOffXPixel()) - 1;
            break;
        }
        case MirrorMode::BiDi:
        {
            const tools::Long w = GetDeviceWidth(i_rOutDev);
            SAL_WARN_IF(!w, "vcl", "missing graphics width");
            nTranslate = w - 1;
            break;
        }
        case MirrorMode::NONE:
            break;
    }

    // if the translation (due to device width), or mirror state of the device changed, then m_aLastMirror is invalid
    bool bLastMirrorValid = eNewMirrorMode == m_eLastMirrorMode && nTranslate == m_nLastMirrorTranslation;
    if (!bLastMirrorValid)
    {
        const_cast<SalGraphics*>(this)->m_aLastMirrorW = w;
        const_cast<SalGraphics*>(this)->m_bLastMirrorDeviceLTRButBiDiRtlSet = bMirrorDeviceLTRButBiDiRtlSet;
        const_cast<SalGraphics*>(this)->m_nLastMirrorDeviceLTRButBiDiRtlTranslate = nMirrorDeviceLTRButBiDiRtlTranslate;
        const_cast<SalGraphics*>(this)->m_nLastMirrorTranslation = nTranslate;
        const_cast<SalGraphics*>(this)->m_eLastMirrorMode = eNewMirrorMode;

        if(w)
        switch (eNewMirrorMode)
        {
            if (bMirrorDeviceLTRButBiDiRtlSet)
            // mirror this window back
            case MirrorMode::AntiparallelBiDi:
            {
                /* This path gets exercised in calc's RTL UI (e.g. SAL_RTL_ENABLED=1)
                   with its LTR horizontal scrollbar */

                // Original code was:
                //      // mirror this window back
                //      double devX = w-i_rOutDev.GetOutputWidthPixel()-i_rOutDev.GetOutOffXPixel();   // re-mirrored mnOutOffX
                //      aRet.setX( devX + (i_rPoint.getX() - i_rOutDev.GetOutOffXPixel()) );
                // I do not really understand the comment 'mirror this window back', so cannot guarantee
                // that this works as before, but I have reduced this (by re-placing and re-formatting) to
                // a simple translation:
                const_cast<SalGraphics*>(this)->m_aLastMirror = basegfx::utils::createTranslateB2DHomMatrix(
                    nMirrorDeviceLTRButBiDiRtlTranslate, 0.0);
                   nTranslate, 0.0);
                break;
            }
            else
            case MirrorMode::Antiparallel:
            {
                /* This path gets exercised in writers's LTR UI with a RTL horizontal
                   scrollbar, cross-reference dialog populated from contents from a
                   RTL document tdf#131725 */

                // Original code was;
                //      tools::Long devX = rOutDev.GetOutOffXPixel();   // re-mirrored mnOutOffX
                //      x = rOutDev.GetOutputWidthPixel() - (x - devX) + rOutDev.GetOutOffXPixel() - 1;
                const_cast<SalGraphics*>(this)->m_aLastMirror = basegfx::utils::createScaleTranslateB2DHomMatrix(
                    -1.0,
                    1.0,
                    nTranslate,
                    0.0);
                break;
            }
            case MirrorMode::BiDi:
            {
                // Original code was:
                //      aRet.setX( w-1-i_rPoint.getX() );
@@ -324,13 +363,13 @@ const basegfx::B2DHomMatrix& SalGraphics::getMirror( const OutputDevice& i_rOutD
                const_cast<SalGraphics*>(this)->m_aLastMirror = basegfx::utils::createScaleTranslateB2DHomMatrix(
                    -1.0,
                    1.0,
                    w-1,
                    nTranslate,
                    0.0);
                break;
            }
        }
        else
        {
            const_cast<SalGraphics*>(this)->m_aLastMirror.identity();
            case MirrorMode::NONE:
                const_cast<SalGraphics*>(this)->m_aLastMirror.identity();
                break;
        }
    }