Repository.mk                                               |    3 
 bin/find-can-be-private-symbols.functions.results           |    2 
 bin/find-mergedlib-can-be-private-symbols.functions.results |    6 
 canvas/Library_cairocanvas.mk                               |   75 
 canvas/Library_directx9canvas.mk                            |   69 
 canvas/Library_gdipluscanvas.mk                             |   60 
 canvas/Module_canvas.mk                                     |   14 
 canvas/StaticLibrary_directxcanvas.mk                       |   41 
 canvas/inc/pch/precompiled_cairocanvas.hxx                  |   89 
 canvas/source/cairo/cairo_cachedbitmap.cxx                  |   77 
 canvas/source/cairo/cairo_cachedbitmap.hxx                  |   58 
 canvas/source/cairo/cairo_canvas.cxx                        |  189 +
 canvas/source/cairo/cairo_canvas.hxx                        |  142 
 canvas/source/cairo/cairo_canvasbitmap.cxx                  |  163 
 canvas/source/cairo/cairo_canvasbitmap.hxx                  |  125 
 canvas/source/cairo/cairo_canvascustomsprite.cxx            |  151 
 canvas/source/cairo/cairo_canvascustomsprite.hxx            |  145 
 canvas/source/cairo/cairo_canvasfont.cxx                    |  161 
 canvas/source/cairo/cairo_canvasfont.hxx                    |   84 
 canvas/source/cairo/cairo_canvashelper.cxx                  | 2045 ++++++++++++
 canvas/source/cairo/cairo_canvashelper.hxx                  |  271 +
 canvas/source/cairo/cairo_canvashelper_text.cxx             |  303 +
 canvas/source/cairo/cairo_devicehelper.cxx                  |  257 +
 canvas/source/cairo/cairo_devicehelper.hxx                  |  122 
 canvas/source/cairo/cairo_repainttarget.hxx                 |   48 
 canvas/source/cairo/cairo_sprite.hxx                        |   65 
 canvas/source/cairo/cairo_spritecanvas.cxx                  |  232 +
 canvas/source/cairo/cairo_spritecanvas.hxx                  |  159 
 canvas/source/cairo/cairo_spritecanvashelper.cxx            |  518 +++
 canvas/source/cairo/cairo_spritecanvashelper.hxx            |  140 
 canvas/source/cairo/cairo_spritedevicehelper.cxx            |  153 
 canvas/source/cairo/cairo_spritedevicehelper.hxx            |   77 
 canvas/source/cairo/cairo_spritehelper.cxx                  |  195 +
 canvas/source/cairo/cairo_spritehelper.hxx                  |  102 
 canvas/source/cairo/cairo_surfaceprovider.hxx               |   70 
 canvas/source/cairo/cairo_textlayout.cxx                    |  363 ++
 canvas/source/cairo/cairo_textlayout.hxx                    |  107 
 canvas/source/cairo/cairocanvas.component                   |   30 
 canvas/source/directx/directx9canvas.component              |   26 
 canvas/source/directx/dx_9rm.cxx                            | 1201 +++++++
 canvas/source/directx/dx_bitmap.cxx                         |  204 +
 canvas/source/directx/dx_bitmap.hxx                         |   82 
 canvas/source/directx/dx_bitmapcanvashelper.cxx             |  221 +
 canvas/source/directx/dx_bitmapcanvashelper.hxx             |  126 
 canvas/source/directx/dx_bitmapprovider.hxx                 |   34 
 canvas/source/directx/dx_canvas.cxx                         |  256 +
 canvas/source/directx/dx_canvas.hxx                         |  173 +
 canvas/source/directx/dx_canvasbitmap.cxx                   |  257 +
 canvas/source/directx/dx_canvasbitmap.hxx                   |   91 
 canvas/source/directx/dx_canvascustomsprite.cxx             |  106 
 canvas/source/directx/dx_canvascustomsprite.hxx             |  130 
 canvas/source/directx/dx_canvasfont.cxx                     |  162 
 canvas/source/directx/dx_canvasfont.hxx                     |   92 
 canvas/source/directx/dx_canvashelper.cxx                   |  813 ++++
 canvas/source/directx/dx_canvashelper.hxx                   |  252 +
 canvas/source/directx/dx_canvashelper_texturefill.cxx       |  608 +++
 canvas/source/directx/dx_config.cxx                         |  152 
 canvas/source/directx/dx_config.hxx                         |   80 
 canvas/source/directx/dx_devicehelper.cxx                   |  198 +
 canvas/source/directx/dx_devicehelper.hxx                   |  114 
 canvas/source/directx/dx_gdiplususer.cxx                    |   74 
 canvas/source/directx/dx_gdiplususer.hxx                    |   45 
 canvas/source/directx/dx_graphicsprovider.hxx               |   46 
 canvas/source/directx/dx_ibitmap.hxx                        |   62 
 canvas/source/directx/dx_impltools.cxx                      |  629 +++
 canvas/source/directx/dx_impltools.hxx                      |  124 
 canvas/source/directx/dx_linepolypolygon.cxx                |   59 
 canvas/source/directx/dx_linepolypolygon.hxx                |   47 
 canvas/source/directx/dx_rendermodule.hxx                   |   80 
 canvas/source/directx/dx_sprite.hxx                         |   45 
 canvas/source/directx/dx_spritecanvas.cxx                   |  192 +
 canvas/source/directx/dx_spritecanvas.hxx                   |  155 
 canvas/source/directx/dx_spritecanvashelper.cxx             |  352 ++
 canvas/source/directx/dx_spritecanvashelper.hxx             |  152 
 canvas/source/directx/dx_spritedevicehelper.cxx             |  221 +
 canvas/source/directx/dx_spritedevicehelper.hxx             |   98 
 canvas/source/directx/dx_spritehelper.cxx                   |  199 +
 canvas/source/directx/dx_spritehelper.hxx                   |  102 
 canvas/source/directx/dx_surfacebitmap.cxx                  |  654 +++
 canvas/source/directx/dx_surfacebitmap.hxx                  |  135 
 canvas/source/directx/dx_surfacegraphics.cxx                |   77 
 canvas/source/directx/dx_surfacegraphics.hxx                |   36 
 canvas/source/directx/dx_textlayout.cxx                     |  253 +
 canvas/source/directx/dx_textlayout.hxx                     |  107 
 canvas/source/directx/dx_textlayout_drawhelper.cxx          |  312 +
 canvas/source/directx/dx_textlayout_drawhelper.hxx          |   78 
 canvas/source/directx/dx_vcltools.cxx                       |  309 +
 canvas/source/directx/dx_vcltools.hxx                       |   47 
 canvas/source/directx/dx_winstuff.hxx                       |   71 
 canvas/source/directx/gdipluscanvas.component               |   30 
 compilerplugins/clang/unusedfields.readonly.results         |    4 
 compilerplugins/clang/virtualdead.unusedparams.results      |    3 
 cppcanvas/CppunitTest_cppcanvas_emfplus.mk                  |    1 
 cppcanvas/CppunitTest_cppcanvas_test.mk                     |    1 
 include/vcl/BitmapTools.hxx                                 |    6 
 include/vcl/bitmap.hxx                                      |   21 
 include/vcl/cairo.hxx                                       |   35 
 include/vcl/outdev.hxx                                      |   10 
 include/vcl/sysdata.hxx                                     |   10 
 include/vcl/virdev.hxx                                      |    9 
 officecfg/registry/data/org/openoffice/Office/Canvas.xcu    |   21 
 solenv/gbuild/extensions/pre_MergedLibsList.mk              |    3 
 vcl/Library_vclplug_gen.mk                                  |    1 
 vcl/Library_vclplug_gtk3.mk                                 |    1 
 vcl/Library_vclplug_gtk3_kde5.mk                            |    1 
 vcl/Library_vclplug_gtk4.mk                                 |    1 
 vcl/Library_vclplug_qt5.mk                                  |    1 
 vcl/Library_vclplug_qt6.mk                                  |    1 
 vcl/headless/svpbmp.cxx                                     |    5 
 vcl/headless/svpgdi.cxx                                     |   28 
 vcl/headless/svpinst.cxx                                    |   23 
 vcl/inc/headless/svpbmp.hxx                                 |    1 
 vcl/inc/headless/svpgdi.hxx                                 |    8 
 vcl/inc/headless/svpinst.hxx                                |    9 
 vcl/inc/osx/salinst.h                                       |    5 
 vcl/inc/qt5/QtBitmap.hxx                                    |    1 
 vcl/inc/qt5/QtGraphics.hxx                                  |   13 
 vcl/inc/qt5/QtInstance.hxx                                  |    4 
 vcl/inc/qt5/QtSvpGraphics.hxx                               |   10 
 vcl/inc/qt5/QtSvpSurface.hxx                                |   44 
 vcl/inc/qt6/QtSvpSurface.hxx                                |   12 
 vcl/inc/quartz/salbmp.h                                     |    2 
 vcl/inc/quartz/salvd.h                                      |    1 
 vcl/inc/salbmp.hxx                                          |    2 
 vcl/inc/salgdi.hxx                                          |   14 
 vcl/inc/salinst.hxx                                         |    9 
 vcl/inc/skia/salbmp.hxx                                     |    2 
 vcl/inc/skia/x11/salvd.hxx                                  |    3 
 vcl/inc/unx/genpspgraphics.h                                |    8 
 vcl/inc/unx/gtk/gtkgdi.hxx                                  |    8 
 vcl/inc/unx/gtk/gtkinst.hxx                                 |    5 
 vcl/inc/unx/salgdi.h                                        |    8 
 vcl/inc/unx/salinst.h                                       |    6 
 vcl/inc/unx/salvd.h                                         |    2 
 vcl/inc/win/salbmp.h                                        |    1 
 vcl/inc/win/salinst.h                                       |    4 
 vcl/qt5/QtBitmap.cxx                                        |    2 
 vcl/qt5/QtGraphics.cxx                                      |   31 
 vcl/qt5/QtInstance.cxx                                      |   23 
 vcl/qt5/QtSvpGraphics.cxx                                   |   28 
 vcl/qt5/QtSvpSurface.cxx                                    |   91 
 vcl/qt6/QtSvpSurface.cxx                                    |   12 
 vcl/quartz/salbmp.cxx                                       |   60 
 vcl/quartz/salvd.cxx                                        |   59 
 vcl/skia/salbmp.cxx                                         |    8 
 vcl/skia/x11/salvd.cxx                                      |   18 
 vcl/source/bitmap/BitmapTools.cxx                           |  336 +
 vcl/source/bitmap/bitmap.cxx                                |    6 
 vcl/source/gdi/virdev.cxx                                   |   22 
 vcl/source/outdev/outdev.cxx                                |   45 
 vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx             |    1 
 vcl/unx/generic/gdi/cairo_xlib_cairo.cxx                    |  277 +
 vcl/unx/generic/gdi/cairo_xlib_cairo.hxx                    |   93 
 vcl/unx/generic/gdi/salgdi.cxx                              |   77 
 vcl/unx/generic/gdi/salvd.cxx                               |   82 
 vcl/unx/generic/print/genpspgraphics.cxx                    |   29 
 vcl/unx/gtk3/gtkcairo.cxx                                   |  129 
 vcl/unx/gtk3/gtkcairo.hxx                                   |   46 
 vcl/unx/gtk3/gtkinst.cxx                                    |   16 
 vcl/unx/gtk3/salnativewidgets-gtk.cxx                       |   26 
 vcl/unx/gtk3_kde5/gtk3_kde5_cairo.cxx                       |   22 
 vcl/unx/gtk4/gtkcairo.cxx                                   |   12 
 vcl/unx/gtk4/gtkcairo.hxx                                   |   12 
 vcl/win/gdi/salbmp.cxx                                      |   14 
 vcl/win/gdi/salvd.cxx                                       |   31 
 vcl/win/window/salframe.cxx                                 |    3 
 166 files changed, 19047 insertions(+), 12 deletions(-)

