vcl/inc/salgdi.hxx              |   11 +++++++++++
 vcl/inc/salgdiimpl.hxx          |    2 ++
 vcl/inc/skia/gdiimpl.hxx        |    4 ++++
 vcl/skia/gdiimpl.cxx            |   31 +++++++++++++++++++++++++++++++
 vcl/source/gdi/salgdilayout.cxx |    8 ++++++++
 vcl/source/outdev/wallpaper.cxx |   29 ++++++++++++++++++++++++-----
 6 files changed, 80 insertions(+), 5 deletions(-)

New commits:
commit c92f890cf517e8a2473f757d422d0f83c0d1f7be
Author:     Noel Grandin <[email protected]>
AuthorDate: Fri Sep 12 19:24:56 2025 +0200
Commit:     Noel Grandin <[email protected]>
CommitDate: Fri Sep 12 20:57:42 2025 +0200

    tdf#160345 skia native rendering of bitmap tiling
    
    which makes this SVG pretty fast, should benefit a lot
    of texture/gradient fill type drawing
    
    Change-Id: Ib9684af56d6208d141165d6b26e64c313033f64f
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190899
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <[email protected]>

diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx
index d2e98d540033..bbbc17a0658b 100644
--- a/vcl/inc/salgdi.hxx
+++ b/vcl/inc/salgdi.hxx
@@ -374,6 +374,12 @@ public:
                                     sal_uInt8 nTransparency,
                                     const OutputDevice& rOutDev );
 
+    /** fill/tile with given bitmap
+     *
+     * @returns true if successfully drawn, false if not able to draw
+     */
+    virtual bool                DrawBitmapWallpaper(tools::Long nStartX, 
tools::Long nStartY, tools::Long nRight, tools::Long nBottom, tools::Long 
nBmpWidth, tools::Long nBmpHeight, const SalBitmap& aBmp);
+
     SAL_DLLPRIVATE virtual OUString getRenderBackendName() const;
 
     virtual SystemGraphicsData  GetGraphicsData() const = 0;
@@ -827,6 +833,11 @@ public:
     {
         return GetImpl()->getRenderBackendName();
     }
+
+    bool DrawBitmapWallpaper(tools::Long nStartX, tools::Long nStartY, 
tools::Long nRight, tools::Long nBottom, tools::Long nBmpWidth, tools::Long 
nBmpHeight, const SalBitmap& rBmp) override
+    {
+        return GetImpl()->DrawBitmapWallpaper(nStartX, nStartY, nRight, 
nBottom, nBmpWidth, nBmpHeight, rBmp);
+    }
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/salgdiimpl.hxx b/vcl/inc/salgdiimpl.hxx
index 46cd219e191a..501abac30edd 100644
--- a/vcl/inc/salgdiimpl.hxx
+++ b/vcl/inc/salgdiimpl.hxx
@@ -199,6 +199,8 @@ public:
     virtual bool implDrawGradient(basegfx::B2DPolyPolygon const & 
rPolyPolygon, SalGradient const & rGradient) = 0;
 
     virtual bool supportsOperation(OutDevSupportType eType) const = 0;
+
+    virtual bool DrawBitmapWallpaper(tools::Long /*nStartX*/, tools::Long 
/*nStartY*/, tools::Long /*nRight*/, tools::Long /*nBottom*/, tools::Long 
/*nBmpWidth*/, tools::Long /*nBmpHeight*/, const SalBitmap& /*rBmp*/) { return 
false; }
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx
index 8f94d6580c97..df08b15f2b8b 100644
--- a/vcl/inc/skia/gdiimpl.hxx
+++ b/vcl/inc/skia/gdiimpl.hxx
@@ -179,6 +179,10 @@ public:
 
     virtual bool supportsOperation(OutDevSupportType eType) const override;
 
+    virtual bool DrawBitmapWallpaper(tools::Long nStartX, tools::Long nStartY, 
tools::Long nRight,
+                                     tools::Long nBottom, tools::Long 
nBmpWidth,
+                                     tools::Long nBmpHeight, const SalBitmap& 
rBmp) override;
+
     // Dump contents to a file for debugging.
     void dump(const char* file) const;
 
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index 0872b0ac1c5c..49ddbdbf3b3c 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -2050,6 +2050,37 @@ bool SkiaSalGraphicsImpl::implDrawGradient(const 
basegfx::B2DPolyPolygon& rPolyP
     return true;
 }
 
