[Libreoffice-commits] core.git: Branch 'libreoffice-6-3' - include/vcl vcl/headless vcl/inc vcl/qt5 vcl/unx

Caolán McNamara (via logerrit) logerrit at kemper.freedesktop.org
Tue Oct 8 09:57:00 UTC 2019


 include/vcl/sysdata.hxx           |    4 +
 vcl/headless/svpinst.cxx          |   10 +++-
 vcl/headless/svpvd.cxx            |   84 +++++++++++++++++++++-----------------
 vcl/inc/headless/svpvd.hxx        |    5 +-
 vcl/qt5/Qt5Instance.cxx           |   12 +++--
 vcl/qt5/Qt5SvpSurface.cxx         |   20 ++++++++-
 vcl/qt5/Qt5SvpVirtualDevice.hxx   |    5 +-
 vcl/unx/gtk/gtkinst.cxx           |    6 +-
 vcl/unx/gtk3/cairo_gtk3_cairo.cxx |   22 +++++++++
 9 files changed, 115 insertions(+), 53 deletions(-)

New commits:
commit cc03bfe99271f33a38b50778c078f66497bf11f5
Author:     Caolán McNamara <caolanm at redhat.com>
AuthorDate: Thu Oct 3 17:04:10 2019 +0100
Commit:     Adolfo Jayme Barrientos <fitojb at ubuntu.com>
CommitDate: Tue Oct 8 11:56:16 2019 +0200

    tdf#127529 vertical text not drawn in slideshow canvas
    
    because the canvas text drawing impl falls back to using an OutputDevice view
    of the canvas to use the vcl text drawing apis to achieve vertical text
    
    To get an OutputDevice view of the canvas there is a specific VirtualDevice
    ctor available to create a VirtualDevice that, unlike the normal case, doesn't
    have its own specific backing buffer, but instead draws to the underlying target
    provided via the SystemGraphicsData arg
    
    The svp/gtk impl missed that understanding and provided an ordinary
    VirtualDevice with its own backing buffer, not a VirtualDevice that would draw
    to the expected target surface of the canvas. So the vertical text was drawn to
    a different surface than the intended one, and was just discarded.
    
    The cairo use in the canvas long precedes the use of cairo in vcl itself.
    
    Seeing as text is now rendered with cairo in all cases where the canvas uses
    cairo its probably now pointless for canvas to have its own text rendering
    path.
    
    Change-Id: Ie3b0a43ca2b746cbfe25e2d0415315b3d5403cd2
    Reviewed-on: https://gerrit.libreoffice.org/80192
    Tested-by: Jenkins
    Reviewed-by: Adolfo Jayme Barrientos <fitojb at ubuntu.com>

diff --git a/include/vcl/sysdata.hxx b/include/vcl/sysdata.hxx
index 4b7b562da519..03dd3d148087 100644
--- a/include/vcl/sysdata.hxx
+++ b/include/vcl/sysdata.hxx
@@ -143,7 +143,8 @@ struct SystemGraphicsData
     long            hDrawable;      // a drawable
     void*           pVisual;        // the visual in use
     int             nScreen;        // the current screen of the drawable
-    void*           pXRenderFormat;  // render format for drawable
+    void*           pXRenderFormat; // render format for drawable
+    void*           pSurface;       // the cairo surface when using svp-based backends
 #endif
     SystemGraphicsData()
         : nSize( sizeof( SystemGraphicsData ) )
@@ -162,6 +163,7 @@ struct SystemGraphicsData
         , pVisual( nullptr )
         , nScreen( 0 )
         , pXRenderFormat( nullptr )
+        , pSurface( nullptr )
 #endif
     { }
 };
diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx
index 02e332b92fbf..e46e341200ce 100644
--- a/vcl/headless/svpinst.cxx
+++ b/vcl/headless/svpinst.cxx
@@ -235,14 +235,18 @@ void SvpSalInstance::DestroyObject( SalObject* pObject )
 
 #ifndef IOS
 