New commits:
commit 5357da349b4b266b4003d25b61ecb12a515893c4
Author:     Noel Grandin <noelgran...@gmail.com>
AuthorDate: Fri Feb 21 08:52:56 2025 +0200
Commit:     Noel Grandin <noelgran...@gmail.com>
CommitDate: Fri Feb 21 10:40:31 2025 +0100

    Revert "remove canvas/cairo and canvas/gdi and canvas/directx backends"
    
    So the vclcanvas backend is in worse shape than I thought. It will
    take too long to get it into shape to be sure of making the next
    release, so revert this for now, and I will have to find another
    approach.
    
    This reverts the following commits
    
    commit fbefe07e4c4a8959278ea08a247d75612994727c
    Author: Michael Weghorn <m.wegh...@posteo.de>
    Date:   Thu Feb 20 09:42:14 2025 +0100
    
        qt: Remove now unused vcl/inc/qt6/QtSvpSurface.hxx
    
    commit 595354ab7e01546765d84103aaf2bc38e5d3c9b3
    Author: Julien Nabet <serval2...@yahoo.fr>
    Date:   Wed Feb 19 21:13:49 2025 +0100
    
        Remove also canvas/cairo in gtk4, qt6 and gtk3_kde5
    
    commit d539f6e99e1be89e6133b2ef623c67bf4f0cff4f
    Author: Noel Grandin <noelgran...@gmail.com>
    Date:   Wed Feb 19 18:15:30 2025 +0200
    
        fix "local variable is unused" warning
    
    commit 704f61b1bd2c54831c383e34e74315bd6da356e2
    Author: Noel Grandin <noelgran...@collabora.co.uk>
    Date:   Wed Jan 29 15:35:21 2025 +0200
    
        remove canvas/cairo and canvas/gdi and canvas/directx backends
    
    Change-Id: I0492dabf7da8c42a15720c868f161919e8dc7ae4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181984
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/Repository.mk b/Repository.mk
index fb074d489aae..277a1fb99b8b 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -355,9 +355,12 @@ endif
 ifneq ($(ENABLE_WASM_STRIP_CANVAS),TRUE)
 $(eval $(call gb_Helper_register_libraries_for_install,OOOLIBS,ooo, \
        canvastools \
+       $(if $(ENABLE_CAIRO_CANVAS),cairocanvas) \
        canvasfactory \
        cppcanvas \
+       $(if $(filter WNT,$(OS)),directx9canvas) \
        $(if $(ENABLE_OPENGL_CANVAS),oglcanvas) \
+       $(if $(filter WNT,$(OS)),gdipluscanvas) \
        simplecanvas \
        vclcanvas \
 ))
diff --git a/bin/find-can-be-private-symbols.functions.results 
b/bin/find-can-be-private-symbols.functions.results
index 5dbaf427cb17..ed4b5100cec2 100644
--- a/bin/find-can-be-private-symbols.functions.results
+++ b/bin/find-can-be-private-symbols.functions.results
@@ -1670,6 +1670,7 @@ QtSvpGraphics::CreateSurface(OutputDevice const&, int, 
int, int, int) const
 QtSvpGraphics::CreateSurface(std::shared_ptr<_cairo_surface> const&) const
 QtSvpGraphics::GetResolution(int&, int&)
 QtSvpGraphics::QtSvpGraphics(QtFrame*)
+QtSvpGraphics::SupportsCairo() const
 QtSvpGraphics::handleDamage(tools::Rectangle const&)
 QtSvpGraphics::updateQWidget() const
 QtSvpGraphics::~QtSvpGraphics()
@@ -5770,6 +5771,7 @@ SkiaSalBitmap::GetAsSkBitmap() const
 SkiaSalBitmap::GetBitCount() const
 SkiaSalBitmap::GetImageKey(SkiaHelper::DirectImage) const
 SkiaSalBitmap::GetSkShader(SkSamplingOptions const&, SkiaHelper::DirectImage) 
const
+SkiaSalBitmap::GetSystemData(BitmapSystemData&)
 SkiaSalBitmap::Invert()
 SkiaSalBitmap::IsAllBlack() const
 SkiaSalBitmap::IsFullyOpaqueAsAlpha() const
diff --git a/bin/find-mergedlib-can-be-private-symbols.functions.results 
b/bin/find-mergedlib-can-be-private-symbols.functions.results
index cbdb7c75b544..51f40068f0f0 100644
--- a/bin/find-mergedlib-can-be-private-symbols.functions.results
+++ b/bin/find-mergedlib-can-be-private-symbols.functions.results
@@ -82,6 +82,7 @@ BigInt::operator%=(BigInt const&)
 BigInt::operator=(BigInt const&)
 Bitmap::CreateAlphaMask(Color const&) const
 Bitmap::CreateMask(Color const&) const
+Bitmap::GetSystemData(BitmapSystemData&) const
 Bitmap::RemoveBlendedStartColor(Color const&, AlphaMask const&)
 BitmapBasicMorphologyFilter::BitmapBasicMorphologyFilter(BasicMorphologyOp, 
int, unsigned char)
 BitmapBasicMorphologyFilter::filter(Bitmap const&) const
@@ -1786,6 +1787,7 @@ OutlinerView::Indent(short)
 OutputDevice::AddFontSubstitute(rtl::OUString const&, rtl::OUString const&, 
AddFontSubstituteFlags)
 OutputDevice::AddHatchActions(tools::PolyPolygon const&, Hatch const&, 
GDIMetaFile&)
 OutputDevice::BeginFontSubstitution()
+OutputDevice::CreateBitmapSurface(BitmapSystemData const&, Size const&) const
 OutputDevice::CreateSurface(int, int, int, int) const
 OutputDevice::CreateSurface(std::shared_ptr<_cairo_surface> const&) const
 OutputDevice::CreateUnoGraphicsList()