+bool SkiaSalGraphicsImpl::DrawBitmapWallpaper(tools::Long nStartX, tools::Long 
nStartY,
+                                              tools::Long nRight, tools::Long 
nBottom,
+                                              tools::Long nBmpWidth, 
tools::Long nBmpHeight,
+                                              const SalBitmap& rBmp)
+{
+    assert(dynamic_cast<const SkiaSalBitmap*>(&rBmp));
+    const SkiaSalBitmap& rSkiaBitmap = static_cast<const SkiaSalBitmap&>(rBmp);
+
+    sk_sp<SkImage> image = rSkiaBitmap.GetSkImage();
+    sk_sp<SkShader> shader;
+    if (nBmpWidth == image->width() && nBmpHeight == image->height())
+        shader = image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, 
SkSamplingOptions());
+    else
+    {
+        SkMatrix matrix;
+        matrix.set(SkMatrix::kMScaleX, 1.0 * nBmpWidth / image->width());
+        matrix.set(SkMatrix::kMScaleY, 1.0 * nBmpHeight / image->height());
+        shader = image->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, 
SkSamplingOptions(),
+                                   matrix);
+    }
+    SkPaint paint;
+    paint.setBlendMode(SkBlendMode::kSrcATop);
+    paint.setAntiAlias(mParent.getAntiAlias());
+    paint.setShader(shader);
+    getDrawCanvas()->drawRect(
+        SkRect::MakeXYWH(toSkX(nStartX), toSkY(nStartY), nRight - nStartX, 
nBottom - nStartY),
+        paint);
+    postDraw();
+    return true;
+}
+
 static double toRadian(Degree10 degree10th) { return toRadians(3600_deg10 - 
degree10th); }
 static auto toCos(Degree10 degree10th) { return 
SkScalarCos(toRadian(degree10th)); }
 static auto toSin(Degree10 degree10th) { return 
SkScalarSin(toRadian(degree10th)); }
diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx
index 63f35c52f729..94ee667bb398 100644
--- a/vcl/source/gdi/salgdilayout.cxx
+++ b/vcl/source/gdi/salgdilayout.cxx
@@ -891,4 +891,12 @@ bool SalGraphics::ShouldDownscaleIconsAtSurface(double& 
rScaleOut) const
     return comphelper::LibreOfficeKit::isActive();
 }
 
+bool SalGraphics::DrawBitmapWallpaper(
+                tools::Long /*nStartX*/, tools::Long /*nStartY*/, tools::Long 
/*nRight*/,
+                tools::Long /*nBottom*/, tools::Long /*nBmpWidth*/, 
tools::Long /*nBmpHeight*/,
+                const SalBitmap& /*rBmp*/)
+{
+    return false;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/outdev/wallpaper.cxx b/vcl/source/outdev/wallpaper.cxx
index 61b4daf03fc7..bcefc2557551 100644
--- a/vcl/source/outdev/wallpaper.cxx
+++ b/vcl/source/outdev/wallpaper.cxx
@@ -19,6 +19,7 @@
 
 #include <vcl/metaact.hxx>
 #include <vcl/virdev.hxx>
+#include <salgdi.hxx>
 
 #include <cassert>
 
@@ -132,6 +133,9 @@ void OutputDevice::DrawBitmapWallpaper( tools::Long nX, 
tools::Long nY,
 {
     assert(!is_double_buffered_window());
 
+    if( ImplIsRecordLayout() )
+        return;
+
     const Bitmap* pCached = rWallpaper.ImplGetCachedBitmap();
 
     GDIMetaFile* pOldMetaFile = mpMetaFile;
@@ -283,7 +287,6 @@ void OutputDevice::DrawBitmapWallpaper( tools::Long nX, 
tools::Long nY,
                 nFirstX = aPos.X() + ( ( aSize.Width() - nBmpWidth ) >> 1 );
                 nFirstY = aPos.Y() + ( ( aSize.Height() - nBmpHeight ) >> 1 );
             }
-
             const tools::Long nOffX = ( nFirstX - nX ) % nBmpWidth;
             const tools::Long nOffY = ( nFirstY - nY ) % nBmpHeight;
             tools::Long nStartX = nX + nOffX;
@@ -295,14 +298,30 @@ void OutputDevice::DrawBitmapWallpaper( tools::Long nX, 
tools::Long nY,
             if( nOffY > 0 )
                 nStartY -= nBmpHeight;
 
-            for( tools::Long nBmpY = nStartY; nBmpY <= nBottom; nBmpY += 
nBmpHeight )
+
+            // if possible use accelerated path
+            if( eStyle == WallpaperStyle::Tile
+                && (meRasterOp == RasterOp::OverPaint)
+                && (mnDrawMode == DrawModeFlags::Default)
+                && nWidth > 0 && nHeight > 0 )
+                bDrawn = mpGraphics->DrawBitmapWallpaper(nStartX, nStartY, 
nRight, nBottom, nBmpWidth, nBmpHeight, *aBmp.ImplGetSalBitmap());
+
+            if (!bDrawn)
             {
-                for( tools::Long nBmpX = nStartX; nBmpX <= nRight; nBmpX += 
nBmpWidth )
+                for( tools::Long nBmpY = nStartY; nBmpY <= nBottom; nBmpY += 
nBmpHeight )
                 {
-                    DrawBitmapEx( Point( nBmpX, nBmpY ), aBmp );
+                    for( tools::Long nBmpX = nStartX; nBmpX <= nRight; nBmpX 
+= nBmpWidth )
+                    {
+                        const Size aSizePx( aBmp.GetSizePixel() );
+                        if( !aBmp.HasAlpha() )
+                            DrawBitmap( Point( nBmpX, nBmpY ), PixelToLogic( 
aSizePx ), Point(), aSizePx, aBmp, MetaActionType::BMP );
+                        else
+                            DrawBitmapEx(Point( nBmpX, nBmpY ), 
PixelToLogic(aSizePx), Point(), aSizePx, aBmp,
+                                         MetaActionType::BMPEX);
+                    }
                 }
+                bDrawn = true;
             }
-            bDrawn = true;
         }
         break;
     }

Reply via email to