tdf#136545 use pre-existing cairo_surface

for the cairo-canvas case which has a surface for the drawable already created.
Vaving two of them, one via cairo_xlib_surface_create and one via
cairo_xlib_surface_create_with_xrender_format both alive at the same time seems
understandably unreliable.

This aligns the gen+X11 case closer to the gtk3 case wrt the situation of
tdf#127529

Change-Id: I411649ee36fa944b77c4b09f940a059f507be2cc
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/102200
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h
index caef46a..027d0aa 100644
--- a/vcl/inc/unx/salgdi.h
+++ b/vcl/inc/unx/salgdi.h
@@ -76,7 +76,8 @@ public:
    virtual                         ~X11SalGraphics() COVERITY_NOEXCEPT_FALSE override;

    void                            Init( SalFrame *pFrame, Drawable aDrawable, SalX11Screen nXScreen );
    void                            Init( X11SalVirtualDevice *pVirtualDevice, SalColormap* pColormap = nullptr, bool bDeleteColormap = false );
    void                            Init( X11SalVirtualDevice *pVirtualDevice, cairo_surface_t* pPreExistingTarget = nullptr,
                                          SalColormap* pColormap = nullptr, bool bDeleteColormap = false );
    void                            Init( X11OpenGLSalVirtualDevice *pVirtualDevice );
    void                            Init( X11SkiaSalVirtualDevice *pVirtualDevice );
    void                            DeInit();
@@ -86,8 +87,8 @@ public:
    inline  Display*                GetXDisplay() const;
    inline  const SalVisual&        GetVisual() const;
    SalGeometryProvider*            GetGeometryProvider() const;
    Drawable                GetDrawable() const { return hDrawable_; }
    void                            SetDrawable( Drawable d, SalX11Screen nXScreen );
    Drawable                        GetDrawable() const { return hDrawable_; }
    void                            SetDrawable(Drawable d, cairo_surface_t* surface, SalX11Screen nXScreen);
    XRenderPictFormat*              GetXRenderFormat() const;
    void                    SetXRenderFormat( XRenderPictFormat* pXRenderFormat ) { m_pXRenderFormat = pXRenderFormat; }
    const SalColormap&      GetColormap() const { return *m_pColormap; }
@@ -296,6 +297,7 @@ private:
    const SalColormap*              m_pColormap;
    std::unique_ptr<SalColormap>    m_pDeleteColormap;
    Drawable                        hDrawable_;     // use
    cairo_surface_t*                m_pExternalSurface;
    SalX11Screen                    m_nXScreen;
    mutable XRenderPictFormat*      m_pXRenderFormat;
    XID                             m_aXRenderPicture;
diff --git a/vcl/unx/generic/gdi/cairo_xlib_cairo.cxx b/vcl/unx/generic/gdi/cairo_xlib_cairo.cxx
index 3a82505..1bbf8d3 100644
--- a/vcl/unx/generic/gdi/cairo_xlib_cairo.cxx
+++ b/vcl/unx/generic/gdi/cairo_xlib_cairo.cxx
@@ -248,12 +248,15 @@ namespace cairo
    {
        SystemGraphicsData aSystemGraphicsData;

        cairo_surface_t* pSurface = mpSurface.get();

        aSystemGraphicsData.nSize = sizeof(SystemGraphicsData);
        aSystemGraphicsData.hDrawable = mpPixmap ? mpPixmap->mhDrawable : maSysData.hDrawable;
        aSystemGraphicsData.pXRenderFormat = maSysData.pRenderFormat;
        aSystemGraphicsData.pSurface = pSurface;

        int width = cairo_xlib_surface_get_width(mpSurface.get());
        int height = cairo_xlib_surface_get_height(mpSurface.get());
        int width = cairo_xlib_surface_get_width(pSurface);
        int height = cairo_xlib_surface_get_height(pSurface);

        return VclPtr<VirtualDevice>::Create(aSystemGraphicsData,
                              Size(width, height),
diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx
index 4b26320..79037c1 100644
--- a/vcl/unx/generic/gdi/salgdi.cxx
+++ b/vcl/unx/generic/gdi/salgdi.cxx
@@ -66,6 +66,7 @@ X11SalGraphics::X11SalGraphics():
    m_pVDev(nullptr),
    m_pColormap(nullptr),
    hDrawable_(None),
    m_pExternalSurface(nullptr),
    m_nXScreen( 0 ),
    m_pXRenderFormat(nullptr),
    m_aXRenderPicture(0),
@@ -144,8 +145,10 @@ SalGraphicsImpl* X11SalGraphics::GetImpl() const
    return mxImpl.get();
}

void X11SalGraphics::SetDrawable( Drawable aDrawable, SalX11Screen nXScreen )
void X11SalGraphics::SetDrawable(Drawable aDrawable, cairo_surface_t* pExternalSurface, SalX11Screen nXScreen)
{
    m_pExternalSurface = pExternalSurface;

    // shortcut if nothing changed
    if( hDrawable_ == aDrawable )
        return;
@@ -165,8 +168,6 @@ void X11SalGraphics::SetDrawable( Drawable aDrawable, SalX11Screen nXScreen )
        XRenderPeer::GetInstance().FreePicture( m_aXRenderPicture );
        m_aXRenderPicture = 0;
    }

    // TODO: moggi: FIXME nTextPixel_     = GetPixel( nTextColor_ );
}