-std::unique_ptr<SalVirtualDevice> SvpSalInstance::CreateVirtualDevice( SalGraphics* pGraphics,
+std::unique_ptr<SalVirtualDevice> SvpSalInstance::CreateVirtualDevice(SalGraphics* pGraphics,
                                                        long &nDX, long &nDY,
                                                        DeviceFormat eFormat,
-                                                       const SystemGraphicsData* /* pData */ )
+                                                       const SystemGraphicsData* pGd)
 {
     SvpSalGraphics *pSvpSalGraphics = dynamic_cast<SvpSalGraphics*>(pGraphics);
     assert(pSvpSalGraphics);
-    std::unique_ptr<SalVirtualDevice> pNew(new SvpSalVirtualDevice(eFormat, pSvpSalGraphics->getSurface()));
+    // tdf#127529 normally pPreExistingTarget is null and we are a true virtualdevice drawing to a backing buffer.
+    // Occasionally, for canvas/slideshow, pPreExistingTarget is pre-provided as a hack to use the vcl drawing
+    // apis to render onto a preexisting cairo surface. The necessity for that precedes the use of cairo in vcl proper
+    cairo_surface_t* pPreExistingTarget = pGd ? static_cast<cairo_surface_t*>(pGd->pSurface) : nullptr;
+    std::unique_ptr<SalVirtualDevice> pNew(new SvpSalVirtualDevice(eFormat, pSvpSalGraphics->getSurface(), pPreExistingTarget));
     pNew->SetSize( nDX, nDY );
     return pNew;
 }
diff --git a/vcl/headless/svpvd.cxx b/vcl/headless/svpvd.cxx
index a1e415739d6b..70ac5785ec71 100644
--- a/vcl/headless/svpvd.cxx
+++ b/vcl/headless/svpvd.cxx
@@ -31,17 +31,19 @@
 
 using namespace basegfx;
 
-SvpSalVirtualDevice::SvpSalVirtualDevice(DeviceFormat eFormat, cairo_surface_t* pRefSurface)
+SvpSalVirtualDevice::SvpSalVirtualDevice(DeviceFormat eFormat, cairo_surface_t* pRefSurface, cairo_surface_t* pPreExistingTarget)
     : m_eFormat(eFormat)
     , m_pRefSurface(pRefSurface)
-    , m_pSurface(nullptr)
+    , m_pSurface(pPreExistingTarget)
+    , m_bOwnsSurface(!pPreExistingTarget)
 {
     cairo_surface_reference(m_pRefSurface);
 }
 
 SvpSalVirtualDevice::~SvpSalVirtualDevice()
 {
-    cairo_surface_destroy(m_pSurface);
+    if (m_bOwnsSurface)
+        cairo_surface_destroy(m_pSurface);
     cairo_surface_destroy(m_pRefSurface);
 }
 
@@ -68,6 +70,44 @@ bool SvpSalVirtualDevice::SetSize( long nNewDX, long nNewDY )
     return SetSizeUsingBuffer(nNewDX, nNewDY, nullptr);
 }
 
