drawinglayer/source/processor2d/cairopixelprocessor2d.cxx | 64 +++++++++++++ include/drawinglayer/processor2d/cairopixelprocessor2d.hxx | 2 2 files changed, 66 insertions(+)
New commits: commit 5707b5dce7547420a154209d06b444f1cb863d60 Author: Noel Grandin <[email protected]> AuthorDate: Tue Oct 14 15:53:59 2025 +0200 Commit: Noel Grandin <[email protected]> CommitDate: Wed Oct 15 10:38:31 2025 +0200 tdf#101083 speed up SVG rendering with pattern fill (2) This is the same thing I did in commit 3cbe3a0259bea4dec70e72191ec3c03441926a07 Author: Noel Grandin <[email protected]> Date: Mon Jun 14 15:05:59 2021 +0200 tdf#101083 speed up SVG rendering with pattern fill but cut and paste from the VclPixelProcessor2D to the CairoPixelProcessor2D code. Which makes this SVG render in reasonable time when using the cairo backend. We can probably do even better by cutting out the usage of VCL here, but this is good enough for now. Change-Id: I959539741eef627b25702c91cad3e5f8ee2b3176 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192394 Tested-by: Jenkins Reviewed-by: Noel Grandin <[email protected]> diff --git a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx index 9f6b5a2e6ec5..70f485b3247d 100644 --- a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx @@ -17,6 +17,7 @@ #include <vcl/alpha.hxx> #include <vcl/cairo.hxx> #include <vcl/CairoFormats.hxx> +#include <vcl/canvastools.hxx> #include <vcl/outdev.hxx> #include <vcl/sysdata.hxx> #include <vcl/svapp.hxx> @@ -49,6 +50,7 @@ #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx> #include <drawinglayer/primitive2d/controlprimitive2d.hxx> #include <drawinglayer/primitive2d/textlayoutdevice.hxx> +#include <drawinglayer/primitive2d/patternfillprimitive2d.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> #include <basegfx/utils/systemdependentdata.hxx> #include <basegfx/utils/bgradient.hxx> @@ -59,6 +61,7 @@ #include <com/sun/star/awt/XControl.hpp> #include <unordered_map> #include <dlfcn.h> +#include "vclhelperbufferdevice.hxx" using namespace com::sun::star; @@ -3449,6 +3452,61 @@ void CairoPixelProcessor2D::processFillGradientPrimitive2D( maBColorModifierStack.pop(); } +void CairoPixelProcessor2D::processPatternFillPrimitive2D( + const primitive2d::PatternFillPrimitive2D& rPrimitive) +{ + const basegfx::B2DRange& rReferenceRange = rPrimitive.getReferenceRange(); + if (rReferenceRange.isEmpty() || rReferenceRange.getWidth() <= 0.0 + || rReferenceRange.getHeight() <= 0.0) + return; + basegfx::B2DPolyPolygon aMask = rPrimitive.getMask(); + aMask.transform(getViewInformation2D().getObjectToViewTransformation()); + const basegfx::B2DRange aMaskRange(aMask.getB2DRange()); + if (aMaskRange.isEmpty() || aMaskRange.getWidth() <= 0.0 || aMaskRange.getHeight() <= 0.0) + return; + sal_uInt32 nTileWidth, nTileHeight; + rPrimitive.getTileSize(nTileWidth, nTileHeight, getViewInformation2D()); + if (nTileWidth == 0 || nTileHeight == 0) + return; + Bitmap aTileImage = rPrimitive.createTileImage(nTileWidth, nTileHeight); + tools::Rectangle aMaskRect = vcl::unotools::rectangleFromB2DRectangle(aMaskRange); + // Unless smooth edges are needed, simply use clipping. + if (basegfx::utils::isRectangle(aMask) || !getViewInformation2D().getUseAntiAliasing()) + { + mpTargetOutputDevice->Push(vcl::PushFlags::CLIPREGION); + mpTargetOutputDevice->IntersectClipRegion(vcl::Region(aMask)); + mpTargetOutputDevice->DrawWallpaper(aMaskRect, Wallpaper(aTileImage)); + mpTargetOutputDevice->Pop(); + return; + } + + impBufferDevice aBufferDevice(*mpTargetOutputDevice, aMaskRange); + if (!aBufferDevice.isVisible()) + return; + // remember last OutDev and set to content + OutputDevice* pLastOutputDevice = mpTargetOutputDevice; + mpTargetOutputDevice = &aBufferDevice.getContent(); + // if the tile is a single pixel big, just flood fill with that pixel color + if (nTileWidth == 1 && nTileHeight == 1) + { + Color col = aTileImage.GetPixelColor(0, 0); + mpTargetOutputDevice->SetLineColor(col); + mpTargetOutputDevice->SetFillColor(col); + mpTargetOutputDevice->DrawRect(aMaskRect); + } + else + mpTargetOutputDevice->DrawWallpaper(aMaskRect, Wallpaper(aTileImage)); + // back to old OutDev + mpTargetOutputDevice = pLastOutputDevice; + // draw mask + VirtualDevice& rMask = aBufferDevice.getTransparence(); + rMask.SetLineColor(); + rMask.SetFillColor(COL_BLACK); + rMask.DrawPolyPolygon(aMask); + // dump buffer to outdev + aBufferDevice.paint(); +} + void CairoPixelProcessor2D::processPolyPolygonRGBAPrimitive2D( const primitive2d::PolyPolygonRGBAPrimitive2D& rPolyPolygonRGBAPrimitive2D) { @@ -4468,6 +4526,12 @@ void CairoPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimit static_cast<const primitive2d::FillGradientPrimitive2D&>(rCandidate)); break; } + case PRIMITIVE2D_ID_PATTERNFILLPRIMITIVE2D: + { + processPatternFillPrimitive2D( + static_cast<const drawinglayer::primitive2d::PatternFillPrimitive2D&>(rCandidate)); + break; + } case PRIMITIVE2D_ID_POLYPOLYGONRGBAPRIMITIVE2D: { processPolyPolygonRGBAPrimitive2D( diff --git a/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx b/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx index cfb489e5dc08..2353347ff316 100644 --- a/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx +++ b/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx @@ -49,6 +49,7 @@ class TextLayouterDevice; class SvgLinearGradientPrimitive2D; class SvgRadialGradientPrimitive2D; class SvgGradientHelper; +class PatternFillPrimitive2D; } namespace basegfx @@ -127,6 +128,7 @@ class UNLESS_MERGELIBS(DRAWINGLAYER_DLLPUBLIC) CairoPixelProcessor2D final : pub processSingleLinePrimitive2D(const primitive2d::SingleLinePrimitive2D& rSingleLinePrimitive2D); void processFillGradientPrimitive2D( const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D); + void processPatternFillPrimitive2D(const primitive2d::PatternFillPrimitive2D& rPrimitive); void processFillGraphicPrimitive2D( const primitive2d::FillGraphicPrimitive2D& rFillGraphicPrimitive2D); void processPolyPolygonRGBAPrimitive2D(
