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(

Reply via email to