+void SvpSalVirtualDevice::CreateSurface(long nNewDX, long nNewDY, sal_uInt8 *const pBuffer)
+{
+    if (m_pSurface)
+    {
+        cairo_surface_destroy(m_pSurface);
+    }
+
+    if (m_eFormat == DeviceFormat::BITMASK)
+    {
+        m_pSurface = cairo_surface_create_similar(m_pRefSurface, CAIRO_CONTENT_ALPHA,
+                            nNewDX, nNewDY);
+    }
+    else if (pBuffer)
+    {
+        double fXScale, fYScale;
+        if (comphelper::LibreOfficeKit::isActive())
+        {
+            // Force scaling of the painting
+            fXScale = fYScale = comphelper::LibreOfficeKit::getDPIScale();
+        }
+        else
+        {
+            dl_cairo_surface_get_device_scale(m_pRefSurface, &fXScale, &fYScale);
+            nNewDX *= fXScale;
+            nNewDY *= fYScale;
+        }
+
+        m_pSurface = cairo_image_surface_create_for_data(pBuffer, CAIRO_FORMAT_ARGB32,
+                            nNewDX, nNewDY, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, nNewDX));
+
+        dl_cairo_surface_set_device_scale(m_pSurface, fXScale, fYScale);
+    }
+    else
+    {
+        m_pSurface = cairo_surface_create_similar(m_pRefSurface, CAIRO_CONTENT_COLOR_ALPHA, nNewDX, nNewDY);
+    }
+}
+
 bool SvpSalVirtualDevice::SetSizeUsingBuffer( long nNewDX, long nNewDY,
         sal_uInt8 *const pBuffer)
 {
@@ -77,44 +117,14 @@ bool SvpSalVirtualDevice::SetSizeUsingBuffer( long nNewDX, long nNewDY,
         nNewDY = 1;
 
     if (!m_pSurface || m_aFrameSize.getX() != nNewDX ||
-                       m_aFrameSize.getY() != nNewDY )
+                       m_aFrameSize.getY() != nNewDY)
     {
         m_aFrameSize = basegfx::B2IVector(nNewDX, nNewDY);
 
-        if (m_pSurface)
-        {
-            cairo_surface_destroy(m_pSurface);
-        }
+        if (m_bOwnsSurface)
+            CreateSurface(nNewDX, nNewDY, pBuffer);
 
-        if (m_eFormat == DeviceFormat::BITMASK)
-        {
-            m_pSurface = cairo_surface_create_similar(m_pRefSurface, CAIRO_CONTENT_ALPHA,
-                                nNewDX, nNewDY);
-        }
-        else if (pBuffer)
-        {
-            double fXScale, fYScale;
-            if (comphelper::LibreOfficeKit::isActive())
-            {
-                // Force scaling of the painting
-                fXScale = fYScale = comphelper::LibreOfficeKit::getDPIScale();
-            }
-            else
-            {
-                dl_cairo_surface_get_device_scale(m_pRefSurface, &fXScale, &fYScale);
-                nNewDX *= fXScale;
-                nNewDY *= fYScale;
-            }
-
-            m_pSurface = cairo_image_surface_create_for_data(pBuffer, CAIRO_FORMAT_ARGB32,
-                                nNewDX, nNewDY, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, nNewDX));
-
-            dl_cairo_surface_set_device_scale(m_pSurface, fXScale, fYScale);
-        }
-        else
-        {
-            m_pSurface = cairo_surface_create_similar(m_pRefSurface, CAIRO_CONTENT_COLOR_ALPHA, nNewDX, nNewDY);
-        }
+        assert(m_pSurface);
 
         // update device in existing graphics
         for (auto const& graphic : m_aGraphics)
diff --git a/vcl/inc/headless/svpvd.hxx b/vcl/inc/headless/svpvd.hxx
index 3da74b5e1ba8..9f83026c77db 100644
--- a/vcl/inc/headless/svpvd.hxx
+++ b/vcl/inc/headless/svpvd.hxx
@@ -34,14 +34,17 @@ class VCL_DLLPUBLIC SvpSalVirtualDevice : public SalVirtualDevice
     DeviceFormat const                  m_eFormat;
     cairo_surface_t* const              m_pRefSurface;
     cairo_surface_t*                    m_pSurface;
+    bool                                m_bOwnsSurface; // nearly always true, except for edge case of tdf#127529
     basegfx::B2IVector                  m_aFrameSize;
     std::vector< SvpSalGraphics* >      m_aGraphics;
 
+    void CreateSurface(long nNewDX, long nNewDY, sal_uInt8 *const pBuffer);
+
 protected:
     SvpSalGraphics* AddGraphics(SvpSalGraphics* aGraphics);
 
 public:
-    SvpSalVirtualDevice(DeviceFormat eFormat, cairo_surface_t* pRefSurface);
+    SvpSalVirtualDevice(DeviceFormat eFormat, cairo_surface_t* pRefSurface, cairo_surface_t* pPreExistingTarget);
     virtual ~SvpSalVirtualDevice() override;
 
     // SalVirtualDevice
diff --git a/vcl/qt5/Qt5Instance.cxx b/vcl/qt5/Qt5Instance.cxx
index 8eee8ad955d9..769024898192 100644
--- a/vcl/qt5/Qt5Instance.cxx
+++ b/vcl/qt5/Qt5Instance.cxx
@@ -288,16 +288,20 @@ void Qt5Instance::DestroyObject(SalObject* pObject)
     }
 }
 