void X11SalGraphics::Init( SalFrame *pFrame, Drawable aTarget,
@@ -181,14 +182,14 @@ void X11SalGraphics::Init( SalFrame *pFrame, Drawable aTarget,
    bWindow_    = true;
    bVirDev_    = false;

    SetDrawable( aTarget, nXScreen );
    SetDrawable(aTarget, nullptr, nXScreen);
    mxImpl->Init();
}

void X11SalGraphics::DeInit()
{
    mxImpl->DeInit();
    SetDrawable( None, m_nXScreen );
    SetDrawable(None, nullptr, m_nXScreen);
}

void X11SalGraphics::SetClipRegion( GC pGC, Region pXReg ) const
@@ -782,6 +783,9 @@ SalGeometryProvider *X11SalGraphics::GetGeometryProvider() const

cairo_t* X11SalGraphics::getCairoContext()
{
    if (m_pExternalSurface)
        return cairo_create(m_pExternalSurface);

    cairo_surface_t* surface = cairo_xlib_surface_create(GetXDisplay(), hDrawable_,
            GetVisual().visual, SAL_MAX_INT16, SAL_MAX_INT16);

diff --git a/vcl/unx/generic/gdi/salvd.cxx b/vcl/unx/generic/gdi/salvd.cxx
index 74de1ba..00a6f0a 100644
--- a/vcl/unx/generic/gdi/salvd.cxx
+++ b/vcl/unx/generic/gdi/salvd.cxx
@@ -59,7 +59,7 @@ std::unique_ptr<SalVirtualDevice> X11SalInstance::CreateVirtualDevice(SalGraphic
    return CreateX11VirtualDevice(pGraphics, nDX, nDY, eFormat, pData, std::make_unique<X11SalGraphics>());
}

void X11SalGraphics::Init( X11SalVirtualDevice *pDevice, SalColormap* pColormap,
void X11SalGraphics::Init( X11SalVirtualDevice *pDevice, cairo_surface_t* pPreExistingTarget, SalColormap* pColormap,
                           bool bDeleteColormap )
{
    SalDisplay *pDisplay  = pDevice->GetDisplay();
@@ -88,8 +88,7 @@ void X11SalGraphics::Init( X11SalVirtualDevice *pDevice, SalColormap* pColormap,
    bWindow_     = pDisplay->IsDisplay();
    bVirDev_     = true;

    const Drawable aVdevDrawable = pDevice->GetDrawable();
    SetDrawable( aVdevDrawable, m_nXScreen );
    SetDrawable(pDevice->GetDrawable(), pPreExistingTarget, m_nXScreen);
    mxImpl->Init();
}

@@ -171,7 +170,11 @@ X11SalVirtualDevice::X11SalVirtualDevice(SalGraphics const * pGraphics, long &nD
    }

    pGraphics_->SetLayout( SalLayoutFlags::NONE ); // by default no! mirroring for VirtualDevices, can be enabled with EnableRTL()
    pGraphics_->Init( this, pColormap, bDeleteColormap );

    // tdf#127529 see SvpSalInstance::CreateVirtualDevice for the rare case of a non-null pPreExistingTarget
    cairo_surface_t* pPreExistingTarget = pData ? static_cast<cairo_surface_t*>(pData->pSurface) : nullptr;

    pGraphics_->Init( this, pPreExistingTarget, pColormap, bDeleteColormap );
}

X11SalVirtualDevice::~X11SalVirtualDevice()
diff --git a/vcl/unx/generic/window/salframe.cxx b/vcl/unx/generic/window/salframe.cxx
index 8d6be94..14b73dc 100644
--- a/vcl/unx/generic/window/salframe.cxx
+++ b/vcl/unx/generic/window/salframe.cxx
@@ -991,9 +991,9 @@ void X11SalFrame::updateGraphics( bool bClear )
{
    Drawable aDrawable = bClear ? None : GetWindow();
    if( pGraphics_ )
        pGraphics_->SetDrawable( aDrawable, m_nXScreen );
        pGraphics_->SetDrawable( aDrawable, nullptr, m_nXScreen );
    if( pFreeGraphics_ )
        pFreeGraphics_->SetDrawable( aDrawable, m_nXScreen );
        pFreeGraphics_->SetDrawable( aDrawable, nullptr, m_nXScreen );
}

void X11SalFrame::SetIcon( sal_uInt16 nIcon )