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; }