-std::unique_ptr<SalVirtualDevice>
-Qt5Instance::CreateVirtualDevice(SalGraphics* pGraphics, long& nDX, long& nDY, DeviceFormat eFormat,
-                                 const SystemGraphicsData* /* pData */)
+std::unique_ptr<SalVirtualDevice> Qt5Instance::CreateVirtualDevice(SalGraphics* pGraphics,
+                                                                   long& nDX, long& nDY,
+                                                                   DeviceFormat eFormat,
+                                                                   const SystemGraphicsData* pGd)
 {
     if (m_bUseCairo)
     {
         SvpSalGraphics* pSvpSalGraphics = dynamic_cast<Qt5SvpGraphics*>(pGraphics);
         assert(pSvpSalGraphics);
+        // tdf#127529 see SvpSalInstance::CreateVirtualDevice for the rare case of a non-null pPreExistingTarget
+        cairo_surface_t* pPreExistingTarget
+            = pGd ? static_cast<cairo_surface_t*>(pGd->pSurface) : nullptr;
         std::unique_ptr<SalVirtualDevice> pVD(
-            new Qt5SvpVirtualDevice(eFormat, pSvpSalGraphics->getSurface()));
+            new Qt5SvpVirtualDevice(eFormat, pSvpSalGraphics->getSurface(), pPreExistingTarget));
         pVD->SetSize(nDX, nDY);
         return pVD;
     }
diff --git a/vcl/qt5/Qt5SvpSurface.cxx b/vcl/qt5/Qt5SvpSurface.cxx
index 00f6004bd2a0..7877ab57391c 100644
--- a/vcl/qt5/Qt5SvpSurface.cxx
+++ b/vcl/qt5/Qt5SvpSurface.cxx
@@ -19,6 +19,18 @@
 #include <vcl/window.hxx>
 #include <basegfx/vector/b2isize.hxx>
 
+namespace
+{
+Size get_surface_size(cairo_surface_t* surface)
+{
+    cairo_t* cr = cairo_create(surface);
+    double x1, x2, y1, y2;
+    cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+    cairo_destroy(cr);
+    return Size(x2 - x1, y2 - y1);
+}
+}
+
 namespace cairo
 {
 Qt5SvpSurface::Qt5SvpSurface(const CairoSurfaceSharedPtr& pSurface)
@@ -65,7 +77,13 @@ void Qt5SvpSurface::flush() const
 
 VclPtr<VirtualDevice> Qt5SvpSurface::createVirtualDevice() const
 {
-    return VclPtrInstance<VirtualDevice>(nullptr, Size(1, 1), DeviceFormat::DEFAULT);
+    SystemGraphicsData aSystemGraphicsData;
+
+    aSystemGraphicsData.nSize = sizeof(SystemGraphicsData);
+    aSystemGraphicsData.pSurface = m_pSurface.get();
+
+    return VclPtr<VirtualDevice>::Create(&aSystemGraphicsData, get_surface_size(m_pSurface.get()),
+                                         DeviceFormat::DEFAULT);
 }
 
 } // namespace cairo
