Resolves: tdf#99508 ensure sufficient size for hidpi backing surface

and match virtual device scale with widget device scale

Change-Id: I1f35dcbaec94be12758ad6e4276bfd6bda4b1e88
Reviewed-on: https://gerrit.libreoffice.org/31080
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Tested-by: Jenkins <ci@libreoffice.org>
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index 1f861e7..46d8a8a 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -374,6 +374,7 @@ bool SvpSalGraphics::drawAlphaRect(long nX, long nY, long nWidth, long nHeight, 

SvpSalGraphics::SvpSalGraphics()
    : m_pSurface(nullptr)
    , m_fScale(1.0)
    , m_aLineColor(MAKE_SALCOLOR(0x00, 0x00, 0x00))
    , m_aFillColor(MAKE_SALCOLOR(0xFF, 0xFF, 0XFF))
    , m_ePaintMode(OVERPAINT)
@@ -388,6 +389,7 @@ SvpSalGraphics::~SvpSalGraphics()
void SvpSalGraphics::setSurface(cairo_surface_t* pSurface)
{
    m_pSurface = pSurface;
    cairo_surface_get_device_scale(pSurface, &m_fScale, nullptr);
    ResetClipRegion();
}

@@ -981,14 +983,15 @@ void SvpSalGraphics::copyBits( const SalTwoRect& rTR,
#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 12, 0)
        pCopy = cairo_surface_create_similar(source,
                                            cairo_surface_get_content(m_pSurface),
                                            aTR.mnSrcWidth,
                                            aTR.mnSrcHeight);
                                            aTR.mnSrcWidth * m_fScale,
                                            aTR.mnSrcHeight * m_fScale);
#else
        pCopy = cairo_surface_create_similar_image(source,
                                            cairo_image_surface_get_format(m_pSurface),
                                            aTR.mnSrcWidth,
                                            aTR.mnSrcHeight);
                                            aTR.mnSrcWidth * m_fScale,
                                            aTR.mnSrcHeight * m_fScale);
#endif
        cairo_surface_set_device_scale(pCopy, m_fScale, m_fScale);

        cairo_t* cr = cairo_create(pCopy);
        cairo_set_source_surface(cr, source, -aTR.mnSrcX, -aTR.mnSrcY);
diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx
index 53072d6..39ad727 100644
--- a/vcl/headless/svpinst.cxx
+++ b/vcl/headless/svpinst.cxx
@@ -281,7 +281,7 @@ SalVirtualDevice* SvpSalInstance::CreateVirtualDevice( SalGraphics* /* pGraphics
                                                       DeviceFormat eFormat,
                                                       const SystemGraphicsData* /* pData */ )
{
    SvpSalVirtualDevice* pNew = new SvpSalVirtualDevice(eFormat);
    SvpSalVirtualDevice* pNew = new SvpSalVirtualDevice(eFormat, 1);
    pNew->SetSize( nDX, nDY );
    return pNew;
}
diff --git a/vcl/headless/svpvd.cxx b/vcl/headless/svpvd.cxx
index f356d7d..f0d31f84 100644
--- a/vcl/headless/svpvd.cxx
+++ b/vcl/headless/svpvd.cxx
@@ -57,14 +57,16 @@ bool SvpSalVirtualDevice::SetSize( long nNewDX, long nNewDY )
bool SvpSalVirtualDevice::SetSizeUsingBuffer( long nNewDX, long nNewDY,
        sal_uInt8 *const pBuffer)
{
    B2IVector aDevSize( nNewDX, nNewDY );
    if( aDevSize.getX() == 0 )
        aDevSize.setX( 1 );
    if( aDevSize.getY() == 0 )
        aDevSize.setY( 1 );
    if (nNewDX == 0)
        nNewDX = 1;
    if (nNewDY == 0)
        nNewDY = 1;

    if (!m_pSurface || cairo_image_surface_get_width(m_pSurface) != aDevSize.getX() ||
                       cairo_image_surface_get_height(m_pSurface) != aDevSize.getY() )
    nNewDX *= m_fScale;
    nNewDY *= m_fScale;

    if (!m_pSurface || cairo_image_surface_get_width(m_pSurface) != nNewDX ||
                       cairo_image_surface_get_height(m_pSurface) != nNewDY )
    {
        if (m_pSurface)
        {
@@ -74,22 +76,21 @@ bool SvpSalVirtualDevice::SetSizeUsingBuffer( long nNewDX, long nNewDY,
        if (m_eFormat == DeviceFormat::BITMASK)
        {
            m_pSurface = cairo_image_surface_create(CAIRO_FORMAT_A1,
                                aDevSize.getX(),
                                aDevSize.getY());
                                nNewDX, nNewDY);
        }
        else
        {
            m_pSurface = pBuffer ?
                             cairo_image_surface_create_for_data(pBuffer, CAIRO_FORMAT_ARGB32,
                                   aDevSize.getX(),
                                   aDevSize.getY(),
                                   cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, aDevSize.getX()))
                                   nNewDX, nNewDY,
                                   cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, nNewDX))
                                 :
                             cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
                                   aDevSize.getX(),
                                   aDevSize.getY());
                                   nNewDX, nNewDY);
        }

        cairo_surface_set_device_scale(m_pSurface, m_fScale, m_fScale);

        // update device in existing graphics
        for( std::list< SvpSalGraphics* >::iterator it = m_aGraphics.begin();
             it != m_aGraphics.end(); ++it )
diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx
index 1ef0f32..97fd678 100644
--- a/vcl/inc/headless/svpgdi.hxx
+++ b/vcl/inc/headless/svpgdi.hxx
@@ -80,6 +80,7 @@ struct VCL_DLLPUBLIC DamageHandler
class VCL_DLLPUBLIC SvpSalGraphics : public SalGraphics
{
    cairo_surface_t*               m_pSurface;
    double                         m_fScale;
    SalColor                       m_aLineColor;
    SalColor                       m_aFillColor;
    PaintMode                      m_ePaintMode;
@@ -236,6 +237,7 @@ public:
    cairo_t*                getCairoContext(bool bXorModeAllowed) const;
    void                    releaseCairoContext(cairo_t* cr, bool bXorModeAllowed, const basegfx::B2DRange& rExtents) const;
    static cairo_surface_t* createCairoSurface(const BitmapBuffer *pBuffer);
    double                  getScale() const { return m_fScale; }
    void                    clipRegion(cairo_t* cr);
};

diff --git a/vcl/inc/headless/svpvd.hxx b/vcl/inc/headless/svpvd.hxx
index c624f74..882f36d 100644
--- a/vcl/inc/headless/svpvd.hxx
+++ b/vcl/inc/headless/svpvd.hxx
@@ -31,12 +31,14 @@ class VCL_DLLPUBLIC SvpSalVirtualDevice : public SalVirtualDevice
{
    DeviceFormat                        m_eFormat;
    cairo_surface_t*                    m_pSurface;
    double                              m_fScale;
    std::list< SvpSalGraphics* >        m_aGraphics;

public:
    SvpSalVirtualDevice(DeviceFormat eFormat)
    SvpSalVirtualDevice(DeviceFormat eFormat, double fScale)
        : m_eFormat(eFormat)
        , m_pSurface(nullptr)
        , m_fScale(fScale)
    {
    }
    virtual ~SvpSalVirtualDevice() override;
diff --git a/vcl/inc/unx/gtk/gtkdata.hxx b/vcl/inc/unx/gtk/gtkdata.hxx
index ffb0fb7..c59d7a240 100644
--- a/vcl/inc/unx/gtk/gtkdata.hxx
+++ b/vcl/inc/unx/gtk/gtkdata.hxx
@@ -137,6 +137,7 @@ class GtkSalDisplay : public SalDisplay
    o3tl::enumarray<PointerStyle, GdkCursor*> m_aCursors;
    bool                            m_bStartupCompleted;
    bool                            m_bX11Display;
    bool                            m_bOwnHiDpiScale;

    GdkCursor* getFromXBM( const unsigned char *pBitmap, const unsigned char *pMask,
                           int nWidth, int nHeight, int nXHot, int nYHot );
@@ -146,6 +147,7 @@ public:

    GdkDisplay* GetGdkDisplay() const { return m_pGdkDisplay; }
    bool        IsX11Display() const { return m_bX11Display; }
    bool        IsOwnHiDpiScale() const { return m_bOwnHiDpiScale; }

    GtkSalSystem* getSystem() const { return m_pSys; }

diff --git a/vcl/unx/gtk/gtkdata.cxx b/vcl/unx/gtk/gtkdata.cxx
index e621f47..2de555e 100644
--- a/vcl/unx/gtk/gtkdata.cxx
+++ b/vcl/unx/gtk/gtkdata.cxx
@@ -80,6 +80,7 @@ GtkSalDisplay::GtkSalDisplay( GdkDisplay* pDisplay ) :
        GetGenericData()->ErrorTrapPush(); // and leak the trap

    m_bX11Display = true;
    m_bOwnHiDpiScale = true;

    gtk_widget_set_default_direction(AllSettings::GetLayoutRTL() ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR);
}
diff --git a/vcl/unx/gtk/gtkinst.cxx b/vcl/unx/gtk/gtkinst.cxx
index 14bd71d..e01a267b 100644
--- a/vcl/unx/gtk/gtkinst.cxx
+++ b/vcl/unx/gtk/gtkinst.cxx
@@ -339,8 +339,10 @@ SalVirtualDevice* GtkInstance::CreateVirtualDevice( SalGraphics *pG,
{
    EnsureInit();
#if GTK_CHECK_VERSION(3,0,0)
    (void)pG; (void) pGd;
    SvpSalVirtualDevice* pNew = new SvpSalVirtualDevice(eFormat);
    (void) pGd;
    SvpSalGraphics *pSvpSalGraphics = dynamic_cast<SvpSalGraphics*>(pG);
    assert(pSvpSalGraphics);
    SvpSalVirtualDevice* pNew = new SvpSalVirtualDevice(eFormat, pSvpSalGraphics->getScale());
    pNew->SetSize( nDX, nDY );
    return pNew;
#else
diff --git a/vcl/unx/gtk3/gtk3gtkdata.cxx b/vcl/unx/gtk3/gtk3gtkdata.cxx
index 70f9249..464a865 100644
--- a/vcl/unx/gtk3/gtk3gtkdata.cxx
+++ b/vcl/unx/gtk3/gtk3gtkdata.cxx
@@ -83,6 +83,7 @@ GtkSalDisplay::GtkSalDisplay( GdkDisplay* pDisplay ) :
        GetGenericData()->ErrorTrapPush(); // and leak the trap

    m_bX11Display = GDK_IS_X11_DISPLAY( m_pGdkDisplay );
    m_bOwnHiDpiScale = false;

#if GTK_CHECK_VERSION(3,10,0)
#ifdef GDK_WINDOWING_X11
@@ -91,6 +92,7 @@ GtkSalDisplay::GtkSalDisplay( GdkDisplay* pDisplay ) :
        if (!getenv("GDK_SCALE"))
        {
            gdk_x11_display_set_window_scale(m_pGdkDisplay, 1);
            m_bOwnHiDpiScale = true;
        }
    }
#endif
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx
index e3a6286..5acb139 100644
--- a/vcl/unx/gtk3/gtk3gtkframe.cxx
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx
@@ -1575,13 +1575,14 @@ void GtkSalFrame::AllocateFrame()
        if (m_pSurface)
            cairo_surface_destroy(m_pSurface);


#if GTK_CHECK_VERSION(3,10,0)
        int scale = getDisplay()->IsOwnHiDpiScale() ? 1 : gtk_widget_get_scale_factor(m_pWindow);
        m_pSurface = gdk_window_create_similar_image_surface(widget_get_window(m_pWindow),
                                                             CAIRO_FORMAT_ARGB32,
                                                             aFrameSize.getX(),
                                                             aFrameSize.getY(),
                                                             0);
                                                             aFrameSize.getX() * scale,
                                                             aFrameSize.getY() * scale,
                                                             scale);
        cairo_surface_set_device_scale(m_pSurface, scale, scale);
#else
        m_pSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
                                                aFrameSize.getX(),
diff --git a/vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx b/vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx
index f3edc2b..8090f68 100644
--- a/vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx
+++ b/vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx
@@ -3117,7 +3117,7 @@ void GtkSalGraphics::GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY)
    int nScaleFactor = 1;

#if GTK_CHECK_VERSION(3, 10, 0)
    nScaleFactor = gdk_window_get_scale_factor(widget_get_window(mpWindow));
    nScaleFactor = GtkSalFrame::getDisplay()->IsOwnHiDpiScale() ? gtk_widget_get_scale_factor(mpWindow) : 1;
#endif

    if (fResolution > 0.0)