@@ -1799,6 +1801,7 @@ OutputDevice::GetGlyphBoundRects(Point const&, 
rtl::OUString const&, int, int, s
 OutputDevice::GetGraphics() const
 OutputDevice::GetInverseViewTransformation(MapMode const&) const
 OutputDevice::GetNativeControlRegion(ControlType, ControlPart, 
tools::Rectangle const&, ControlState, ImplControlValue const&, 
tools::Rectangle&, tools::Rectangle&) const
+OutputDevice::GetNativeSurfaceHandle(std::shared_ptr<cairo::Surface>&, 
basegfx::B2ISize const&) const
 OutputDevice::GetRenderBackendName() const
 OutputDevice::GetSpriteCanvas() const
 OutputDevice::GetTextBoundRect(basegfx::B2DRange&, rtl::OUString const&, int, 
int, int, unsigned long, KernArraySpan, std::span<unsigned char const, 
18446744073709551615ul>, SalLayoutGlyphs const*) const
@@ -1817,6 +1820,7 @@ OutputDevice::PixelToLogic(vcl::Region const&) const
 OutputDevice::RefreshFontData(bool)
 OutputDevice::RemoveFontsSubstitute()
 OutputDevice::RemoveTransparenciesFromMetaFile(GDIMetaFile const&, 
GDIMetaFile&, long, long, bool, bool, bool, Color const&)
+OutputDevice::SupportsCairo() const
 PDFSignatureHelper::GetNewSecurityId() const
 
PDFSignatureHelper::ReadAndVerifySignature(com::sun::star::uno::Reference<com::sun::star::io::XInputStream>
 const&)
 PDFSignatureHelper::SetDescription(rtl::OUString const&)
@@ -2008,6 +2012,7 @@ QtSvpGraphics::CreateSurface(OutputDevice const&, int, 
int, int, int) const
 QtSvpGraphics::CreateSurface(std::shared_ptr<_cairo_surface> const&) const
 QtSvpGraphics::GetResolution(int&, int&)
 QtSvpGraphics::QtSvpGraphics(QtFrame*)
+QtSvpGraphics::SupportsCairo() const
 QtSvpGraphics::handleDamage(tools::Rectangle const&)
 QtSvpGraphics::updateQWidget() const
 QtSvpGraphics::~QtSvpGraphics()
@@ -6022,6 +6027,7 @@ SkiaSalBitmap::GetAsSkBitmap() const
 SkiaSalBitmap::GetBitCount() const
 SkiaSalBitmap::GetImageKey(SkiaHelper::DirectImage) const
 SkiaSalBitmap::GetSkShader(SkSamplingOptions const&, SkiaHelper::DirectImage) 
const
+SkiaSalBitmap::GetSystemData(BitmapSystemData&)
 SkiaSalBitmap::Invert()
 SkiaSalBitmap::IsAllBlack() const
 SkiaSalBitmap::IsFullyOpaqueAsAlpha() const
diff --git a/canvas/Library_cairocanvas.mk b/canvas/Library_cairocanvas.mk
new file mode 100644
index 000000000000..b7cd8d86b5f0
--- /dev/null
+++ b/canvas/Library_cairocanvas.mk
@@ -0,0 +1,75 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+#   Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements. See the NOTICE file distributed
+#   with this work for additional information regarding copyright
+#   ownership. The ASF licenses this file to you under the Apache
+#   License, Version 2.0 (the "License"); you may not use this file
+#   except in compliance with the License. You may obtain a copy of
+#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call gb_Library_Library,cairocanvas))
+
+$(eval $(call gb_Library_set_include,cairocanvas,\
+    $$(INCLUDE) \
+    -I$(SRCDIR)/canvas/inc \
+))
+
+$(eval $(call 
gb_Library_set_precompiled_header,cairocanvas,canvas/inc/pch/precompiled_cairocanvas))
+
+$(eval $(call 
gb_Library_set_componentfile,cairocanvas,canvas/source/cairo/cairocanvas,services))
+
+$(eval $(call gb_Library_use_sdk_api,cairocanvas))
+
+ifeq ($(OS),MACOSX)
+
+$(eval $(call gb_Library_use_system_darwin_frameworks,cairocanvas,\
+    Cocoa \
+))
+
+endif
+
+$(eval $(call gb_Library_use_libraries,cairocanvas,\
+       sal \
+       cppu \
+       basegfx \
+       cppuhelper \
+       comphelper \
+       vcl \
+       tk \
+       tl \
+       i18nlangtag \
+       canvastools \
+))
+
+$(eval $(call gb_Library_add_exception_objects,cairocanvas,\
+       canvas/source/cairo/cairo_cachedbitmap \
+       canvas/source/cairo/cairo_canvas \
+       canvas/source/cairo/cairo_canvasbitmap \
+       canvas/source/cairo/cairo_canvascustomsprite \
+       canvas/source/cairo/cairo_canvasfont \
+       canvas/source/cairo/cairo_canvashelper \
+       canvas/source/cairo/cairo_canvashelper_text \
+       canvas/source/cairo/cairo_devicehelper \
+       canvas/source/cairo/cairo_spritecanvas \
+       canvas/source/cairo/cairo_spritecanvashelper \
+       canvas/source/cairo/cairo_spritedevicehelper \
+       canvas/source/cairo/cairo_spritehelper \
+       canvas/source/cairo/cairo_textlayout \
+))
+
+$(eval $(call gb_Library_use_externals,cairocanvas,\
+       boost_headers \
+       cairo \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/canvas/Library_directx9canvas.mk b/canvas/Library_directx9canvas.mk
new file mode 100644
index 000000000000..4369de32d636
--- /dev/null
+++ b/canvas/Library_directx9canvas.mk
@@ -0,0 +1,69 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+#   Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements. See the NOTICE file distributed
+#   with this work for additional information regarding copyright
+#   ownership. The ASF licenses this file to you under the Apache
+#   License, Version 2.0 (the "License"); you may not use this file
+#   except in compliance with the License. You may obtain a copy of
+#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call gb_Library_Library,directx9canvas))
+
+$(eval $(call gb_Library_set_include,directx9canvas,\
+    $$(INCLUDE) \
+    -I$(SRCDIR)/canvas/inc \
+))
+
+$(eval $(call 
gb_Library_set_componentfile,directx9canvas,canvas/source/directx/directx9canvas,services))
+
+$(eval $(call gb_Library_use_sdk_api,directx9canvas))
+
+$(eval $(call gb_Library_use_external,directx9canvas,boost_headers))
+
+$(eval $(call gb_Library_use_libraries,directx9canvas,\
+       cppu \
+       tk \
+       sal \
+       comphelper \
+       cppuhelper \
+       basegfx \
+       canvastools \
+       vcl \
+       tl \
+       utl \
+       i18nlangtag \
+))
+
+$(eval $(call gb_Library_use_system_win32_libs,directx9canvas,\
+       d3d9 \
+       gdi32 \
+       gdiplus \
+))
+
+$(eval $(call gb_Library_use_static_libraries,directx9canvas,\
+       directxcanvas \
+))
+
+$(eval $(call gb_Library_add_exception_objects,directx9canvas,\
+       canvas/source/directx/dx_9rm \
+       canvas/source/directx/dx_canvascustomsprite \
+       canvas/source/directx/dx_config \
+       canvas/source/directx/dx_spritecanvas \
+       canvas/source/directx/dx_spritecanvashelper \
+       canvas/source/directx/dx_spritedevicehelper \
+       canvas/source/directx/dx_spritehelper \
+       canvas/source/directx/dx_surfacebitmap \
+       canvas/source/directx/dx_surfacegraphics \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/canvas/Library_gdipluscanvas.mk b/canvas/Library_gdipluscanvas.mk
new file mode 100644
index 000000000000..a67a19df4120
--- /dev/null
+++ b/canvas/Library_gdipluscanvas.mk
@@ -0,0 +1,60 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+#   Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements. See the NOTICE file distributed
+#   with this work for additional information regarding copyright
+#   ownership. The ASF licenses this file to you under the Apache
+#   License, Version 2.0 (the "License"); you may not use this file
+#   except in compliance with the License. You may obtain a copy of
+#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+$(eval $(call gb_Library_Library,gdipluscanvas))
+
+$(eval $(call gb_Library_set_include,gdipluscanvas,\
+    $$(INCLUDE) \
+    -I$(SRCDIR)/canvas/inc \
+))
+
+$(eval $(call 
gb_Library_set_componentfile,gdipluscanvas,canvas/source/directx/gdipluscanvas,services))
+
+$(eval $(call gb_Library_use_external,gdipluscanvas,boost_headers))
+
+$(eval $(call gb_Library_use_sdk_api,gdipluscanvas))
+
+$(eval $(call gb_Library_use_libraries,gdipluscanvas,\
+       cppu \
+       tk \
+       sal \
+       comphelper \
+       cppuhelper \
+       basegfx \
+       canvastools \
+       vcl \
+       tl \
+       utl \
+       i18nlangtag \
+))
+
+$(eval $(call gb_Library_use_system_win32_libs,gdipluscanvas,\
+       gdi32 \
+       gdiplus \
+))
+
+$(eval $(call gb_Library_use_static_libraries,gdipluscanvas,\
+       directxcanvas \
+))
+
+$(eval $(call gb_Library_add_exception_objects,gdipluscanvas,\
+       canvas/source/directx/dx_canvas \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/canvas/Module_canvas.mk b/canvas/Module_canvas.mk
index 9fc588ad6c76..79165c4976e7 100644
--- a/canvas/Module_canvas.mk
+++ b/canvas/Module_canvas.mk
@@ -28,6 +28,12 @@ $(eval $(call gb_Module_add_targets,canvas,\
         $(if $(or 
$(DISABLE_GUI),$(DISABLE_DYNLOADING)),,Executable_canvasdemo)) \
 ))
 
+ifeq ($(ENABLE_CAIRO_CANVAS),TRUE)
+$(eval $(call gb_Module_add_targets,canvas,\
+       Library_cairocanvas \
+))
+endif
+
 ifeq ($(ENABLE_OPENGL_CANVAS),TRUE)
 $(eval $(call gb_Module_add_targets,canvas,\
        Library_oglcanvas \
@@ -35,6 +41,14 @@ $(eval $(call gb_Module_add_targets,canvas,\
 ))
 endif
 
+ifeq ($(OS),WNT)
+$(eval $(call gb_Module_add_targets,canvas,\
+       Library_directx9canvas \
+       Library_gdipluscanvas \
+       StaticLibrary_directxcanvas \
+))
+endif
+
 $(eval $(call gb_Module_add_check_targets,canvas,\
     CppunitTest_canvas_test \
 ))
diff --git a/canvas/StaticLibrary_directxcanvas.mk 
b/canvas/StaticLibrary_directxcanvas.mk
new file mode 100644
index 000000000000..1e0d34409806
--- /dev/null
+++ b/canvas/StaticLibrary_directxcanvas.mk
@@ -0,0 +1,41 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_StaticLibrary_StaticLibrary,directxcanvas))
+
+$(eval $(call gb_StaticLibrary_set_include,directxcanvas,\
+    $$(INCLUDE) \
+    -I$(SRCDIR)/canvas/inc \
+))
+
+$(eval $(call gb_StaticLibrary_use_external,directxcanvas,boost_headers))
+
+$(eval $(call gb_StaticLibrary_use_api,directxcanvas,\
+    offapi \
+    udkapi \
+))
+
+$(eval $(call gb_StaticLibrary_add_exception_objects,directxcanvas,\
+       canvas/source/directx/dx_bitmap \
+       canvas/source/directx/dx_bitmapcanvashelper \
+       canvas/source/directx/dx_canvasbitmap \
+       canvas/source/directx/dx_canvasfont \
+       canvas/source/directx/dx_canvashelper \
+       canvas/source/directx/dx_canvashelper_texturefill \
+       canvas/source/directx/dx_devicehelper \
+       canvas/source/directx/dx_gdiplususer \
+       canvas/source/directx/dx_impltools \
+       canvas/source/directx/dx_linepolypolygon \
+       canvas/source/directx/dx_textlayout \
+       canvas/source/directx/dx_textlayout_drawhelper \
+       canvas/source/directx/dx_vcltools \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/canvas/inc/pch/precompiled_cairocanvas.hxx 
b/canvas/inc/pch/precompiled_cairocanvas.hxx
new file mode 100644
index 000000000000..3657267d7383
--- /dev/null
+++ b/canvas/inc/pch/precompiled_cairocanvas.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All 
such
+ manual changes will be rewritten by the next run of update_pch.sh (which 
presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2021-03-08 13:11:37 using:
+ ./bin/update_pch canvas cairocanvas --cutoff=1 --exclude:system 
--include:module --include:local
+
+ If after updating build fails, use the following command to locate 
conflicting headers:
+ ./bin/update_pch_bisect ./canvas/inc/pch/precompiled_cairocanvas.hxx "make 
canvas.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#include <algorithm>
+#include <cairo.h>
+#include <math.h>
+#include <memory>
+#include <tuple>
+#include <boost/cast.hpp>
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#include <osl/mutex.hxx>
+#include <rtl/instance.hxx>
+#include <rtl/math.hxx>
+#include <sal/log.hxx>
+#include <vcl/BitmapTools.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/cairo.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/dibtools.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/skia/SkiaHelper.hxx>
+#include <vcl/sysdata.hxx>
+#include <vcl/virdev.hxx>
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/range/b2irange.hxx>
+#include <basegfx/utils/canvastools.hxx>
+#include <basegfx/utils/keystoplerp.hxx>
+#include <basegfx/utils/lerp.hxx>
+#include <basegfx/utils/unopolypolygon.hxx>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/rendering/ColorComponentTag.hpp>
+#include <com/sun/star/rendering/ColorSpaceType.hpp>
+#include <com/sun/star/rendering/CompositeOperation.hpp>
+#include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
+#include <com/sun/star/rendering/PanoseProportion.hpp>
+#include <com/sun/star/rendering/PathCapType.hpp>
+#include <com/sun/star/rendering/PathJoinType.hpp>
+#include <com/sun/star/rendering/RenderingIntent.hpp>
+#include <com/sun/star/rendering/RepaintResult.hpp>
+#include <com/sun/star/rendering/TextDirection.hpp>
+#include <com/sun/star/rendering/TexturingMode.hpp>
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
+#include <com/sun/star/util/Endianness.hpp>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <tools/stream.hxx>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#include <canvas/canvastools.hxx>
+#include <parametricpolypolygon.hxx>
+#include <verifyinput.hxx>
+#endif // PCH_LEVEL >= 4
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/cairo/cairo_cachedbitmap.cxx 
b/canvas/source/cairo/cairo_cachedbitmap.cxx
new file mode 100644
index 000000000000..e548778b2fe4
--- /dev/null
+++ b/canvas/source/cairo/cairo_cachedbitmap.cxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <com/sun/star/rendering/RepaintResult.hpp>
+#include <utility>
+#include <comphelper/diagnose_ex.hxx>
+
+#include "cairo_cachedbitmap.hxx"
+#include "cairo_repainttarget.hxx"
+
+
+using namespace ::cairo;
+using namespace ::com::sun::star;
+
+namespace cairocanvas
+{
+    CachedBitmap::CachedBitmap( SurfaceSharedPtr                            
pSurface,
+                                const rendering::ViewState&                 
rUsedViewState,
+                                rendering::RenderState                      
aUsedRenderState,
+                                const uno::Reference< rendering::XCanvas >& 
rTarget ) :
+        CachedPrimitiveBase( rUsedViewState, rTarget ),
+        mpSurface(std::move( pSurface )),
+        maRenderState(std::move( aUsedRenderState ))
+    {}
+
+    void CachedBitmap::disposing(std::unique_lock<std::mutex>& rGuard)
+    {
+        mpSurface.reset();
+        CachedPrimitiveBase::disposing(rGuard);
+    }
+
+    ::sal_Int8 CachedBitmap::doRedraw( const rendering::ViewState&             
     rNewState,
+                                       const rendering::ViewState&             
     /*rOldState*/,
+                                       const uno::Reference< 
rendering::XCanvas >&  rTargetCanvas,
+                                       bool                                    
     bSameViewTransform )
+    {
+        ENSURE_OR_THROW( bSameViewTransform,
+                          "CachedBitmap::doRedraw(): base called with changed 
view transform "
+                          "(told otherwise during construction)" );
+
+        RepaintTarget* pTarget = dynamic_cast< RepaintTarget* 
>(rTargetCanvas.get());
+
+        ENSURE_OR_THROW( pTarget,
+                          "CachedBitmap::redraw(): cannot cast target to 
RepaintTarget" );
+
+        if( !pTarget->repaint( mpSurface,
+                               rNewState,
+                               maRenderState ) )
+        {
+            // target failed to repaint
+            return rendering::RepaintResult::FAILED;
+        }
+
+        return rendering::RepaintResult::REDRAWN;
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/cairo/cairo_cachedbitmap.hxx 
b/canvas/source/cairo/cairo_cachedbitmap.hxx
new file mode 100644
index 000000000000..d7f4c58ef681
--- /dev/null
+++ b/canvas/source/cairo/cairo_cachedbitmap.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <base/cachedprimitivebase.hxx>
+#include <com/sun/star/rendering/RenderState.hpp>
+
+#include <vcl/cairo.hxx>
+
+/* Definition of CachedBitmap class */
+
+namespace cairocanvas
+{
+    class CachedBitmap : public ::canvas::CachedPrimitiveBase
+    {
+    public:
+
+        /** Create an XCachedPrimitive for given GraphicObject
+         */
+        CachedBitmap( ::cairo::SurfaceSharedPtr                              
pSurface,
+                      const css::rendering::ViewState&                       
rUsedViewState,
+                      css::rendering::RenderState                            
aUsedRenderState,
+                      const css::uno::Reference< css::rendering::XCanvas >&  
rTarget   );
+
+        /// Dispose all internal references
+        virtual void disposing(std::unique_lock<std::mutex>& rGuard) override;
+
+    private:
+        virtual ::sal_Int8 doRedraw( const css::rendering::ViewState&  
rNewState,
+                                     const css::rendering::ViewState&  
rOldState,
+                                     const css::uno::Reference<
+                                     css::rendering::XCanvas >&        
rTargetCanvas,
+                                     bool                                      
     bSameViewTransform ) override;
+
+
+        ::cairo::SurfaceSharedPtr mpSurface;
+        const css::rendering::RenderState maRenderState;
+    };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/cairo/cairo_canvas.cxx 
b/canvas/source/cairo/cairo_canvas.cxx
new file mode 100644
index 000000000000..4078e95deb63
--- /dev/null
+++ b/canvas/source/cairo/cairo_canvas.cxx
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <osl/mutex.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <vcl/sysdata.hxx>
+#include <vcl/skia/SkiaHelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include "cairo_canvas.hxx"
+
+using namespace ::cairo;
+using namespace ::com::sun::star;
+
+namespace cairocanvas
+{
+    Canvas::Canvas( const uno::Sequence< uno::Any >&                aArguments,
+                    const uno::Reference< uno::XComponentContext >& 
/*rxContext*/ ) :
+        maArguments(aArguments)
+    {
+    }
+
+    void Canvas::initialize()
+    {
+        // #i64742# Only perform initialization when not in probe mode
+        if( !maArguments.hasElements() )
+            return;
+
+        assert( !SkiaHelper::isVCLSkiaEnabled() );
+
+        /* maArguments:
+           0: ptr to creating instance (Window or VirtualDevice)
+           1: current bounds of creating instance
+           2: bool, denoting always on top state for Window (always false for 
VirtualDevice)
+           3: XWindow for creating Window (or empty for VirtualDevice)
+           4: SystemGraphicsData as a streamed Any
+         */
+        SAL_INFO("canvas.cairo","Canvas created " <<  this);
+
+        ENSURE_ARG_OR_THROW( maArguments.getLength() >= 5 &&
+                             maArguments[0].getValueTypeClass() == 
uno::TypeClass_HYPER &&
+                             maArguments[4].getValueTypeClass() == 
uno::TypeClass_SEQUENCE,
+                             "Canvas::initialize: wrong number of arguments, 
or wrong types" );
+
+        // We expect a single Any here, containing a pointer to a valid
+        // VCL output device, on which to output (mostly needed for text)
+        sal_Int64 nPtr = 0;
+        maArguments[0] >>= nPtr;
+        OutputDevice* pOutDev = reinterpret_cast<OutputDevice*>(nPtr);
+        ENSURE_ARG_OR_THROW( pOutDev != nullptr,
+                             "Canvas::initialize: invalid OutDev pointer" );
+
+        awt::Rectangle aBounds;
+        maArguments[1] >>= aBounds;
+
+        uno::Sequence<sal_Int8> aSeq;
+        maArguments[4] >>= aSeq;
+
+        const SystemGraphicsData* pSysData=reinterpret_cast<const 
SystemGraphicsData*>(aSeq.getConstArray());
+        if( !pSysData || !pSysData->nSize )
+            throw lang::NoSupportException( u"Passed SystemGraphicsData 
invalid!"_ustr );
+
+        bool bHasCairo = pOutDev->SupportsCairo();
+        ENSURE_ARG_OR_THROW(bHasCairo, "SpriteCanvas::SpriteCanvas: No Cairo 
capability");
+
+        // setup helper
+        maDeviceHelper.init( *this, *pOutDev );
+
+        maCanvasHelper.init( basegfx::B2ISize(aBounds.Width, aBounds.Height), 
*this, this );
+
+        // forward surface to render on to canvashelper
+        maCanvasHelper.setSurface( maDeviceHelper.getSurface(), false );
+
+        maArguments.realloc(0);
+    }
+
+    Canvas::~Canvas()
+    {
+        SAL_INFO("canvas.cairo", "CairoCanvas destroyed" );
+    }
+
+    void Canvas::disposeThis()
+    {
+        ::osl::MutexGuard aGuard( m_aMutex );
+
+        // forward to parent
+        CanvasBaseT::disposeThis();
+    }
+
+    OUString SAL_CALL Canvas::getServiceName(  )
+    {
+        return u"com.sun.star.rendering.Canvas.Cairo"_ustr;
+    }
+
+    //  XServiceInfo
+    sal_Bool Canvas::supportsService(const OUString& sServiceName)
+    {
+        return cppu::supportsService(this, sServiceName);
+
+    }
+    OUString Canvas::getImplementationName()
+    {
+        return u"com.sun.star.comp.rendering.Canvas.Cairo"_ustr;
+    }
+    css::uno::Sequence< OUString > Canvas::getSupportedServiceNames()
+    {
+        return { getServiceName() };
+    }
+
+    bool Canvas::repaint( const SurfaceSharedPtr&       pSurface,
+                          const rendering::ViewState&   viewState,
+                          const rendering::RenderState& renderState )
+    {
+        return maCanvasHelper.repaint( pSurface, viewState, renderState );
+    }
+
+    SurfaceSharedPtr Canvas::getSurface()
+    {
+        return maDeviceHelper.getSurface();
+    }
+
+    SurfaceSharedPtr Canvas::createSurface( const ::basegfx::B2ISize& rSize, 
int aContent )
+    {
+        return maDeviceHelper.createSurface( rSize, aContent );
+    }
+
+    SurfaceSharedPtr Canvas::createSurface( ::Bitmap& rBitmap )
+    {
+        SurfaceSharedPtr pSurface;
+
+        BitmapSystemData aData;
+        if( rBitmap.GetSystemData( aData ) ) {
+            const Size aSize = rBitmap.GetSizePixel();
+
+            pSurface = maDeviceHelper.createSurface( aData, aSize );
+        }
+
+        return pSurface;
+    }
+
+    SurfaceSharedPtr Canvas::changeSurface()
+    {
+        // non-modifiable surface here
+        return SurfaceSharedPtr();
+    }
+
+    OutputDevice* Canvas::getOutputDevice()
+    {
+        return maDeviceHelper.getOutputDevice();
+    }
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_rendering_Canvas_Cairo_get_implementation(
+    css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> 
const& args)
+{
+    rtl::Reference<cairocanvas::Canvas> p = new cairocanvas::Canvas(args, 
context);
+    try {
+        p->initialize();
+    } catch (css::uno::Exception&) {
+        p->dispose();
+        throw;
+    }
+    return cppu::acquire(p.get());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/cairo/cairo_canvas.hxx 
b/canvas/source/cairo/cairo_canvas.hxx
new file mode 100644
index 000000000000..0c41a8a5c0d3
--- /dev/null
+++ b/canvas/source/cairo/cairo_canvas.hxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XServiceName.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/util/XUpdatable.hpp>
+#include <com/sun/star/rendering/XIntegerBitmap.hpp>
+#include <com/sun/star/rendering/XGraphicDevice.hpp>
+#include <com/sun/star/rendering/XBitmapCanvas.hpp>
+
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/uno3.hxx>
+
+#include <base/basemutexhelper.hxx>
+#include <base/bitmapcanvasbase.hxx>
+#include <base/graphicdevicebase.hxx>
+#include <base/integerbitmapbase.hxx>
+
+#include "cairo_canvashelper.hxx"
+#include "cairo_devicehelper.hxx"
+#include "cairo_repainttarget.hxx"
+#include "cairo_surfaceprovider.hxx"
+
+namespace cairocanvas
+{
+    typedef ::cppu::WeakComponentImplHelper< css::rendering::XBitmapCanvas,
+                                             css::rendering::XIntegerBitmap,
+                                             css::rendering::XGraphicDevice,
+                                             css::lang::XMultiServiceFactory,
+                                             css::util::XUpdatable,
+                                             css::beans::XPropertySet,
+                                             css::lang::XServiceName,
+                                             css::lang::XServiceInfo >  
GraphicDeviceBase_Base;
+    typedef ::canvas::GraphicDeviceBase< ::canvas::BaseMutexHelper< 
GraphicDeviceBase_Base >,
+                                                 DeviceHelper,
+                                                 ::osl::MutexGuard,
+                                                 ::cppu::OWeakObject > 
CanvasBase_Base;
+
+    /** Mixin SurfaceProvider
+
+        Have to mixin the SurfaceProvider before deriving from
+        ::canvas::CanvasBase, as this template should already
+        implement some of those interface methods.
+
+        The reason why this appears kinda convoluted is the fact that
+        we cannot specify non-IDL types as WeakComponentImplHelper
+        template args, and furthermore, don't want to derive
+        ::canvas::CanvasBase directly from
+        SurfaceProvider (because derivees of
+        ::canvas::CanvasBase have to explicitly forward the
+        XInterface methods (e.g. via DECLARE_UNO3_AGG_DEFAULTS)
+        anyway).
+     */
+    class CanvasBaseSurfaceProvider_Base : public CanvasBase_Base,
+                                           public SurfaceProvider
+    {
+    };
+
+    typedef ::canvas::IntegerBitmapBase<
+        canvas::BitmapCanvasBase2<
+            CanvasBaseSurfaceProvider_Base,
+            CanvasHelper,
+            ::osl::MutexGuard,
+            ::cppu::OWeakObject> > CanvasBaseT;
+
+    /** Product of this component's factory.
+
+        The Canvas object combines the actual Window canvas with
+        the XGraphicDevice interface. This is because there's a
+        one-to-one relation between them, anyway, since each window
+        can have exactly one canvas and one associated
+        XGraphicDevice. And to avoid messing around with circular
+        references, this is implemented as one single object.
+     */
+    class Canvas : public CanvasBaseT,
+                   public RepaintTarget
+    {
+    public:
+        Canvas( const css::uno::Sequence< css::uno::Any >&               
aArguments,
+                const css::uno::Reference< css::uno::XComponentContext >& 
rxContext );
+
+        void initialize();
+
+        /// For resource tracking
+        virtual ~Canvas() override;
+
+        /// Dispose all internal references
+        virtual void disposeThis() override;
+
+        // Forwarding the XComponent implementation to the
+        // cppu::ImplHelper templated base
+        //                          Classname     Base doing refcounting       
 Base implementing the XComponent interface
+        //                            |                 |                      
      |
+        //                            V                 V                      
      V
+        DECLARE_UNO3_XCOMPONENT_AGG_DEFAULTS( Canvas, GraphicDeviceBase_Base, 
::cppu::WeakComponentImplHelperBase )
+
+        // XServiceName
+        virtual OUString SAL_CALL getServiceName(  ) override;
+
+        //  XServiceInfo
+        virtual sal_Bool SAL_CALL supportsService(const OUString& 
sServiceName) override;
+        virtual OUString SAL_CALL getImplementationName() override;
+        virtual css::uno::Sequence< OUString > SAL_CALL 
getSupportedServiceNames() override;
+
+        // RepaintTarget
+        virtual bool repaint( const ::cairo::SurfaceSharedPtr& pSurface,
+                  const css::rendering::ViewState& viewState,
+                  const css::rendering::RenderState&   renderState ) override;
+
+        // SurfaceProvider
+        virtual ::cairo::SurfaceSharedPtr getSurface() override;
+        virtual ::cairo::SurfaceSharedPtr createSurface( const 
::basegfx::B2ISize& rSize, int aContent ) override;
+        virtual ::cairo::SurfaceSharedPtr createSurface( ::Bitmap& rBitmap ) 
override;
+        virtual ::cairo::SurfaceSharedPtr changeSurface() override;
+        virtual OutputDevice* getOutputDevice() override;
+
+     private:
+        css::uno::Sequence< css::uno::Any >                maArguments;
+    };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/cairo/cairo_canvasbitmap.cxx 
b/canvas/source/cairo/cairo_canvasbitmap.cxx
new file mode 100644
index 000000000000..c4de75ee2fce
--- /dev/null
+++ b/canvas/source/cairo/cairo_canvasbitmap.cxx
@@ -0,0 +1,163 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <utility>
+#include <vcl/bitmapex.hxx>
+#include <vcl/BitmapTools.hxx>
+
+#include <cairo.h>
+
+#include "cairo_canvasbitmap.hxx"
+
+using namespace ::cairo;
+using namespace ::com::sun::star;
+
+namespace cairocanvas
+{
+    CanvasBitmap::CanvasBitmap( const ::basegfx::B2ISize&  rSize,
+                                SurfaceProviderRef         rSurfaceProvider,
+                                rendering::XGraphicDevice* pDevice,
+                                bool                       bHasAlpha ) :
+        mpSurfaceProvider(std::move( rSurfaceProvider )),
+        maSize(rSize),
+        mbHasAlpha(bHasAlpha)
+    {
+        ENSURE_OR_THROW( mpSurfaceProvider.is(),
+                          "CanvasBitmap::CanvasBitmap(): Invalid surface or 
device" );
+
+        SAL_INFO(
+            "canvas.cairo",
+            "bitmap size: " << rSize.getWidth() << "x" << rSize.getHeight());
+
+        mpBufferSurface = mpSurfaceProvider->createSurface( rSize, bHasAlpha ? 
CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR );
+        mpBufferCairo = mpBufferSurface->getCairo();
+
+        maCanvasHelper.init( rSize, *mpSurfaceProvider, pDevice );
+        maCanvasHelper.setSurface( mpBufferSurface, bHasAlpha );
+
+        // clear bitmap to 100% transparent
+        maCanvasHelper.clear();
+    }
+
+    void CanvasBitmap::disposeThis()
+    {
+        mpSurfaceProvider.clear();
+
+        mpBufferCairo.reset();
+        mpBufferSurface.reset();
+
+        // forward to parent
+        CanvasBitmap_Base::disposeThis();
+    }
+
+    SurfaceSharedPtr CanvasBitmap::getSurface()
+    {
+        return mpBufferSurface;
+    }
+
+    SurfaceSharedPtr CanvasBitmap::createSurface( const ::basegfx::B2ISize& 
rSize, int aContent )
+    {
+        return mpSurfaceProvider->createSurface(rSize,aContent);
+    }
+
+    SurfaceSharedPtr CanvasBitmap::createSurface( ::Bitmap& rBitmap )
+    {
+        return mpSurfaceProvider->createSurface(rBitmap);
+    }
+
+    SurfaceSharedPtr CanvasBitmap::changeSurface()
+    {
+        // non-modifiable surface here
+        return SurfaceSharedPtr();
+    }
+
+    OutputDevice* CanvasBitmap::getOutputDevice()
+    {
+        return mpSurfaceProvider->getOutputDevice();
+    }
+
+    bool CanvasBitmap::repaint( const SurfaceSharedPtr&       pSurface,
+                                const rendering::ViewState&   viewState,
+                                const rendering::RenderState& renderState )
+    {
+        return maCanvasHelper.repaint( pSurface, viewState, renderState );
+    }
+
+    uno::Any SAL_CALL CanvasBitmap::getFastPropertyValue( sal_Int32 nHandle )
+    {
+        uno::Any aRV( sal_Int32(0) );
+        // 0 ... get BitmapEx
+        // 1 ... get Pixbuf with bitmap RGB content
+        // 2 ... return nothing (empty Any)
+        switch( nHandle )
+        {
+            case 0:
+            {
+                aRV <<= reinterpret_cast<sal_Int64>( nullptr );
+                if ( !mbHasAlpha )
+                    break;
+
+                BitmapEx* pBitmapEx = vcl::bitmap::CreateFromCairoSurface(
+                                          ::Size( maSize.getWidth(), 
maSize.getHeight() ),
+                                          
getSurface()->getCairoSurface().get());
+                if (pBitmapEx)
+                    aRV <<= reinterpret_cast<sal_Int64>( pBitmapEx );
+
+                break;
+            }
+            case 1:
+            {
+                aRV = 
getOutputDevice()->GetNativeSurfaceHandle(mpBufferSurface, maSize);
+                break;
+            }
+            case 2:
+            {
+                // Always return nothing - for the RGB surface support.
+                // Alpha code paths go via the above case 0.
+                aRV = uno::Any();
+                break;
+            }
+        }
+
+        return aRV;
+    }
+
+    OUString SAL_CALL CanvasBitmap::getImplementationName(  )
+    {
+        return u"CairoCanvas.CanvasBitmap"_ustr;
+    }
+
+    sal_Bool SAL_CALL CanvasBitmap::supportsService( const OUString& 
ServiceName )
+    {
+        return cppu::supportsService( this, ServiceName );
+    }
+
+    uno::Sequence< OUString > SAL_CALL CanvasBitmap::getSupportedServiceNames( 
 )
+    {
+        return { u"com.sun.star.rendering.CanvasBitmap"_ustr };
+    }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/cairo/cairo_canvasbitmap.hxx 
b/canvas/source/cairo/cairo_canvasbitmap.hxx
new file mode 100644
index 000000000000..f2371821023f
--- /dev/null
+++ b/canvas/source/cairo/cairo_canvasbitmap.hxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/compbase.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/rendering/XBitmapCanvas.hpp>
+#include <com/sun/star/rendering/XIntegerBitmap.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <comphelper/uno3.hxx>
+
+#include <base/bitmapcanvasbase.hxx>
+#include <base/basemutexhelper.hxx>
+#include <base/integerbitmapbase.hxx>
+
+#include "cairo_canvashelper.hxx"
+#include "cairo_repainttarget.hxx"
+
+
+/* Definition of CanvasBitmap class */
+
+namespace cairocanvas
+{
+    typedef ::cppu::WeakComponentImplHelper< css::rendering::XBitmapCanvas,
+                                             css::rendering::XIntegerBitmap,
+                                             css::lang::XServiceInfo,
+                                             css::beans::XFastPropertySet >   
CanvasBitmapBase_Base;
+    class CanvasBitmapSpriteSurface_Base :
+        public ::canvas::BaseMutexHelper<CanvasBitmapBase_Base>,
+        public SurfaceProvider
+    {
+    };
+
+    typedef ::canvas::IntegerBitmapBase<
+        canvas::BitmapCanvasBase2<
+            CanvasBitmapSpriteSurface_Base,
+            CanvasHelper,
+            ::osl::MutexGuard,
+            ::cppu::OWeakObject> > CanvasBitmap_Base;
+
+    class CanvasBitmap : public CanvasBitmap_Base,
+                         public RepaintTarget
+    {
+    public:
+        /** Create a canvas bitmap for the given surface
+
+            @param rSize
+            Size of the bitmap
+
+            @param rDevice
+            Reference device, with which bitmap should be compatible
+        */
+        CanvasBitmap( const ::basegfx::B2ISize& rSize,
+                      SurfaceProviderRef  rDevice,
+                      css::rendering::XGraphicDevice* pDevice,
+                      bool                      bHasAlpha );
+
+        /// Dispose all internal references
+        virtual void disposeThis() override;
+
+        // Forwarding the XComponent implementation to the
+        // cppu::ImplHelper templated base
+        //                                    Classname     Base doing 
refcounting        Base implementing the XComponent interface
+        //                                       |                 |           
                 |
+        //                                       V                 V           
                 V
+        DECLARE_UNO3_XCOMPONENT_AGG_DEFAULTS( CanvasBitmap, 
CanvasBitmapBase_Base, ::cppu::WeakComponentImplHelperBase )
+
+        // XServiceInfo
+        virtual OUString SAL_CALL getImplementationName(  ) override;
+        virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName 
) override;
+        virtual css::uno::Sequence< OUString > SAL_CALL 
getSupportedServiceNames(  ) override;
+
+        // SurfaceProvider
+        virtual ::cairo::SurfaceSharedPtr getSurface() override;
+        virtual ::cairo::SurfaceSharedPtr createSurface( const 
::basegfx::B2ISize& rSize, int aContent ) override;
+        virtual ::cairo::SurfaceSharedPtr createSurface( ::Bitmap& rBitmap ) 
override;
+        virtual ::cairo::SurfaceSharedPtr changeSurface() override;
+        virtual OutputDevice* getOutputDevice() override;
+
+        // RepaintTarget
+        virtual bool repaint( const ::cairo::SurfaceSharedPtr&                
pSurface,
+                              const css::rendering::ViewState&   viewState,
+                              const css::rendering::RenderState& renderState ) 
override;
+
+        // XFastPropertySet
+        // used to retrieve BitmapEx pointer or X Pixmap handles for this 
bitmap
+        // handle values have these meanings:
+        // 0 ... get pointer to BitmapEx
+        // 1 ... get X pixmap handle to rgb content
+        // 2 ... FIXME: leftover? ever called with this? always returns 
nothing (empty Any)
+        // returned any contains either BitmapEx pointer or array of two Any 
value
+        //     1st a bool value: true - free the pixmap after used by 
XFreePixmap, false do nothing, the pixmap is used internally in the canvas
+        //     2nd the pixmap handle (sal_Int64)
+        virtual css::uno::Any SAL_CALL getFastPropertyValue(sal_Int32 nHandle) 
override;
+        virtual void SAL_CALL setFastPropertyValue(sal_Int32, const 
css::uno::Any&) override {}
+
+    private:
+        SurfaceProviderRef        mpSurfaceProvider;
+        ::cairo::SurfaceSharedPtr mpBufferSurface;
+        ::cairo::CairoSharedPtr   mpBufferCairo;
+
+        const ::basegfx::B2ISize  maSize;
+        const bool                mbHasAlpha;
+    };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/cairo/cairo_canvascustomsprite.cxx 
b/canvas/source/cairo/cairo_canvascustomsprite.cxx
new file mode 100644
index 000000000000..72fb291ebf35
--- /dev/null
+++ b/canvas/source/cairo/cairo_canvascustomsprite.cxx
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <basegfx/point/b2dpoint.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+#include <canvas/canvastools.hxx>
+#include <cairo.h>
+
+#include "cairo_canvascustomsprite.hxx"
+#include "cairo_spritecanvas.hxx"
+
+
+using namespace ::cairo;
+using namespace ::com::sun::star;
+
+namespace cairocanvas
+{
+    CanvasCustomSprite::CanvasCustomSprite( const css::geometry::RealSize2D&   
rSpriteSize,
+                                            const SpriteCanvasRef&             
             rRefDevice ) :
+        mpSpriteCanvas( rRefDevice ),
+        maSize( ::canvas::tools::roundUp( rSpriteSize.Width ),
+                ::canvas::tools::roundUp( rSpriteSize.Height ) )
+    {
+        ENSURE_OR_THROW( rRefDevice,
+                          "CanvasCustomSprite::CanvasCustomSprite(): Invalid 
sprite canvas" );
+
+        SAL_INFO( "canvas.cairo", "sprite size: " << ::canvas::tools::roundUp( 
rSpriteSize.Width ) << ", " << ::canvas::tools::roundUp( rSpriteSize.Height ));
+
+        mpBufferSurface = mpSpriteCanvas->createSurface( maSize, 
CAIRO_CONTENT_COLOR_ALPHA );
+
+        maCanvasHelper.init( maSize,
+                             *rRefDevice,
+                             rRefDevice.get() );
+        maCanvasHelper.setSurface( mpBufferSurface, true );
+
+        maSpriteHelper.init( rSpriteSize,
+                             rRefDevice );
+        maSpriteHelper.setSurface( mpBufferSurface );
+
+        // clear sprite to 100% transparent
+        maCanvasHelper.clear();
+    }
+
+    void CanvasCustomSprite::disposeThis()
+    {
+        ::osl::MutexGuard aGuard( m_aMutex );
+
+        mpSpriteCanvas.clear();
+        mpBufferSurface.reset();
+
+        // forward to parent
+        CanvasCustomSpriteBaseT::disposeThis();
+    }
+
+    void CanvasCustomSprite::redraw( const CairoSharedPtr& pCairo,
+                                     bool                  bBufferedUpdate ) 
const
+    {
+        ::osl::MutexGuard aGuard( m_aMutex );
+
+        redraw( pCairo, maSpriteHelper.getPosPixel(), bBufferedUpdate );
+    }
+
+    void CanvasCustomSprite::redraw( const CairoSharedPtr&      pCairo,
+                                     const ::basegfx::B2DPoint& rOrigOutputPos,
+                                     bool                       
bBufferedUpdate ) const
+    {
+        ::osl::MutexGuard aGuard( m_aMutex );
+
+        maSpriteHelper.redraw( pCairo,
+                               rOrigOutputPos,
+                               mbSurfaceDirty,
+                               bBufferedUpdate );
+
+        mbSurfaceDirty = false;
+    }
+
+    bool CanvasCustomSprite::repaint( const SurfaceSharedPtr&       pSurface,
+                                      const rendering::ViewState&   viewState,
+                                      const rendering::RenderState& 
renderState )
+    {
+        return maCanvasHelper.repaint( pSurface, viewState, renderState );
+    }
+
+    SurfaceSharedPtr CanvasCustomSprite::getSurface()
+    {
+        return mpBufferSurface;
+    }
+
+    SurfaceSharedPtr CanvasCustomSprite::createSurface( const 
::basegfx::B2ISize& rSize, int aContent )
+    {
+        return mpSpriteCanvas->createSurface(rSize,aContent);
+    }
+
+    SurfaceSharedPtr CanvasCustomSprite::createSurface( ::Bitmap& rBitmap )
+    {
+        return mpSpriteCanvas->createSurface(rBitmap);
+    }
+
+    SurfaceSharedPtr CanvasCustomSprite::changeSurface()
+    {
+        SAL_INFO( "canvas.cairo", "replacing sprite background surface");
+
+        mpBufferSurface = mpSpriteCanvas->createSurface( maSize, 
CAIRO_CONTENT_COLOR );
+        maSpriteHelper.setSurface( mpBufferSurface );
+
+        return mpBufferSurface;
+    }
+
+    OutputDevice* CanvasCustomSprite::getOutputDevice()
+    {
+        return mpSpriteCanvas->getOutputDevice();
+    }
+
+    OUString SAL_CALL CanvasCustomSprite::getImplementationName()
+    {
+        return u"CairoCanvas.CanvasCustomSprite"_ustr;
+    }
+
+    sal_Bool SAL_CALL CanvasCustomSprite::supportsService( const OUString& 
ServiceName )
+    {
+        return cppu::supportsService( this, ServiceName );
+    }
+
+    uno::Sequence< OUString > SAL_CALL 
CanvasCustomSprite::getSupportedServiceNames()
+    {
+        return { u"com.sun.star.rendering.CanvasCustomSprite"_ustr };
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/cairo/cairo_canvascustomsprite.hxx 
b/canvas/source/cairo/cairo_canvascustomsprite.hxx
new file mode 100644
index 000000000000..ffe766ab0966
--- /dev/null
+++ b/canvas/source/cairo/cairo_canvascustomsprite.hxx
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/compbase.hxx>
+#include <comphelper/uno3.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/rendering/XBitmapCanvas.hpp>
+#include <com/sun/star/rendering/XCustomSprite.hpp>
+#include <com/sun/star/rendering/XIntegerBitmap.hpp>
+
+#include <basegfx/point/b2dpoint.hxx>
+
+#include <base/basemutexhelper.hxx>
+#include <base/canvascustomspritebase.hxx>
+
+#include <vcl/cairo.hxx>
+
+#include "cairo_sprite.hxx"
+#include "cairo_canvashelper.hxx"
+#include "cairo_repainttarget.hxx"
+#include "cairo_spritehelper.hxx"
+#include "cairo_spritecanvas.hxx"
+
+
+namespace cairocanvas
+{
+    typedef ::cppu::WeakComponentImplHelper< css::rendering::XCustomSprite,
+                                             css::rendering::XBitmapCanvas,
+                                             css::rendering::XIntegerBitmap,
+                                             css::lang::XServiceInfo >  
CanvasCustomSpriteBase_Base;
+    /** Mixin Sprite
+
+        Have to mixin the Sprite interface before deriving from
+        ::canvas::CanvasCustomSpriteBase, as this template should
+        already implement some of those interface methods.
+
+        The reason why this appears kinda convoluted is the fact that
+        we cannot specify non-IDL types as WeakComponentImplHelper
+        template args, and furthermore, don't want to derive
+        ::canvas::CanvasCustomSpriteBase directly from
+        ::canvas::Sprite (because derivees of
+        ::canvas::CanvasCustomSpriteBase have to explicitly forward
+        the XInterface methods (e.g. via DECLARE_UNO3_AGG_DEFAULTS)
+        anyway). Basically, ::canvas::CanvasCustomSpriteBase should
+        remain a base class that provides implementation, not to
+        enforce any specific interface on its derivees.
+     */
+    class CanvasCustomSpriteSpriteBase_Base : public 
::canvas::BaseMutexHelper< CanvasCustomSpriteBase_Base >,
+                                                 public Sprite,
+                                              public SurfaceProvider
+    {
+    };
+
+    typedef ::canvas::CanvasCustomSpriteBase< 
CanvasCustomSpriteSpriteBase_Base,
+                                              SpriteHelper,
+                                              CanvasHelper,
+                                              ::osl::MutexGuard,
+                                              ::cppu::OWeakObject >            
         CanvasCustomSpriteBaseT;
+
+    /* Definition of CanvasCustomSprite class */
+
+    class CanvasCustomSprite : public CanvasCustomSpriteBaseT,
+                               public RepaintTarget
+    {
+    public:
+        /** Create a custom sprite
+
+            @param rSpriteSize
+            Size of the sprite in pixel
+
+            @param rRefDevice
+            Associated output device
+
+            @param rSpriteCanvas
+            Target canvas
+
+            @param rDevice
+            Target DX device
+         */
+        CanvasCustomSprite( const css::geometry::RealSize2D&   rSpriteSize,
+                            const SpriteCanvasRef&                          
rRefDevice );
+
+        virtual void disposeThis() override;
+
+        // Forwarding the XComponent implementation to the
+        // cppu::ImplHelper templated base
+        //                                    Classname           Base doing 
refcount          Base implementing the XComponent interface
+        //                                          |                    |     
                    |
+        //                                          V                    V     
                    V
+        DECLARE_UNO3_XCOMPONENT_AGG_DEFAULTS( CanvasCustomSprite, 
CanvasCustomSpriteBase_Base, ::cppu::WeakComponentImplHelperBase )
+
+        // XServiceInfo
+        virtual OUString SAL_CALL getImplementationName() override;
+        virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName 
) override;
+        virtual css::uno::Sequence< OUString > SAL_CALL 
getSupportedServiceNames() override;
+
+        // Sprite
+        virtual void redraw( const ::cairo::CairoSharedPtr& pCairo,
+                             bool                           bBufferedUpdate ) 
const override;
+        virtual void redraw( const ::cairo::CairoSharedPtr& pCairo,
+                             const ::basegfx::B2DPoint&     rOrigOutputPos,
+                             bool                           bBufferedUpdate ) 
const override;
+
+        // RepaintTarget
+        virtual bool repaint( const ::cairo::SurfaceSharedPtr&                
pSurface,
+                              const css::rendering::ViewState&   viewState,
+                              const css::rendering::RenderState& renderState ) 
override;
+
+        // SurfaceProvider
+        virtual ::cairo::SurfaceSharedPtr getSurface() override;
+        virtual ::cairo::SurfaceSharedPtr createSurface( const 
::basegfx::B2ISize& rSize, int aContent ) override;
+        virtual ::cairo::SurfaceSharedPtr createSurface( ::Bitmap& rBitmap ) 
override;
+        virtual ::cairo::SurfaceSharedPtr changeSurface() override;
+        virtual OutputDevice* getOutputDevice() override;
+
+    private:
+        /** MUST hold here, too, since CanvasHelper only contains a
+            raw pointer (without refcounting)
+        */
+        SpriteCanvasRef           mpSpriteCanvas;
+        ::cairo::SurfaceSharedPtr mpBufferSurface;
+        ::basegfx::B2ISize        maSize;
+    };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/cairo/cairo_canvasfont.cxx 
b/canvas/source/cairo/cairo_canvasfont.cxx
new file mode 100644
index 000000000000..a2650811b721
--- /dev/null
+++ b/canvas/source/cairo/cairo_canvasfont.cxx
@@ -0,0 +1,161 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <basegfx/numeric/ftools.hxx>
+#include <com/sun/star/rendering/PanoseProportion.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <rtl/math.hxx>
+#include <utility>
+#include <vcl/metric.hxx>
+
+#include <canvas/canvastools.hxx>
+
+#include "cairo_canvasfont.hxx"
+#include "cairo_textlayout.hxx"
+
+using namespace ::com::sun::star;
+
+namespace cairocanvas
+{
+
+    CanvasFont::CanvasFont( const rendering::FontRequest&                   
rFontRequest,
+                            const uno::Sequence< beans::PropertyValue >&    
rExtraFontProperties,
+                            const geometry::Matrix2D&                       
rFontMatrix,
+                            SurfaceProviderRef                              
rDevice ) :
+        maFont( vcl::Font( rFontRequest.FontDescription.FamilyName,
+                      rFontRequest.FontDescription.StyleName,
+                      Size( 0, ::basegfx::fround(rFontRequest.CellSize) ) ) ),
+        maFontRequest( rFontRequest ),
+        mpRefDevice(std::move( rDevice )),
+        mnEmphasisMark(0)
+    {
+        ::canvas::tools::extractExtraFontProperties(rExtraFontProperties, 
mnEmphasisMark);
+
+        maFont->SetAlignment( ALIGN_BASELINE );
+        maFont->SetCharSet( 
(rFontRequest.FontDescription.IsSymbolFont==css::util::TriState_YES) ? 
RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
+        maFont->SetVertical( 
rFontRequest.FontDescription.IsVertical==css::util::TriState_YES );
+
+        // TODO(F2): improve panose->vclenum conversion
+        maFont->SetWeight( 
static_cast<FontWeight>(rFontRequest.FontDescription.FontDescription.Weight) );
+        maFont->SetItalic( 
(rFontRequest.FontDescription.FontDescription.Letterform<=8) ? ITALIC_NONE : 
ITALIC_NORMAL );
+        maFont->SetPitch(
+                rFontRequest.FontDescription.FontDescription.Proportion == 
rendering::PanoseProportion::MONO_SPACED
+                    ? PITCH_FIXED : PITCH_VARIABLE);
+
+        maFont->SetLanguage( LanguageTag::convertToLanguageType( 
rFontRequest.Locale, false));
+
+        // adjust to stretched/shrunk font
+        if( ::rtl::math::approxEqual( rFontMatrix.m00, rFontMatrix.m11) )
+            return;
+
+        VclPtr<OutputDevice> pOutDev( mpRefDevice->getOutputDevice() );
+
+        if( !pOutDev )
+            return;
+
+        const bool bOldMapState( pOutDev->IsMapModeEnabled() );
+        pOutDev->EnableMapMode(false);
+
+        const Size aSize = pOutDev->GetFontMetric( *maFont ).GetFontSize();
+
+        const double fDividend( rFontMatrix.m10 + rFontMatrix.m11 );
+        double fStretch = rFontMatrix.m00 + rFontMatrix.m01;
+
+        if( !::basegfx::fTools::equalZero( fDividend) )
+            fStretch /= fDividend;
+
+        const tools::Long nNewWidth = ::basegfx::fround( aSize.Width() * 
fStretch );
+
+        maFont->SetAverageFontWidth( nNewWidth );
+
+        pOutDev->EnableMapMode(bOldMapState);
+    }
+
+    void CanvasFont::disposing(std::unique_lock<std::mutex>& rGuard)
+    {
+        rGuard.unlock();
+        {
+            SolarMutexGuard aGuard;
+            mpRefDevice.clear();
+        }
+        rGuard.lock();
+    }
+
+    uno::Reference< rendering::XTextLayout > SAL_CALL  
CanvasFont::createTextLayout( const rendering::StringContext& aText, sal_Int8 
nDirection, sal_Int64 nRandomSeed )
+    {
+        SolarMutexGuard aGuard;
+
+        if( !mpRefDevice.is() )
+            return uno::Reference< rendering::XTextLayout >(); // we're 
disposed
+
+        return new TextLayout( aText,
+                               nDirection,
+                               nRandomSeed,
+                               Reference( this ),
+                               mpRefDevice );
+    }
+
+    rendering::FontRequest SAL_CALL  CanvasFont::getFontRequest(  )
+    {
+        return maFontRequest;
+    }
+
+    rendering::FontMetrics SAL_CALL  CanvasFont::getFontMetrics(  )
+    {
+        // TODO(F1)
+        return rendering::FontMetrics();
+    }
+
+    uno::Sequence< double > SAL_CALL  CanvasFont::getAvailableSizes(  )
+    {
+        // TODO(F1)
+        return uno::Sequence< double >();
+    }
+
+    uno::Sequence< beans::PropertyValue > SAL_CALL  
CanvasFont::getExtraFontProperties(  )
+    {
+        // TODO(F1)
+        return uno::Sequence< beans::PropertyValue >();
+    }
+
+    OUString SAL_CALL CanvasFont::getImplementationName()
+    {
+        return u"CairoCanvas::CanvasFont"_ustr;
+    }
+
+    sal_Bool SAL_CALL CanvasFont::supportsService( const OUString& ServiceName 
)
+    {
+        return cppu::supportsService( this, ServiceName );
+    }
+
+    uno::Sequence< OUString > SAL_CALL CanvasFont::getSupportedServiceNames()
+    {
+        return { u"com.sun.star.rendering.CanvasFont"_ustr };
+    }
+
+    vcl::Font const & CanvasFont::getVCLFont() const
+    {
+        return *maFont;
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/cairo/cairo_canvasfont.hxx 
b/canvas/source/cairo/cairo_canvasfont.hxx
new file mode 100644
index 000000000000..d5e015006c98
--- /dev/null
+++ b/canvas/source/cairo/cairo_canvasfont.hxx
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <comphelper/compbase.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/geometry/Matrix2D.hpp>
+#include <com/sun/star/rendering/FontRequest.hpp>
+#include <com/sun/star/rendering/XCanvasFont.hpp>
+
+#include <vcl/font.hxx>
+
+#include <vclwrapper.hxx>
+
+#include "cairo_surfaceprovider.hxx"
+
+
+/* Definition of CanvasFont class */
+
+namespace cairocanvas
+{
+    typedef ::comphelper::WeakComponentImplHelper< css::rendering::XCanvasFont,
+                                             css::lang::XServiceInfo > 
CanvasFont_Base;
+
+    class CanvasFont : public CanvasFont_Base
+    {
+    public:
+        typedef rtl::Reference<CanvasFont> Reference;
+        /// make noncopyable
+        CanvasFont(const CanvasFont&) = delete;
+        const CanvasFont& operator=(const CanvasFont&) = delete;
+
+        CanvasFont( const css::rendering::FontRequest&                         
         fontRequest,
+                    const css::uno::Sequence< css::beans::PropertyValue >&     
         extraFontProperties,
+                    const css::geometry::Matrix2D&                             
         rFontMatrix,
+                    SurfaceProviderRef                                         
         rDevice );
+
+        /// Dispose all internal references
+        virtual void disposing(std::unique_lock<std::mutex>& rGuard) override;
+
+        // XCanvasFont
+        virtual css::uno::Reference< css::rendering::XTextLayout > SAL_CALL 
createTextLayout( const css::rendering::StringContext& aText, sal_Int8 
nDirection, sal_Int64 nRandomSeed ) override;
+        virtual css::rendering::FontRequest SAL_CALL getFontRequest(  ) 
override;
+        virtual css::rendering::FontMetrics SAL_CALL getFontMetrics(  ) 
override;
+        virtual css::uno::Sequence< double > SAL_CALL getAvailableSizes(  ) 
override;
+        virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL 
getExtraFontProperties(  ) override;
+
+        // XServiceInfo
+        virtual OUString SAL_CALL getImplementationName() override;
+        virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName 
) override;
+        virtual css::uno::Sequence< OUString > SAL_CALL 
getSupportedServiceNames() override;
+
+        vcl::Font const & getVCLFont() const;
+
+        sal_uInt32 getEmphasisMark() const { return mnEmphasisMark; }
+
+    private:
+        ::canvas::vcltools::VCLObject<vcl::Font> maFont;
+        css::rendering::FontRequest              maFontRequest;
+        SurfaceProviderRef                       mpRefDevice;
+        sal_uInt32                               mnEmphasisMark;
+    };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/canvas/source/cairo/cairo_canvashelper.cxx 
b/canvas/source/cairo/cairo_canvashelper.cxx
new file mode 100644
index 000000000000..701ad1e47859
--- /dev/null
+++ b/canvas/source/cairo/cairo_canvashelper.cxx
@@ -0,0 +1,2045 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <algorithm>
+#include <tuple>
+
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/utils/canvastools.hxx>
+#include <basegfx/utils/keystoplerp.hxx>
+#include <basegfx/utils/lerp.hxx>
+#include <com/sun/star/rendering/ColorComponentTag.hpp>
+#include <com/sun/star/rendering/ColorSpaceType.hpp>
+#include <com/sun/star/rendering/CompositeOperation.hpp>
+#include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
+#include <com/sun/star/rendering/PathCapType.hpp>
+#include <com/sun/star/rendering/PathJoinType.hpp>
+#include <com/sun/star/rendering/RenderingIntent.hpp>
+#include <com/sun/star/rendering/TexturingMode.hpp>
+#include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp>
+#include <com/sun/star/util/Endianness.hpp>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/math.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <vcl/bitmapex.hxx>
+#include <vcl/BitmapTools.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/virdev.hxx>
+
+#include <canvas/canvastools.hxx>
+#include <parametricpolypolygon.hxx>
+#include <cairo.h>
+
+#include "cairo_cachedbitmap.hxx"
+#include "cairo_canvasbitmap.hxx"
+#include "cairo_canvashelper.hxx"
+
+using namespace ::cairo;
+using namespace ::com::sun::star;
+
+namespace cairocanvas
+{
+    CanvasHelper::CanvasHelper() :
+        mpSurfaceProvider(nullptr),
+        mpDevice(nullptr),
+        mbHaveAlpha()
+    {
+    }
+
+    void CanvasHelper::disposing()
+    {
+        mpSurface.reset();
+        mpCairo.reset();
+        mpVirtualDevice.disposeAndClear();
+        mpDevice = nullptr;
+        mpSurfaceProvider = nullptr;
+    }
+
+    void CanvasHelper::init( const ::basegfx::B2ISize&  rSizePixel,
+                             SurfaceProvider&           rSurfaceProvider,
+                             rendering::XGraphicDevice* pDevice )
+    {
+        maSize = rSizePixel;
+        mpSurfaceProvider = &rSurfaceProvider;
+        mpDevice = pDevice;
+    }
+
+    void CanvasHelper::setSize( const ::basegfx::B2ISize& rSize )
+    {
+        maSize = rSize;
+    }
+
+    void CanvasHelper::setSurface( const SurfaceSharedPtr& pSurface, bool 
bHasAlpha )
+    {
+        mbHaveAlpha = bHasAlpha;
+        mpVirtualDevice.disposeAndClear();
+        mpSurface = pSurface;
+        mpCairo = pSurface->getCairo();
+    }
+
+    static void setColor( cairo_t* pCairo,
+                          const uno::Sequence<double>& rColor )
+    {
+        if( rColor.getLength() > 3 )
+        {
+            cairo_set_source_rgba( pCairo,
+                                   rColor[0],
+                                   rColor[1],
+                                   rColor[2],
+                                   rColor[3] );
+        }
+        else if( rColor.getLength() == 3 )
+            cairo_set_source_rgb( pCairo,
+                                  rColor[0],
+                                  rColor[1],
+                                  rColor[2] );
+    }
+
+    void CanvasHelper::useStates( const rendering::ViewState& viewState,
+                                  const rendering::RenderState& renderState,
+                                  bool bSetColor )
+    {
+        cairo_matrix_t aViewMatrix;
+        cairo_matrix_t aRenderMatrix;
+        cairo_matrix_t aCombinedMatrix;
+
+        cairo_matrix_init( &aViewMatrix,
+                           viewState.AffineTransform.m00, 
viewState.AffineTransform.m10, viewState.AffineTransform.m01,
+                           viewState.AffineTransform.m11, 
viewState.AffineTransform.m02, viewState.AffineTransform.m12);
+        cairo_matrix_init( &aRenderMatrix,
+                           renderState.AffineTransform.m00, 
renderState.AffineTransform.m10, renderState.AffineTransform.m01,
+                           renderState.AffineTransform.m11, 
renderState.AffineTransform.m02, renderState.AffineTransform.m12);
+        cairo_matrix_multiply( &aCombinedMatrix, &aRenderMatrix, &aViewMatrix);
+
+        if( viewState.Clip.is() )
+        {
+            SAL_INFO( "canvas.cairo", "view clip");
+
+            aViewMatrix.x0 = basegfx::fround( aViewMatrix.x0 );
+            aViewMatrix.y0 = basegfx::fround( aViewMatrix.y0 );
+            cairo_set_matrix( mpCairo.get(), &aViewMatrix );
+            doPolyPolygonPath( viewState.Clip, Clip );
+        }
+
+        aCombinedMatrix.x0 = basegfx::fround( aCombinedMatrix.x0 );
+        aCombinedMatrix.y0 = basegfx::fround( aCombinedMatrix.y0 );
+        cairo_set_matrix( mpCairo.get(), &aCombinedMatrix );
+
+        if( renderState.Clip.is() )
+        {
+            SAL_INFO( "canvas.cairo", "render clip BEGIN");
+
+            doPolyPolygonPath( renderState.Clip, Clip );
+            SAL_INFO( "canvas.cairo", "render clip END");
+        }
+
+        if( bSetColor )
+            setColor(mpCairo.get(),renderState.DeviceColor);
+
+        cairo_operator_t compositingMode( CAIRO_OPERATOR_OVER );
+        switch( renderState.CompositeOperation )
+        {
+            case rendering::CompositeOperation::CLEAR:
+                compositingMode = CAIRO_OPERATOR_CLEAR;
+                break;
+            case rendering::CompositeOperation::SOURCE:
+                compositingMode = CAIRO_OPERATOR_SOURCE;
+                break;
+            case rendering::CompositeOperation::DESTINATION:
+            case rendering::CompositeOperation::UNDER:
+                compositingMode = CAIRO_OPERATOR_DEST;
+                break;
+            case rendering::CompositeOperation::OVER:
+                compositingMode = CAIRO_OPERATOR_OVER;
+                break;
+            case rendering::CompositeOperation::INSIDE:
+                compositingMode = CAIRO_OPERATOR_IN;
+                break;
+            case rendering::CompositeOperation::INSIDE_REVERSE:
+                compositingMode = CAIRO_OPERATOR_OUT;
+                break;
+            case rendering::CompositeOperation::OUTSIDE:
+                compositingMode = CAIRO_OPERATOR_DEST_OVER;
+                break;
+            case rendering::CompositeOperation::OUTSIDE_REVERSE:
+                compositingMode = CAIRO_OPERATOR_DEST_OUT;
+                break;
+            case rendering::CompositeOperation::ATOP:
+                compositingMode = CAIRO_OPERATOR_ATOP;
+                break;
+            case rendering::CompositeOperation::ATOP_REVERSE:
+                compositingMode = CAIRO_OPERATOR_DEST_ATOP;
+                break;
+            case rendering::CompositeOperation::XOR:
+                compositingMode = CAIRO_OPERATOR_XOR;
+                break;
+            case rendering::CompositeOperation::ADD:
+                compositingMode = CAIRO_OPERATOR_ADD;
+                break;
+            case rendering::CompositeOperation::SATURATE:
+                compositingMode = CAIRO_OPERATOR_SATURATE;
+                break;
+        }
+        cairo_set_operator( mpCairo.get(), compositingMode );
+    }
+
+    void CanvasHelper::clear()
+    {
+        SAL_INFO( "canvas.cairo", "clear whole area: " << maSize.getWidth() << 
" x " << maSize.getHeight() );
+
+        if( !mpCairo )
+            return;
+
+        cairo_save( mpCairo.get() );
+
+        cairo_identity_matrix( mpCairo.get() );
+        // this does not really differ from all-zero, as cairo
+        // internally converts to premultiplied alpha. but anyway,
+        // this keeps it consistent with the other canvas impls
+        if( mbHaveAlpha )
+            cairo_set_source_rgba( mpCairo.get(), 1.0, 1.0, 1.0, 0.0 );
+        else
+            cairo_set_source_rgb( mpCairo.get(), 1.0, 1.0, 1.0 );
+        cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE );
+
+        cairo_rectangle( mpCairo.get(), 0, 0, maSize.getWidth(), 
maSize.getHeight() );
+        cairo_fill( mpCairo.get() );
+
+        cairo_restore( mpCairo.get() );
+    }
+
+    void CanvasHelper::drawLine( const rendering::XCanvas*      /*pCanvas*/,
+                                 const geometry::RealPoint2D&   aStartPoint,
+                                 const geometry::RealPoint2D&   aEndPoint,
+                                 const rendering::ViewState&    viewState,
+                                 const rendering::RenderState&  renderState )
+    {
+        if( !mpCairo )
+            return;
+
+        cairo_save( mpCairo.get() );
+
+        cairo_set_line_width( mpCairo.get(), 1 );
+
+        useStates( viewState, renderState, true );
+
+        cairo_move_to( mpCairo.get(), aStartPoint.X + 0.5, aStartPoint.Y + 0.5 
);
+        cairo_line_to( mpCairo.get(), aEndPoint.X + 0.5, aEndPoint.Y + 0.5 );
+        cairo_stroke( mpCairo.get() );
+
+        cairo_restore( mpCairo.get() );
+    }
+
+    void CanvasHelper::drawBezier( const rendering::XCanvas*            ,
+                                   const geometry::RealBezierSegment2D& 
aBezierSegment,
+                                   const geometry::RealPoint2D&         
aEndPoint,
+                                   const rendering::ViewState&          
viewState,
+                                   const rendering::RenderState&        
renderState )
+    {
+        if( !mpCairo )
+            return;
+
+        cairo_save( mpCairo.get() );
+
+        cairo_set_line_width( mpCairo.get(), 1 );
+
+        useStates( viewState, renderState, true );
+
+        cairo_move_to( mpCairo.get(), aBezierSegment.Px + 0.5, 
aBezierSegment.Py + 0.5 );
+        // tdf#99165 correction of control points not needed here, only 
hairlines drawn
+        // (see cairo_set_line_width above)
+        cairo_curve_to( mpCairo.get(),
+                        aBezierSegment.C1x + 0.5, aBezierSegment.C1y + 0.5,
+                        aBezierSegment.C2x + 0.5, aBezierSegment.C2y + 0.5,
+                        aEndPoint.X + 0.5, aEndPoint.Y + 0.5 );
+        cairo_stroke( mpCairo.get() );
+
+        cairo_restore( mpCairo.get() );
+    }
+
+constexpr OUStringLiteral PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME = 
u"Canvas::ParametricPolyPolygon";
+
+    /** surfaceFromXBitmap Create a surface from XBitmap
+     * @param xBitmap bitmap image that will be used for the surface
+     * @param bHasAlpha will be set to true if resulting surface has alpha
+     *
+     * This is a helper function for the other surfaceFromXBitmap().
+     * This function tries to create surface from xBitmap by checking if 
xBitmap is CanvasBitmap or SpriteCanvas.
+     *
+     * @return created surface or NULL
+     **/
+    static SurfaceSharedPtr surfaceFromXBitmap( const uno::Reference< 
rendering::XBitmap >& xBitmap )
+    {
+        CanvasBitmap* pBitmapImpl = dynamic_cast< CanvasBitmap* >( 
xBitmap.get() );
+        if( pBitmapImpl )
+            return pBitmapImpl->getSurface();
+
+        SurfaceProvider* pSurfaceProvider = dynamic_cast<SurfaceProvider*>( 
xBitmap.get() );
+        if( pSurfaceProvider )
+            return pSurfaceProvider->getSurface();
+
+        return SurfaceSharedPtr();
+    }
+
+    static ::BitmapEx bitmapExFromXBitmap( const uno::Reference< 
rendering::XBitmap >& xBitmap )
+    {
+        // TODO(F1): Add support for floating point bitmap formats
+        uno::Reference<rendering::XIntegerReadOnlyBitmap> xIntBmp(xBitmap,
+                                                                  
uno::UNO_QUERY_THROW);
+        ::BitmapEx aBmpEx = vcl::unotools::bitmapExFromXBitmap(xIntBmp);
+        if( !aBmpEx.IsEmpty() )
+            return aBmpEx;
+
+        // TODO(F1): extract pixel from XBitmap interface
+        ENSURE_OR_THROW( false,
+                         "bitmapExFromXBitmap(): could not extract BitmapEx" );
+
+        return ::BitmapEx();
+    }
+
+    /** surfaceFromXBitmap Create a surface from XBitmap
+     * @param xBitmap bitmap image that will be used for the surface
+     * @param rDevice reference to the device into which we want to draw
+     * @param data will be filled with alpha data, if xBitmap is 
alpha/transparent image
+     * @param bHasAlpha will be set to true if resulting surface has alpha
+     *
+     * This function tries various methods for creating a surface from 
xBitmap. It also uses
+     * the helper function surfaceFromXBitmap( xBitmap, bHasAlpha )
+     *
+     * @return created surface or NULL
+     **/
+    static SurfaceSharedPtr surfaceFromXBitmap( const uno::Reference< 
rendering::XBitmap >& xBitmap, const SurfaceProviderRef& rSurfaceProvider, 
unsigned char*& data, bool& bHasAlpha )
+    {
+        bHasAlpha = xBitmap->hasAlpha();
+        SurfaceSharedPtr pSurface = surfaceFromXBitmap( xBitmap );
+        if( pSurface )
+            data = nullptr;
+        else
+        {
+            ::BitmapEx aBmpEx = bitmapExFromXBitmap(xBitmap);
+            ::Bitmap aBitmap = aBmpEx.GetBitmap();
+
+            // there's no pixmap for alpha bitmap. we might still
+            // use rgb pixmap and only access alpha pixels the
+            // slow way. now we just speedup rgb bitmaps
+            if( !aBmpEx.IsAlpha() )
+            {
+                pSurface = rSurfaceProvider->createSurface( aBitmap );
+                data = nullptr;
+                bHasAlpha = false;
+            }
+
+            if( !pSurface )
+            {
+                tools::Long nWidth;
+                tools::Long nHeight;
+                vcl::bitmap::CanvasCairoExtractBitmapData(aBmpEx, aBitmap, 
data, bHasAlpha, nWidth, nHeight);
+
+                pSurface = rSurfaceProvider->getOutputDevice()->CreateSurface(
+                    CairoSurfaceSharedPtr(
+                        cairo_image_surface_create_for_data(
+                            data,
+                            bHasAlpha ? CAIRO_FORMAT_ARGB32 : 
CAIRO_FORMAT_RGB24,
+                            nWidth, nHeight, nWidth*4 ),
+                        &cairo_surface_destroy) );
+
+                SAL_INFO( "canvas.cairo","image: " << nWidth << " x " << 
nHeight << " alpha: " << bHasAlpha);
+            }
+        }
+
+        return pSurface;
+    }
+
+    static void addColorStops( cairo_pattern_t* pPattern, const uno::Sequence< 
uno::Sequence< double > >& rColors, const uno::Sequence< double >& rStops, bool 
bReverseStops )
+    {
+        int i;
+
+        OSL_ASSERT( rColors.getLength() == rStops.getLength() );
+
+        for( i = 0; i < rColors.getLength(); i++ )
+        {
+            const uno::Sequence< double >& rColor( rColors[i] );
+            float stop = bReverseStops ? 1 - rStops[i] : rStops[i];
+            if( rColor.getLength() == 3 )
+                cairo_pattern_add_color_stop_rgb( pPattern, stop, rColor[0], 
rColor[1], rColor[2] );
+            else if( rColor.getLength() == 4 )
+            {
+                double alpha = rColor[3];
+                // cairo expects premultiplied alpha
+                cairo_pattern_add_color_stop_rgba( pPattern, stop, 
rColor[0]*alpha, rColor[1]*alpha, rColor[2]*alpha, alpha );
+            }
+        }
+    }
+
+    static uno::Sequence<double> lerp(const uno::Sequence<double>& rLeft, 
const uno::Sequence<double>& rRight, double fAlpha)
+    {
+        if( rLeft.getLength() == 3 )
+        {
+            return
+            {
+                basegfx::utils::lerp(rLeft[0],rRight[0],fAlpha),
+                basegfx::utils::lerp(rLeft[1],rRight[1],fAlpha),
+                basegfx::utils::lerp(rLeft[2],rRight[2],fAlpha)
+            };
+        }
+        else if( rLeft.getLength() == 4 )
+        {
+            return
+            {
+                basegfx::utils::lerp(rLeft[0],rRight[0],fAlpha),
+                basegfx::utils::lerp(rLeft[1],rRight[1],fAlpha),
+                basegfx::utils::lerp(rLeft[2],rRight[2],fAlpha),
+                basegfx::utils::lerp(rLeft[3],rRight[3],fAlpha)
+            };
+        }
+
+        return {};
+    }
+
+    static cairo_pattern_t* patternFromParametricPolyPolygon( 
::canvas::ParametricPolyPolygon const & rPolygon )
+    {
+        cairo_pattern_t* pPattern = nullptr;
+        const ::canvas::ParametricPolyPolygon::Values& aValues = 
rPolygon.getValues();
+        double x0, x1, y0, y1, cx, cy, r0, r1;
+
+        switch( aValues.meType )
+        {
+            case ::canvas::ParametricPolyPolygon::GradientType::Linear:
+                x0 = 0;
+                y0 = 0;
+                x1 = 1;
+                y1 = 0;
+                pPattern = cairo_pattern_create_linear( x0, y0, x1, y1 );
+                addColorStops( pPattern, aValues.maColors, aValues.maStops, 
false );
+                break;
+
+            case ::canvas::ParametricPolyPolygon::GradientType::Elliptical:
+                cx = 0;
+                cy = 0;
+                r0 = 0;
+                r1 = 1;
+
+                pPattern = cairo_pattern_create_radial( cx, cy, r0, cy, cy, r1 
);
+                addColorStops( pPattern, aValues.maColors, aValues.maStops, 
true );
+                break;
+            default:
+                break;
+        }
+
+        return pPattern;
+    }
+
+    static void doOperation( Operation aOperation,
+                             cairo_t* pCairo,
+                             const uno::Sequence< rendering::Texture >* 
pTextures,
+                             const SurfaceProviderRef& pDevice,
+                             const basegfx::B2DRange& rBounds )
+    {
+        switch( aOperation )
+        {
+            case Fill:
+                /* TODO: multitexturing */
+                if( pTextures )
+                {
+                    const css::rendering::Texture& aTexture ( (*pTextures)[0] 
);
+                    if( aTexture.Bitmap.is() )
+                    {
+                        unsigned char* data = nullptr;
+                        bool bHasAlpha = false;
+                        SurfaceSharedPtr pSurface = surfaceFromXBitmap( 
(*pTextures)[0].Bitmap, pDevice, data, bHasAlpha );
+
+                        if( pSurface )
+                        {
+                            cairo_pattern_t* pPattern;
+
+                            cairo_save( pCairo );
+
+                            css::geometry::AffineMatrix2D aTransform( 
aTexture.AffineTransform );
+                            cairo_matrix_t aScaleMatrix, aTextureMatrix, 
aScaledTextureMatrix;
+
+                            cairo_matrix_init( &aTextureMatrix,
+                                               aTransform.m00, aTransform.m10, 
aTransform.m01,
+                                               aTransform.m11, aTransform.m02, 
aTransform.m12);
+
+                            geometry::IntegerSize2D aSize = 
aTexture.Bitmap->getSize();
+
+                            cairo_matrix_init_scale( &aScaleMatrix, 
1.0/aSize.Width, 1.0/aSize.Height );
+                            cairo_matrix_multiply( &aScaledTextureMatrix, 
&aScaleMatrix, &aTextureMatrix );
+                            cairo_matrix_invert( &aScaledTextureMatrix );
+
+                            // we don't care about repeat mode yet, so the 
workaround is disabled for now
+                            pPattern = cairo_pattern_create_for_surface( 
pSurface->getCairoSurface().get() );
+
+                            if( aTexture.RepeatModeX == 
rendering::TexturingMode::REPEAT &&
+                                aTexture.RepeatModeY == 
rendering::TexturingMode::REPEAT )
+                            {
+                                cairo_pattern_set_extend( pPattern, 
CAIRO_EXTEND_REPEAT );
+                            }
+                            else if ( aTexture.RepeatModeX == 
rendering::TexturingMode::NONE &&
+                                      aTexture.RepeatModeY == 
rendering::TexturingMode::NONE )
+                            {
+                                cairo_pattern_set_extend( pPattern, 
CAIRO_EXTEND_NONE );
+                            }
+                            else if ( aTexture.RepeatModeX == 
rendering::TexturingMode::CLAMP &&
+                                      aTexture.RepeatModeY == 
rendering::TexturingMode::CLAMP )
+                            {
+                                cairo_pattern_set_extend( pPattern, 
CAIRO_EXTEND_PAD );
+                            }
+
+                            aScaledTextureMatrix.x0 = basegfx::fround( 
aScaledTextureMatrix.x0 );
+                            aScaledTextureMatrix.y0 = basegfx::fround( 
aScaledTextureMatrix.y0 );
+
+                            double x1, y1, x2, y2;
+                            cairo_path_extents(pCairo, &x1, &y1, &x2, &y2);
+                            aScaledTextureMatrix.x0 -= (x1 * 
aScaledTextureMatrix.xx);
+                            aScaledTextureMatrix.y0 -= (y1 * 
aScaledTextureMatrix.yy);
+
+                            cairo_pattern_set_matrix( pPattern, 
&aScaledTextureMatrix );
+
+                            cairo_set_source( pCairo, pPattern );
+                            if( !bHasAlpha )
+                                cairo_set_operator( pCairo, 
CAIRO_OPERATOR_SOURCE );
+                            cairo_fill( pCairo );
+
+                            cairo_restore( pCairo );
+
+                            cairo_pattern_destroy( pPattern );
+                        }
+
+                        if( data )
+                            free( data );
+                    }
+                    else if( aTexture.Gradient.is() )
+                    {
+                        uno::Reference< lang::XServiceInfo > xRef( 
aTexture.Gradient, uno::UNO_QUERY );
+
+                        SAL_INFO( "canvas.cairo", "gradient fill" );
+                        if( xRef.is() && xRef->getImplementationName() == 
PARAMETRICPOLYPOLYGON_IMPLEMENTATION_NAME )
+                        {
+                            // TODO(Q1): Maybe use dynamic_cast here
+
+                            // TODO(E1): Return value
+                            // TODO(F1): FillRule
+                            SAL_INFO( "canvas.cairo", "known implementation" );
+
+                            ::canvas::ParametricPolyPolygon* pPolyImpl = 
static_cast< ::canvas::ParametricPolyPolygon* >( aTexture.Gradient.get() );
+                            css::geometry::AffineMatrix2D aTransform( 
aTexture.AffineTransform );
+                            cairo_matrix_t aTextureMatrix;
+
+                            cairo_matrix_init( &aTextureMatrix,
+                                               aTransform.m00, aTransform.m10, 
aTransform.m01,
+                                               aTransform.m11, aTransform.m02, 
aTransform.m12);
+                            if( pPolyImpl->getValues().meType == 
canvas::ParametricPolyPolygon::GradientType::Rectangular )
+                            {
+                                // no general path gradient yet in cairo; 
emulate then
+                                cairo_save( pCairo );
+                                cairo_clip( pCairo );
+
+                                // fill bound rect with start color
+                                cairo_rectangle( pCairo, rBounds.getMinX(), 
rBounds.getMinY(),
+                                                 rBounds.getWidth(), 
rBounds.getHeight() );
+                                
setColor(pCairo,pPolyImpl->getValues().maColors[0]);
+                                cairo_fill(pCairo);
+
+                                cairo_transform( pCairo, &aTextureMatrix );
+
+                                // longest line in gradient bound rect
+                                const unsigned int nGradientSize(
+                                    static_cast<unsigned int>(
+                                        
::basegfx::B2DVector(rBounds.getMinimum() - rBounds.getMaximum()).getLength() + 
1.0 ) );
+
+                                // typical number for pixel of the same color 
(strip size)
+                                const unsigned int nStripSize( nGradientSize < 
50 ? 2 : 4 );
+
+                                // use at least three steps, and at utmost the 
number of color
+                                // steps
+                                const unsigned int nStepCount(
+                                    std::max(
+                                        3U,
+                                        std::min(
+                                            nGradientSize / nStripSize,
+                                            128U )) + 1 );
+
+                                const uno::Sequence<double>* 
pColors=&pPolyImpl->getValues().maColors[0];
+                                basegfx::utils::KeyStopLerp 
aLerper(pPolyImpl->getValues().maStops);
+                                for( unsigned int i=1; i<nStepCount; ++i )
+                                {
+                                    const double fT( i/double(nStepCount) );
+
+                                    std::ptrdiff_t nIndex;
+                                    double fAlpha;
+                                    std::tie(nIndex,fAlpha)=aLerper.lerp(fT);
+
+                                    setColor(pCairo, lerp(pColors[nIndex], 
pColors[nIndex+1], fAlpha));
+                                    cairo_rectangle( pCairo, -1+fT, -1+fT, 
2-2*fT, 2-2*fT );
+                                    cairo_fill(pCairo);
+                                }
+
+                                cairo_restore( pCairo );
+                            }
+                            else
+                            {
+                                cairo_pattern_t* pPattern = 
patternFromParametricPolyPolygon( *pPolyImpl );
+
+                                if( pPattern )
+                                {
+                                    SAL_INFO( "canvas.cairo", "filling with 
pattern" );
+
+                                    cairo_save( pCairo );
+
+                                    cairo_transform( pCairo, &aTextureMatrix );
+                                    cairo_set_source( pCairo, pPattern );
+                                    cairo_fill( pCairo );
+                                    cairo_restore( pCairo );
+
+                                    cairo_pattern_destroy( pPattern );
-e 
... etc. - the rest is truncated

Reply via email to