diff --git a/vcl/qt5/Qt5SvpVirtualDevice.hxx b/vcl/qt5/Qt5SvpVirtualDevice.hxx
index 75c446bafb33..0eb4ed26ed2f 100644
--- a/vcl/qt5/Qt5SvpVirtualDevice.hxx
+++ b/vcl/qt5/Qt5SvpVirtualDevice.hxx
@@ -25,8 +25,9 @@
 class VCL_DLLPUBLIC Qt5SvpVirtualDevice : public SvpSalVirtualDevice
 {
 public:
-    Qt5SvpVirtualDevice(DeviceFormat eFormat, cairo_surface_t* pRefSurface)
-        : SvpSalVirtualDevice(eFormat, pRefSurface)
+    Qt5SvpVirtualDevice(DeviceFormat eFormat, cairo_surface_t* pRefSurface,
+                        cairo_surface_t* pPreExistingTarget)
+        : SvpSalVirtualDevice(eFormat, pRefSurface, pPreExistingTarget)
     {
     }
 
diff --git a/vcl/unx/gtk/gtkinst.cxx b/vcl/unx/gtk/gtkinst.cxx
index f18dc9457fd5..02ed688f366b 100644
--- a/vcl/unx/gtk/gtkinst.cxx
+++ b/vcl/unx/gtk/gtkinst.cxx
@@ -334,10 +334,12 @@ std::unique_ptr<SalVirtualDevice> GtkInstance::CreateVirtualDevice( SalGraphics
 {
     EnsureInit();
 #if GTK_CHECK_VERSION(3,0,0)
-    (void) pGd;
     SvpSalGraphics *pSvpSalGraphics = dynamic_cast<SvpSalGraphics*>(pG);
     assert(pSvpSalGraphics);
-    std::unique_ptr<SalVirtualDevice> pNew(new SvpSalVirtualDevice(eFormat, pSvpSalGraphics->getSurface()));
+    // tdf#127529 see SvpSalInstance::CreateVirtualDevice for the rare case of a non-null pPreExistingTarget
+    cairo_surface_t* pPreExistingTarget
+        = pGd ? static_cast<cairo_surface_t*>(pGd->pSurface) : nullptr;
+    std::unique_ptr<SalVirtualDevice> pNew(new SvpSalVirtualDevice(eFormat, pSvpSalGraphics->getSurface(), pPreExistingTarget));
     pNew->SetSize( nDX, nDY );
     return pNew;
 #else
diff --git a/vcl/unx/gtk3/cairo_gtk3_cairo.cxx b/vcl/unx/gtk3/cairo_gtk3_cairo.cxx
index 73a650e2757c..de32599b480e 100644
--- a/vcl/unx/gtk3/cairo_gtk3_cairo.cxx
+++ b/vcl/unx/gtk3/cairo_gtk3_cairo.cxx
@@ -19,6 +19,18 @@
 
 #include <unx/gtk/gtkgdi.hxx>
 
+namespace
+{
+    Size get_surface_size(cairo_surface_t *surface)
+    {
+        cairo_t *cr = cairo_create(surface);
+        double x1, x2, y1, y2;
+        cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
+        cairo_destroy(cr);
+        return Size(x2 - x1, y2 - y1);
+    }
+}
+
 namespace cairo
 {
     /**
@@ -108,9 +120,15 @@ namespace cairo
 
     VclPtr<VirtualDevice> Gtk3Surface::createVirtualDevice() const
     {
-        return VclPtrInstance<VirtualDevice>(nullptr, Size(1, 1), DeviceFormat::DEFAULT);
-    }
+        SystemGraphicsData aSystemGraphicsData;
 
+        aSystemGraphicsData.nSize = sizeof(SystemGraphicsData);
+        aSystemGraphicsData.pSurface = mpSurface.get();
+
+        return VclPtr<VirtualDevice>::Create(&aSystemGraphicsData,
+                              get_surface_size(mpSurface.get()),
+                              DeviceFormat::DEFAULT);
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list