From 6e2a7571e8ee4960f54610ba790394202c4d7aed Mon Sep 17 00:00:00 2001 From: Caolán McNamara Date: Thu, 3 Oct 2019 19:45:20 +0100 Subject: tdf#127529 vertical text not drawn in slideshow canvas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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/80162 Tested-by: Jenkins Reviewed-by: Caolán McNamara Tested-by: Caolán McNamara --- include/vcl/sysdata.hxx | 4 +++- vcl/headless/svpinst.cxx | 10 +++++++--- vcl/headless/svpvd.cxx | 15 +++++++++------ vcl/inc/headless/svpvd.hxx | 3 ++- vcl/qt5/Qt5Instance.cxx | 12 ++++++++---- vcl/qt5/Qt5SvpSurface.cxx | 21 +++++++++++++++++++-- vcl/qt5/Qt5SvpVirtualDevice.hxx | 5 +++-- vcl/unx/gtk3/cairo_gtk3_cairo.cxx | 23 ++++++++++++++++++++--- vcl/unx/gtk3/gtk3gtkinst.cxx | 6 ++++-- 9 files changed, 75 insertions(+), 24 deletions(-) diff --git a/include/vcl/sysdata.hxx b/include/vcl/sysdata.hxx index 28f991db4878..722c223f5e19 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 2070f68e1663..6b415d39135f 100644 --- a/vcl/headless/svpinst.cxx +++ b/vcl/headless/svpinst.cxx @@ -240,14 +240,18 @@ void SvpSalInstance::DestroyObject( SalObject* pObject ) #ifndef IOS -std::unique_ptr SvpSalInstance::CreateVirtualDevice( SalGraphics* pGraphics, +std::unique_ptr SvpSalInstance::CreateVirtualDevice(SalGraphics* pGraphics, long &nDX, long &nDY, DeviceFormat eFormat, - const SystemGraphicsData* /* pData */ ) + const SystemGraphicsData* pGd) { SvpSalGraphics *pSvpSalGraphics = dynamic_cast(pGraphics); assert(pSvpSalGraphics); - std::unique_ptr 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(pGd->pSurface) : nullptr; + std::unique_ptr 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 686587f9deab..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); } @@ -70,8 +72,6 @@ bool SvpSalVirtualDevice::SetSize( long nNewDX, long nNewDY ) void SvpSalVirtualDevice::CreateSurface(long nNewDX, long nNewDY, sal_uInt8 *const pBuffer) { - m_aFrameSize = basegfx::B2IVector(nNewDX, nNewDY); - if (m_pSurface) { cairo_surface_destroy(m_pSurface); @@ -121,7 +121,10 @@ bool SvpSalVirtualDevice::SetSizeUsingBuffer( long nNewDX, long nNewDY, { m_aFrameSize = basegfx::B2IVector(nNewDX, nNewDY); - CreateSurface(nNewDX, nNewDY, pBuffer); + if (m_bOwnsSurface) + CreateSurface(nNewDX, nNewDY, pBuffer); + + 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 b069c63286d1..9f83026c77db 100644 --- a/vcl/inc/headless/svpvd.hxx +++ b/vcl/inc/headless/svpvd.hxx @@ -34,6 +34,7 @@ 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; @@ -43,7 +44,7 @@ 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 64481b64108e..129eb8e5c221 100644 --- a/vcl/qt5/Qt5Instance.cxx +++ b/vcl/qt5/Qt5Instance.cxx @@ -288,16 +288,20 @@ void Qt5Instance::DestroyObject(SalObject* pObject) } } -std::unique_ptr -Qt5Instance::CreateVirtualDevice(SalGraphics* pGraphics, long& nDX, long& nDY, DeviceFormat eFormat, - const SystemGraphicsData* /* pData */) +std::unique_ptr Qt5Instance::CreateVirtualDevice(SalGraphics* pGraphics, + long& nDX, long& nDY, + DeviceFormat eFormat, + const SystemGraphicsData* pGd) { if (m_bUseCairo) { SvpSalGraphics* pSvpSalGraphics = dynamic_cast(pGraphics); assert(pSvpSalGraphics); + // tdf#127529 see SvpSalInstance::CreateVirtualDevice for the rare case of a non-null pPreExistingTarget + cairo_surface_t* pPreExistingTarget + = pGd ? static_cast(pGd->pSurface) : nullptr; std::unique_ptr 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 3e300755a992..21e0ca03b5b2 100644 --- a/vcl/qt5/Qt5SvpSurface.cxx +++ b/vcl/qt5/Qt5SvpSurface.cxx @@ -19,6 +19,18 @@ #include #include +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,8 +77,13 @@ void Qt5SvpSurface::flush() const VclPtr Qt5SvpSurface::createVirtualDevice() const { - //TODO allow creating a VirtualDevice to draw to the current surface - return VclPtrInstance(DeviceFormat::DEFAULT); + SystemGraphicsData aSystemGraphicsData; + + aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); + aSystemGraphicsData.pSurface = m_pSurface.get(); + + return VclPtr::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/gtk3/cairo_gtk3_cairo.cxx b/vcl/unx/gtk3/cairo_gtk3_cairo.cxx index 9b273ea16cf5..5f0e0b7a136f 100644 --- a/vcl/unx/gtk3/cairo_gtk3_cairo.cxx +++ b/vcl/unx/gtk3/cairo_gtk3_cairo.cxx @@ -19,6 +19,18 @@ #include +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,10 +120,15 @@ namespace cairo VclPtr Gtk3Surface::createVirtualDevice() const { - //TODO allow creating a VirtualDevice to draw to the current surface - return VclPtrInstance(DeviceFormat::DEFAULT); - } + SystemGraphicsData aSystemGraphicsData; + aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); + aSystemGraphicsData.pSurface = mpSurface.get(); + + return VclPtr::Create(aSystemGraphicsData, + get_surface_size(mpSurface.get()), + DeviceFormat::DEFAULT); + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index 544145d906dc..fd8db4675ff3 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -322,12 +322,14 @@ void GtkYieldMutex::ThreadsLeave() std::unique_ptr GtkInstance::CreateVirtualDevice( SalGraphics *pG, long &nDX, long &nDY, DeviceFormat eFormat, - const SystemGraphicsData* /*pGd*/ ) + const SystemGraphicsData* pGd ) { EnsureInit(); SvpSalGraphics *pSvpSalGraphics = dynamic_cast(pG); assert(pSvpSalGraphics); - std::unique_ptr 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(pGd->pSurface) : nullptr; + std::unique_ptr pNew(new SvpSalVirtualDevice(eFormat, pSvpSalGraphics->getSurface(), pPreExistingTarget)); pNew->SetSize( nDX, nDY ); return pNew; } -- cgit