drawinglayer/source/processor2d/vclhelperbufferdevice.cxx | 2 include/vcl/bitmap.hxx | 42 +++ include/vcl/outdev.hxx | 8 include/vcl/print.hxx | 2 vcl/backendtest/outputdevice/bitmap.cxx | 4 vcl/headless/CairoCommon.cxx | 35 -- vcl/headless/SvpGraphicsBackend.cxx | 5 vcl/inc/headless/CairoCommon.hxx | 2 vcl/inc/headless/SvpGraphicsBackend.hxx | 2 vcl/inc/qt5/QtGraphics.hxx | 2 vcl/inc/quartz/salgdi.h | 2 vcl/inc/salgdi.hxx | 6 vcl/inc/salgdiimpl.hxx | 1 vcl/inc/skia/gdiimpl.hxx | 10 vcl/inc/win/salbmp.h | 2 vcl/inc/win/salgdi.h | 1 vcl/qa/cppunit/BackendTest.cxx | 9 vcl/qa/cppunit/outdev.cxx | 6 vcl/qa/cppunit/skia/skia.cxx | 2 vcl/qt5/QtGraphics_GDI.cxx | 22 - vcl/quartz/AquaGraphicsBackend.cxx | 12 vcl/skia/gdiimpl.cxx | 103 +------ vcl/source/bitmap/bitmap.cxx | 189 ++++++++++++++ vcl/source/gdi/print.cxx | 2 vcl/source/gdi/salgdilayout.cxx | 6 vcl/source/outdev/bitmapex.cxx | 61 +--- vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx | 5 vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx | 2 vcl/win/gdi/gdiimpl.cxx | 5 vcl/win/gdi/gdiimpl.hxx | 1 vcl/win/gdi/salbmp.cxx | 44 --- vcl/win/gdi/salgdi_gdiplus.cxx | 3 32 files changed, 316 insertions(+), 282 deletions(-)
New commits: commit aba63efcdb1b084c6ef68ecb8df2e648e993af13 Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Mon Sep 1 13:45:41 2025 +0200 Commit: Noel Grandin <noel.gran...@collabora.co.uk> CommitDate: Thu Sep 4 17:06:46 2025 +0200 converting the SalGraphics backend from BitmapEx->Bitmap (3) pass a single SalBitmap in drawTransformedBitmap Change-Id: Iacb67804e47867f4ab85b394b14f052807925b75 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190498 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> diff --git a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx index 9358759ea90d..1e6cf9042d1b 100644 --- a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx +++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx @@ -547,7 +547,7 @@ void impBufferDevice::paint(double fTrans) aSizePixel.Width(), aSizePixel.Height(), maDestPixel.TopLeft().X(), maDestPixel.TopLeft().Y()), - BitmapEx(aContent), 1 - fTrans); + aContent, 1 - fTrans); } else { diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx index ce8f5450bcbd..59e6d119086b 100644 --- a/include/vcl/bitmap.hxx +++ b/include/vcl/bitmap.hxx @@ -183,6 +183,48 @@ public: sal_Int32 nX, sal_Int32 nY) const; + /** Create transformed Bitmap + + @param fWidth + The target width in pixels + + @param fHeight + The target height in pixels + + @param rTransformation + The back transformation for each pixel in (0 .. fWidth),(0 .. fHeight) to + local pixel coordinates + */ + [[nodiscard]] + Bitmap TransformBitmap( + double fWidth, + double fHeight, + const basegfx::B2DHomMatrix& rTransformation) const; + + /** Create transformed Bitmap + + @param rTransformation + The transformation from unit coordinates to the unit range + + @param rVisibleRange + The relative visible range in unit coordinates, relative to (0,0,1,1) which + defines the whole target area + + @param fMaximumArea + A limitation for the maximum size of pixels to use for the result + + The target size of the result bitmap is defined by transforming the given + rTargetRange with the given rTransformation; the area of the result is + linearly scaled to not exceed the given fMaximumArea + + @return The transformed bitmap + */ + [[nodiscard]] + SAL_DLLPRIVATE Bitmap getTransformed( + const basegfx::B2DHomMatrix& rTransformation, + const basegfx::B2DRange& rVisibleRange, + double fMaximumArea) const; + /** Convert bitmap format @param eConversion diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx index 812a982d153f..d1bdfff13411 100644 --- a/include/vcl/outdev.hxx +++ b/include/vcl/outdev.hxx @@ -1388,10 +1388,6 @@ public: @param fAlpha Optional additional alpha to use for drawing (0 to 1, 1 being no change). */ - void DrawTransformedBitmapEx( - const basegfx::B2DHomMatrix& rTransformation, - const BitmapEx& rBitmapEx, - double fAlpha = 1.0); void DrawTransformedBitmapEx( const basegfx::B2DHomMatrix& rTransformation, const Bitmap& rBitmap, @@ -1415,13 +1411,13 @@ protected: /** Transform and draw a bitmap directly @param aFullTransform The B2DHomMatrix used for the transformation - @param rBitmapEx Reference to the bitmap to be transformed and drawn + @param rBitmap Reference to the bitmap to be transformed and drawn @return true if it was able to draw the bitmap, false if not */ virtual bool DrawTransformBitmapExDirect( const basegfx::B2DHomMatrix& aFullTransform, - const BitmapEx& rBitmapEx, + const Bitmap& rBitmap, double fAlpha = 1.0); /** Transform and reduce the area that needs to be drawn of the bitmap and return the new diff --git a/include/vcl/print.hxx b/include/vcl/print.hxx index a4d49341c9c0..9b6d4f9ad8ca 100644 --- a/include/vcl/print.hxx +++ b/include/vcl/print.hxx @@ -164,7 +164,7 @@ protected: const Point& rSrcPtPixel, const Size& rSrcSizePixel) override; bool DrawTransformBitmapExDirect( const basegfx::B2DHomMatrix& aFullTransform, - const BitmapEx& rBitmapEx, double fAlpha = 1.0) override; + const Bitmap& rBitmap, double fAlpha = 1.0) override; bool TransformAndReduceBitmapExToTargetRange( const basegfx::B2DHomMatrix& aFullTransform, basegfx::B2DRange &aVisibleRange, double &fMaximumArea) override; diff --git a/vcl/backendtest/outputdevice/bitmap.cxx b/vcl/backendtest/outputdevice/bitmap.cxx index e9a5c3b3a1c5..4ee9cc528dac 100644 --- a/vcl/backendtest/outputdevice/bitmap.cxx +++ b/vcl/backendtest/outputdevice/bitmap.cxx @@ -37,7 +37,7 @@ Bitmap OutputDeviceTestBitmap::setupDrawTransformedBitmap(vcl::PixelFormat aBitm aTransform.translate((maVDRectangle.GetWidth() / 2.0) - (aBitmapSize.Width() / 2.0), (maVDRectangle.GetHeight() / 2.0) - (aBitmapSize.Height() / 2.0)); - mpVirtualDevice->DrawTransformedBitmapEx(aTransform, BitmapEx(aBitmap)); + mpVirtualDevice->DrawTransformedBitmapEx(aTransform, aBitmap); return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); } @@ -59,7 +59,7 @@ Bitmap OutputDeviceTestBitmap::setupComplexDrawTransformedBitmap(vcl::PixelForma aTransform.scale(aBitmapSize.Width() * 2, aBitmapSize.Height() * 2); aTransform.translate(1, 1); - mpVirtualDevice->DrawTransformedBitmapEx(aTransform, BitmapEx(aBitmap)); + mpVirtualDevice->DrawTransformedBitmapEx(aTransform, aBitmap); return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); } diff --git a/vcl/headless/CairoCommon.cxx b/vcl/headless/CairoCommon.cxx index 9e6140b82676..a9bdff539014 100644 --- a/vcl/headless/CairoCommon.cxx +++ b/vcl/headless/CairoCommon.cxx @@ -1699,16 +1699,8 @@ void CairoCommon::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitmap& rS bool CairoCommon::drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha, - bool bAntiAlias) + double fAlpha, bool bAntiAlias) { - if (pAlphaBitmap && pAlphaBitmap->GetBitCount() != 8 && pAlphaBitmap->GetBitCount() != 1) - { - SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawTransformedBitmap alpha depth case: " - << pAlphaBitmap->GetBitCount()); - return false; - } - if (fAlpha != 1.0) return false; @@ -1725,26 +1717,6 @@ bool CairoCommon::drawTransformedBitmap(const basegfx::B2DPoint& rNull, const ba return false; } - // MM02 try to access buffered MaskHelper - std::shared_ptr<MaskHelper> aMask; - if (nullptr != pAlphaBitmap) - { - tryToUseMaskBuffer(*pAlphaBitmap, aMask); - } - - // access cairo_surface_t from MaskHelper - cairo_surface_t* mask(nullptr); - if (aMask) - { - mask = aMask->getSurface(nDestWidth, nDestHeight); - } - - if (nullptr != pAlphaBitmap && nullptr == mask) - { - SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawTransformedBitmap case"); - return false; - } - const Size aSize = rSourceBitmap.GetSize(); cairo_t* cr = getCairoContext(false, bAntiAlias); clipRegion(cr); @@ -1765,10 +1737,7 @@ bool CairoCommon::drawTransformedBitmap(const basegfx::B2DPoint& rNull, const ba cairo_clip(cr); cairo_set_source_surface(cr, source, 0, 0); - if (mask) - cairo_mask_surface(cr, mask, 0, 0); - else - cairo_paint(cr); + cairo_paint(cr); releaseCairoContext(cr, false, extents); diff --git a/vcl/headless/SvpGraphicsBackend.cxx b/vcl/headless/SvpGraphicsBackend.cxx index 14b5d72b0423..c6dad28b31f4 100644 --- a/vcl/headless/SvpGraphicsBackend.cxx +++ b/vcl/headless/SvpGraphicsBackend.cxx @@ -214,10 +214,9 @@ void SvpGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rTR, const SalBitmap& bool SvpGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, - const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) + const SalBitmap& rSourceBitmap, double fAlpha) { - return m_rCairoCommon.drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, pAlphaBitmap, fAlpha, + return m_rCairoCommon.drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, fAlpha, getAntiAlias()); } diff --git a/vcl/inc/headless/CairoCommon.hxx b/vcl/inc/headless/CairoCommon.hxx index 8b8eb9763797..a81100df7b98 100644 --- a/vcl/inc/headless/CairoCommon.hxx +++ b/vcl/inc/headless/CairoCommon.hxx @@ -218,7 +218,7 @@ struct VCL_DLLPUBLIC CairoCommon bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha, bool bAntiAlias); + double fAlpha, bool bAntiAlias); void drawMask(const SalTwoRect& rTR, const SalBitmap& rSalBitmap, Color nMaskColor, bool bAntiAlias); diff --git a/vcl/inc/headless/SvpGraphicsBackend.hxx b/vcl/inc/headless/SvpGraphicsBackend.hxx index b388b8a9245a..8bc8721e55c2 100644 --- a/vcl/inc/headless/SvpGraphicsBackend.hxx +++ b/vcl/inc/headless/SvpGraphicsBackend.hxx @@ -103,7 +103,7 @@ public: bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) override; + double fAlpha) override; bool drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt8 nTransparency) override; diff --git a/vcl/inc/qt5/QtGraphics.hxx b/vcl/inc/qt5/QtGraphics.hxx index 6bd243d8d077..b049134a2a87 100644 --- a/vcl/inc/qt5/QtGraphics.hxx +++ b/vcl/inc/qt5/QtGraphics.hxx @@ -132,7 +132,7 @@ public: bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) override; + double fAlpha) override; bool drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt8 nTransparency) override; diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index 2cbfa4392450..8ef5f4dbd807 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -344,7 +344,7 @@ public: bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) override; + double fAlpha) override; bool drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt8 nTransparency) override; diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx index 64c858fdfb6a..d2e98d540033 100644 --- a/vcl/inc/salgdi.hxx +++ b/vcl/inc/salgdi.hxx @@ -363,7 +363,6 @@ public: const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha, const OutputDevice& rOutDev ); @@ -521,7 +520,6 @@ protected: const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) = 0; /// Returns true if the drawTransformedBitmap() call is fast, and so it should @@ -793,9 +791,9 @@ public: const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) override + double fAlpha) override { - return GetImpl()->drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, pAlphaBitmap, fAlpha); + return GetImpl()->drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, fAlpha); } bool hasFastDrawTransformedBitmap() const override diff --git a/vcl/inc/salgdiimpl.hxx b/vcl/inc/salgdiimpl.hxx index 3f6c20785db6..46cd219e191a 100644 --- a/vcl/inc/salgdiimpl.hxx +++ b/vcl/inc/salgdiimpl.hxx @@ -185,7 +185,6 @@ public: const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) = 0; /// Only currently true for SkiaSalGraphicsImpl diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx index ff9d68e9f7f8..ee14d6e86121 100644 --- a/vcl/inc/skia/gdiimpl.hxx +++ b/vcl/inc/skia/gdiimpl.hxx @@ -150,7 +150,7 @@ public: /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ virtual bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) override; + double fAlpha) override; virtual bool hasFastDrawTransformedBitmap() const override; @@ -251,12 +251,10 @@ protected: void setCanvasScalingAndClipping(); void resetCanvasScalingAndClipping(); static void setCanvasClipRegion(SkCanvas* canvas, const vcl::Region& region); - sk_sp<SkImage> mergeCacheBitmaps(const SkiaSalBitmap& bitmap, const SkiaSalBitmap* alphaBitmap, - const Size& targetSize); + sk_sp<SkImage> mergeCacheBitmaps(const SkiaSalBitmap& bitmap, const Size& targetSize); using DirectImage = SkiaHelper::DirectImage; - static OString makeCachedImageKey(const SkiaSalBitmap& bitmap, const SkiaSalBitmap* alphaBitmap, - const Size& targetSize, DirectImage bitmapType, - DirectImage alphaBitmapType); + static OString makeCachedImageKey(const SkiaSalBitmap& bitmap, const Size& targetSize, + DirectImage bitmapType); // Skia uses floating point coordinates, so when we use integer coordinates, sometimes // rounding results in off-by-one errors (down), especially when drawing using GPU, diff --git a/vcl/inc/win/salbmp.h b/vcl/inc/win/salbmp.h index a6786cb9c649..200051bf64f1 100644 --- a/vcl/inc/win/salbmp.h +++ b/vcl/inc/win/salbmp.h @@ -50,7 +50,7 @@ public: void* ImplGethDIB() const { return mpDIB; } HBITMAP ImplGethDDB() const { return mhDDB; } - std::shared_ptr< Gdiplus::Bitmap > ImplGetGdiPlusBitmap(const WinSalBitmap* pAlphaSource = nullptr) const; + std::shared_ptr< Gdiplus::Bitmap > ImplGetGdiPlusBitmap() const; static void ImplCreateDIB( const Size& rSize, vcl::PixelFormat ePixelFormat, const BitmapPalette& rPal, void*& rpDIB, sal_Int32 &rnDIBSize ); diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index 8904b8627ee5..ee862664fdb5 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -126,7 +126,6 @@ public: const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) override; virtual bool hasFastDrawTransformedBitmap() const override; diff --git a/vcl/qa/cppunit/BackendTest.cxx b/vcl/qa/cppunit/BackendTest.cxx index 3fa34f429433..212baaf49cdf 100644 --- a/vcl/qa/cppunit/BackendTest.cxx +++ b/vcl/qa/cppunit/BackendTest.cxx @@ -653,12 +653,11 @@ public: for (int j = 0; j < 8; ++j) pWriteAccess->SetPixel(j, i, COL_BLACK); } - BitmapEx aBitmapEx(aBitmap); basegfx::B2DHomMatrix aMatrix; // Draw with no transformation, only alpha change. aMatrix.scale(16, 16); - device->DrawTransformedBitmapEx(aMatrix, aBitmapEx, 0.5); - BitmapEx result(device->GetBitmap(Point(0, 0), Size(16, 16))); + device->DrawTransformedBitmapEx(aMatrix, aBitmap, 0.5); + Bitmap result(device->GetBitmap(Point(0, 0), Size(16, 16))); CPPUNIT_ASSERT_EQUAL(COL_GRAY, result.GetPixelColor(0, 0)); CPPUNIT_ASSERT_EQUAL(COL_WHITE, result.GetPixelColor(15, 15)); // Draw rotated and move to the bottom-left corner. @@ -667,7 +666,7 @@ public: aMatrix.scale(16, 16); aMatrix.rotate(M_PI / 2); aMatrix.translate(8, 8); - device->DrawTransformedBitmapEx(aMatrix, aBitmapEx, 0.5); + device->DrawTransformedBitmapEx(aMatrix, aBitmap, 0.5); result = device->GetBitmap(Point(0, 0), Size(16, 16)); CPPUNIT_ASSERT_EQUAL(COL_WHITE, result.GetPixelColor(0, 0)); CPPUNIT_ASSERT_EQUAL(COL_GRAY, result.GetPixelColor(0, 15)); @@ -1401,7 +1400,7 @@ public: bitmap.GetSizePixel().Height()); // draw as 10x10 // Draw a blue bitmap to the device. The bug was that there was no alpha, but OutputDevice::DrawTransformBitmapExDirect() // supplied a fully opaque alpha done with Erase() on the alpha bitmap, and Skia backend didn't handle such alpha correctly. - device->DrawTransformedBitmapEx(matrix, BitmapEx(bitmap)); + device->DrawTransformedBitmapEx(matrix, bitmap); exportDevice(u"tdf136171.png"_ustr, device); // The whole virtual device content now should be blue. CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(0, 0))); diff --git a/vcl/qa/cppunit/outdev.cxx b/vcl/qa/cppunit/outdev.cxx index 040f4d91231a..a1af25f17805 100644 --- a/vcl/qa/cppunit/outdev.cxx +++ b/vcl/qa/cppunit/outdev.cxx @@ -356,7 +356,6 @@ CPPUNIT_TEST_FIXTURE(VclOutdevTest, testDrawTransformedBitmapEx) } } } - BitmapEx aBitmapEx(aBitmap); basegfx::B2DHomMatrix aMatrix; aMatrix.scale(8, 8); // Rotate 90 degrees clockwise, so the black part goes to the top right. @@ -365,7 +364,7 @@ CPPUNIT_TEST_FIXTURE(VclOutdevTest, testDrawTransformedBitmapEx) aMtf.Record(pVDev.get()); // Draw the rotated bitmap on the vdev. - pVDev->DrawTransformedBitmapEx(aMatrix, aBitmapEx); + pVDev->DrawTransformedBitmapEx(aMatrix, aBitmap); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aMtf.GetActionSize()); MetaAction* pAction = aMtf.GetAction(0); CPPUNIT_ASSERT_EQUAL(MetaActionType::BMPEXSCALE, pAction->GetType()); @@ -420,7 +419,6 @@ CPPUNIT_TEST_FIXTURE(VclOutdevTest, testDrawTransformedBitmapExFlip) } } } - BitmapEx aBitmapEx(aBitmap); basegfx::B2DHomMatrix aMatrix; // Negative y scale: bitmap should be upside down, so the black part goes to the bottom left. aMatrix.scale(8, -8); @@ -430,7 +428,7 @@ CPPUNIT_TEST_FIXTURE(VclOutdevTest, testDrawTransformedBitmapExFlip) aMtf.Record(pVDev.get()); // Draw the scaled and rotated bitmap on the vdev. - pVDev->DrawTransformedBitmapEx(aMatrix, aBitmapEx); + pVDev->DrawTransformedBitmapEx(aMatrix, aBitmap); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aMtf.GetActionSize()); MetaAction* pAction = aMtf.GetAction(0); CPPUNIT_ASSERT_EQUAL(MetaActionType::BMPEXSCALE, pAction->GetType()); diff --git a/vcl/qa/cppunit/skia/skia.cxx b/vcl/qa/cppunit/skia/skia.cxx index 8768699d3f70..1d1ec471b91d 100644 --- a/vcl/qa/cppunit/skia/skia.cxx +++ b/vcl/qa/cppunit/skia/skia.cxx @@ -149,7 +149,7 @@ void SkiaTest::testDrawShaders() basegfx::B2DHomMatrix matrix; matrix.scale(10, 10); matrix.rotate(M_PI / 4); - device->DrawTransformedBitmapEx(matrix, BitmapEx(bitmap, alpha)); + device->DrawTransformedBitmapEx(matrix, Bitmap(bitmap, alpha)); //savePNG("/tmp/a3.png", device); CPPUNIT_ASSERT_EQUAL(resultRed, device->GetPixel(Point(0, 1))); CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(1, 0))); diff --git a/vcl/qt5/QtGraphics_GDI.cxx b/vcl/qt5/QtGraphics_GDI.cxx index 06a2ad33dce6..54592258ee64 100644 --- a/vcl/qt5/QtGraphics_GDI.cxx +++ b/vcl/qt5/QtGraphics_GDI.cxx @@ -559,19 +559,6 @@ void QtGraphicsBackend::invert(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/, { } -static QImage getAlphaImage(const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap) -{ - assert(rSourceBitmap.GetSize() == rAlphaBitmap.GetSize()); - assert(rAlphaBitmap.GetBitCount() == 8 || rAlphaBitmap.GetBitCount() == 1); - - QImage aAlphaMask = *static_cast<const QtBitmap*>(&rAlphaBitmap)->GetQImage(); - - const QImage* pBitmap = static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage(); - QImage aImage = pBitmap->convertToFormat(Qt_DefaultFormat32); - aImage.setAlphaChannel(aAlphaMask); - return aImage; -} - void QtGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSourceBitmap) { drawBitmap(rPosAry, rSourceBitmap); @@ -580,14 +567,9 @@ void QtGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitm bool QtGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, - const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) + const SalBitmap& rSourceBitmap, double fAlpha) { - QImage aImage; - if (!pAlphaBitmap) - aImage = *static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage(); - else - aImage = getAlphaImage(rSourceBitmap, *pAlphaBitmap); + QImage aImage = *static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage(); const basegfx::B2DVector aXRel = rX - rNull; const basegfx::B2DVector aYRel = rY - rNull; diff --git a/vcl/quartz/AquaGraphicsBackend.cxx b/vcl/quartz/AquaGraphicsBackend.cxx index 4f0ffc6c130e..7aaa9cddd63f 100644 --- a/vcl/quartz/AquaGraphicsBackend.cxx +++ b/vcl/quartz/AquaGraphicsBackend.cxx @@ -1216,8 +1216,7 @@ void AquaGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBi bool AquaGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, - const SalBitmap& rSrcBitmap, - const SalBitmap* pAlphaBmp, double fAlpha) + const SalBitmap& rSrcBitmap, double fAlpha) { if (!mrShared.checkContext()) return true; @@ -1226,14 +1225,9 @@ bool AquaGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull, return false; // get the Quartz image - CGImageRef xImage = nullptr; const Size aSize = rSrcBitmap.GetSize(); - - if (!pAlphaBmp) - xImage = rSrcBitmap.CreateCroppedImage(0, 0, int(aSize.Width()), int(aSize.Height())); - else - xImage - = rSrcBitmap.CreateWithMask(*pAlphaBmp, 0, 0, int(aSize.Width()), int(aSize.Height())); + CGImageRef xImage + = rSrcBitmap.CreateCroppedImage(0, 0, int(aSize.Width()), int(aSize.Height())); if (!xImage) return false; diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index f123237c9b3d..629ab7552588 100644 --- a/vcl/skia/gdiimpl.cxx +++ b/vcl/skia/gdiimpl.cxx @@ -1532,17 +1532,11 @@ void SkiaSalGraphicsImpl::invert(sal_uInt32 nPoints, const Point* pPointArray, S // with the given target size. Result will be possibly cached, unless disabled. // Especially in raster mode scaling and alpha blending may be expensive if done repeatedly. sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitmap, - const SkiaSalBitmap* alphaBitmap, const Size& targetSize) { - if (alphaBitmap) - assert(bitmap.GetSize() == alphaBitmap->GetSize()); - if (targetSize.IsEmpty()) return {}; - if (alphaBitmap && alphaBitmap->IsFullyOpaqueAsAlpha()) - alphaBitmap = nullptr; // the alpha can be ignored - if (bitmap.PreferSkShader() && (!alphaBitmap || alphaBitmap->PreferSkShader())) + if (bitmap.PreferSkShader()) return {}; // If the bitmap has SkImage that matches the required size, try to use it, even @@ -1551,48 +1545,18 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma // scale, changing GetImageKey() in the process so we'd have to re-cache, and then we'd need // to scale again in this function. bool bitmapReady = false; - bool alphaBitmapReady = false; if (const sk_sp<SkImage>& image = bitmap.GetSkImage(DirectImage::Yes)) { assert(!bitmap.PreferSkShader()); if (imageSize(image) == targetSize) bitmapReady = true; } - // If the image usable and there's no alpha, then it matches exactly what's wanted. - if (bitmapReady && !alphaBitmap) + // If the image usable, then it matches exactly what's wanted. + if (bitmapReady) return bitmap.GetSkImage(DirectImage::Yes); - if (alphaBitmap) - { - if (!alphaBitmap->GetAlphaSkImage(DirectImage::Yes) - && alphaBitmap->GetSkImage(DirectImage::Yes) - && imageSize(alphaBitmap->GetSkImage(DirectImage::Yes)) == targetSize) - { - // There's a usable non-alpha image, try to convert it to alpha. - assert(!alphaBitmap->PreferSkShader()); - const_cast<SkiaSalBitmap*>(alphaBitmap)->TryDirectConvertToAlphaNoScaling(); - } - if (const sk_sp<SkImage>& image = alphaBitmap->GetAlphaSkImage(DirectImage::Yes)) - { - assert(!alphaBitmap->PreferSkShader()); - if (imageSize(image) == targetSize) - alphaBitmapReady = true; - } - } - - if (bitmapReady && (!alphaBitmap || alphaBitmapReady)) - { - // Try to find a cached image based on the already existing images. - OString key = makeCachedImageKey(bitmap, alphaBitmap, targetSize, DirectImage::Yes, - DirectImage::Yes); - if (sk_sp<SkImage> image = findCachedImage(key)) - { - assert(imageSize(image) == targetSize); - return image; - } - } // Probably not much point in caching of just doing a copy. - if (alphaBitmap == nullptr && targetSize == bitmap.GetSize()) + if (targetSize == bitmap.GetSize()) return {}; // Image too small to be worth caching if not scaling. if (targetSize == bitmap.GetSize() && targetSize.Width() < 100 && targetSize.Height() < 100) @@ -1616,17 +1580,11 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma // that they are the same size, or that one prefers a shader or doesn't exist // (i.e. avoid two images of different size). bitmapReady = bitmap.GetSkImage(DirectImage::Yes) != nullptr; - alphaBitmapReady = alphaBitmap && alphaBitmap->GetAlphaSkImage(DirectImage::Yes) != nullptr; - if (bitmapReady && alphaBitmap && !alphaBitmapReady && !alphaBitmap->PreferSkShader()) - bitmapReady = false; - if (alphaBitmapReady && !bitmapReady && bitmap.PreferSkShader()) - alphaBitmapReady = false; DirectImage bitmapType = bitmapReady ? DirectImage::Yes : DirectImage::No; - DirectImage alphaBitmapType = alphaBitmapReady ? DirectImage::Yes : DirectImage::No; // Try to find a cached result, this time after possible delayed scaling. - OString key = makeCachedImageKey(bitmap, alphaBitmap, targetSize, bitmapType, alphaBitmapType); + OString key = makeCachedImageKey(bitmap, targetSize, bitmapType); if (sk_sp<SkImage> image = findCachedImage(key)) { assert(imageSize(image) == targetSize); @@ -1666,14 +1624,11 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma Size sourceSize; if (bitmapReady) sourceSize = imageSize(bitmap.GetSkImage(DirectImage::Yes)); - else if (alphaBitmapReady) - sourceSize = imageSize(alphaBitmap->GetAlphaSkImage(DirectImage::Yes)); else sourceSize = bitmap.GetSize(); // Generate a new result and cache it. - sk_sp<SkSurface> tmpSurface - = createSkSurface(targetSize, alphaBitmap ? kPremul_SkAlphaType : bitmap.alphaType()); + sk_sp<SkSurface> tmpSurface = createSkSurface(targetSize, bitmap.alphaType()); if (!tmpSurface) return nullptr; SkCanvas* canvas = tmpSurface->getCanvas(); @@ -1690,12 +1645,10 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma if (!isUnitTestRunning()) // unittests want exact pixel values samplingOptions = makeSamplingOptions(matrix, 1); } - if (alphaBitmap != nullptr) + if (bitmap.alphaType() == kPremul_SkAlphaType) { canvas->clear(SK_ColorTRANSPARENT); - paint.setShader(SkShaders::Blend( - SkBlendMode::kDstIn, bitmap.GetSkShader(samplingOptions, bitmapType), - alphaBitmap->GetAlphaSkShader(samplingOptions, alphaBitmapType))); + paint.setShader(bitmap.GetSkShader(samplingOptions, bitmapType)); canvas->drawPaint(paint); } else if (bitmap.PreferSkShader()) @@ -1715,15 +1668,11 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma return image; } -OString SkiaSalGraphicsImpl::makeCachedImageKey(const SkiaSalBitmap& bitmap, - const SkiaSalBitmap* alphaBitmap, - const Size& targetSize, DirectImage bitmapType, - DirectImage alphaBitmapType) +OString SkiaSalGraphicsImpl::makeCachedImageKey(const SkiaSalBitmap& bitmap, const Size& targetSize, + DirectImage bitmapType) { OString key = OString::number(targetSize.Width()) + "x" + OString::number(targetSize.Height()) + "_" + bitmap.GetImageKey(bitmapType); - if (alphaBitmap) - key += "_" + alphaBitmap->GetAlphaImageKey(alphaBitmapType); return key; } @@ -1745,7 +1694,7 @@ void SkiaSalGraphicsImpl::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBi imagePosAry.mnSrcHeight = imagePosAry.mnDestHeight; imageSize = Size(imagePosAry.mnSrcWidth, imagePosAry.mnSrcHeight); } - sk_sp<SkImage> image = mergeCacheBitmaps(rSkiaSourceBitmap, nullptr, imageSize * mScaling); + sk_sp<SkImage> image = mergeCacheBitmaps(rSkiaSourceBitmap, imageSize * mScaling); if (image) drawImage(imagePosAry, image, mScaling); else @@ -1769,7 +1718,7 @@ void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SkiaSalBit imagePosAry.mnSrcHeight = imagePosAry.mnDestHeight; imageSize = Size(imagePosAry.mnSrcWidth, imagePosAry.mnSrcHeight); } - sk_sp<SkImage> image = mergeCacheBitmaps(bitmap, nullptr, imageSize * mScaling); + sk_sp<SkImage> image = mergeCacheBitmaps(bitmap, imageSize * mScaling); if (image) drawImage(imagePosAry, image, mScaling, blendMode); else if (bitmap.PreferSkShader()) @@ -1880,17 +1829,11 @@ bool matrixNeedsHighQuality(const SkMatrix& matrix) { return ::matrixNeedsHighQu bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, - const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) + const SalBitmap& rSourceBitmap, double fAlpha) { assert(dynamic_cast<const SkiaSalBitmap*>(&rSourceBitmap)); - assert(!pAlphaBitmap || dynamic_cast<const SkiaSalBitmap*>(pAlphaBitmap)); const SkiaSalBitmap& rSkiaBitmap = static_cast<const SkiaSalBitmap&>(rSourceBitmap); - const SkiaSalBitmap* pSkiaAlphaBitmap = static_cast<const SkiaSalBitmap*>(pAlphaBitmap); - - if (pSkiaAlphaBitmap && pSkiaAlphaBitmap->IsFullyOpaqueAsAlpha()) - pSkiaAlphaBitmap = nullptr; // the alpha can be ignored // Setup the image transformation, // using the rNull, rX, rY points as destinations for the (0,0), (Width,0), (0,Height) source points. @@ -1909,8 +1852,7 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, // Pass size * mScaling to mergeCacheBitmaps() so that it prepares the size that will be needed // after the mScaling-scaling matrix, but otherwise calculate everything else using the VCL coordinates. Size imageSize(round(aXRel.getLength()), round(aYRel.getLength())); - sk_sp<SkImage> imageToDraw - = mergeCacheBitmaps(rSkiaBitmap, pSkiaAlphaBitmap, imageSize * mScaling); + sk_sp<SkImage> imageToDraw = mergeCacheBitmaps(rSkiaBitmap, imageSize * mScaling); if (imageToDraw) { SkMatrix matrix; @@ -1968,19 +1910,7 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, SkSamplingOptions samplingOptions; if (matrixNeedsHighQuality(matrix) || (mScaling != 1 && !isUnitTestRunning())) samplingOptions = makeSamplingOptions(matrix, mScaling); - if (pSkiaAlphaBitmap) - { - SkPaint paint = makeBitmapPaint(); - paint.setShader(SkShaders::Blend(SkBlendMode::kDstIn, - rSkiaBitmap.GetSkShader(samplingOptions), - pSkiaAlphaBitmap->GetAlphaSkShader(samplingOptions))); - if (fAlpha != 1.0) - paint.setShader( - SkShaders::Blend(SkBlendMode::kDstIn, paint.refShader(), - SkShaders::Color(SkColorSetARGB(fAlpha * 255, 0, 0, 0)))); - canvas->drawRect(SkRect::MakeWH(aSize.Width(), aSize.Height()), paint); - } - else if (rSkiaBitmap.PreferSkShader() || fAlpha != 1.0) + if (rSkiaBitmap.PreferSkShader() || fAlpha != 1.0) { SkPaint paint = makeBitmapPaint(); paint.setShader(rSkiaBitmap.GetSkShader(samplingOptions)); @@ -1993,7 +1923,8 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, else { SkPaint paint = makeBitmapPaint(); - canvas->drawImage(rSkiaBitmap.GetSkImage(), 0, 0, samplingOptions, &paint); + paint.setShader(rSkiaBitmap.GetSkShader(samplingOptions)); + canvas->drawRect(SkRect::MakeWH(aSize.Width(), aSize.Height()), paint); } } postDraw(); diff --git a/vcl/source/bitmap/bitmap.cxx b/vcl/source/bitmap/bitmap.cxx index a3e8dad48405..bf82cbf486f3 100644 --- a/vcl/source/bitmap/bitmap.cxx +++ b/vcl/source/bitmap/bitmap.cxx @@ -19,6 +19,7 @@ #include <config_features.h> +#include <rtl/math.hxx> #include <sal/log.hxx> #include <osl/diagnose.h> #include <tools/helpers.hxx> @@ -2719,4 +2720,192 @@ tools::Polygon Bitmap::GetContour( bool bContourEdgeDetect, return aRetPoly; } +static Bitmap impTransformBitmap( + const Bitmap& rSource, + const Size& rDestinationSize, + const basegfx::B2DHomMatrix& rTransform, + bool bSmooth) +{ + Bitmap aDestination(rDestinationSize, rSource.getPixelFormat()); + BitmapScopedWriteAccess xWrite(aDestination); + + if(xWrite) + { + BitmapScopedReadAccess xRead(rSource); + + if (xRead) + { + const Size aDestinationSizePixel(aDestination.GetSizePixel()); + + // tdf#157795 set color to black outside of bitmap bounds + // Due to commit 81994cb2b8b32453a92bcb011830fcb884f22ff3, + // transparent areas are now black instead of white. + // tdf#160831 only set outside color to black for alpha masks + // The outside color still needs to be white for the content + // so only apply the fix for tdf#157795 to the alpha mask. + const BitmapColor aOutside(ColorAlpha, 0xff, 0xff, 0xff, 0x00); + + for(tools::Long y(0); y < aDestinationSizePixel.getHeight(); y++) + { + Scanline pScanline = xWrite->GetScanline( y ); + for(tools::Long x(0); x < aDestinationSizePixel.getWidth(); x++) + { + const basegfx::B2DPoint aSourceCoor(rTransform * basegfx::B2DPoint(x, y)); + + if(bSmooth) + { + xWrite->SetPixelOnData( + pScanline, + x, + xRead->GetInterpolatedColorWithFallback( + aSourceCoor.getY(), + aSourceCoor.getX(), + aOutside)); + } + else + { + // this version does the correct <= 0.0 checks, so no need + // to do the static_cast< sal_Int32 > self and make an error + xWrite->SetPixelOnData( + pScanline, + x, + xRead->GetColorWithFallback( + aSourceCoor.getY(), + aSourceCoor.getX(), + aOutside)); + } + } + } + } + } + xWrite.reset(); + + rSource.AdaptBitCount(aDestination); + + return aDestination; +} + +/// Decides if rTransformation needs smoothing or not (e.g. 180 deg rotation doesn't need it). +static bool implTransformNeedsSmooth(const basegfx::B2DHomMatrix& rTransformation) +{ + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + rTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + if (aScale != basegfx::B2DVector(1, 1)) + { + return true; + } + + fRotate = fmod( fRotate, 2 * M_PI ); + if (fRotate < 0) + { + fRotate += 2 * M_PI; + } + if (!rtl::math::approxEqual(fRotate, 0) + && !rtl::math::approxEqual(fRotate, M_PI_2) + && !rtl::math::approxEqual(fRotate, M_PI) + && !rtl::math::approxEqual(fRotate, 3 * M_PI_2)) + { + return true; + } + + if (!rtl::math::approxEqual(fShearX, 0)) + { + return true; + } + + return false; +} + +Bitmap Bitmap::TransformBitmap( + double fWidth, + double fHeight, + const basegfx::B2DHomMatrix& rTransformation) const +{ + if(fWidth <= 1 || fHeight <= 1) + return Bitmap(); + + // force destination to 24 bit, we want to smooth output + const Size aDestinationSize(basegfx::fround<tools::Long>(fWidth), basegfx::fround<tools::Long>(fHeight)); + bool bSmooth = implTransformNeedsSmooth(rTransformation); + const Bitmap aDestination(impTransformBitmap(*this, aDestinationSize, rTransformation, bSmooth)); + + return aDestination; +} + +Bitmap Bitmap::getTransformed( + const basegfx::B2DHomMatrix& rTransformation, + const basegfx::B2DRange& rVisibleRange, + double fMaximumArea) const +{ + if (IsEmpty()) + return Bitmap(); + + const sal_uInt32 nSourceWidth(GetSizePixel().Width()); + const sal_uInt32 nSourceHeight(GetSizePixel().Height()); + + if (!nSourceWidth || !nSourceHeight) + return Bitmap(); + + // Get aOutlineRange + basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0); + + aOutlineRange.transform(rTransformation); + + // create visible range from it by moving from relative to absolute + basegfx::B2DRange aVisibleRange(rVisibleRange); + + aVisibleRange.transform( + basegfx::utils::createScaleTranslateB2DHomMatrix( + aOutlineRange.getRange(), + aOutlineRange.getMinimum())); + + // get target size (which is visible range's size) + double fWidth(aVisibleRange.getWidth()); + double fHeight(aVisibleRange.getHeight()); + + if (fWidth < 1.0 || fHeight < 1.0) + return Bitmap(); + + // test if discrete size (pixel) maybe too big and limit it + const double fArea(fWidth * fHeight); + const bool bNeedToReduce(basegfx::fTools::more(fArea, fMaximumArea)); + double fReduceFactor(1.0); + + if(bNeedToReduce) + { + fReduceFactor = sqrt(fMaximumArea / fArea); + fWidth *= fReduceFactor; + fHeight *= fReduceFactor; + } + + // Build complete transform from source pixels to target pixels. + // Start by scaling from source pixel size to unit coordinates + basegfx::B2DHomMatrix aTransform( + basegfx::utils::createScaleB2DHomMatrix( + 1.0 / nSourceWidth, + 1.0 / nSourceHeight)); + + // multiply with given transform which leads from unit coordinates inside + // aOutlineRange + aTransform = rTransformation * aTransform; + + // subtract top-left of absolute VisibleRange + aTransform.translate( + -aVisibleRange.getMinX(), + -aVisibleRange.getMinY()); + + // scale to target pixels (if needed) + if(bNeedToReduce) + { + aTransform.scale(fReduceFactor, fReduceFactor); + } + + // invert to get transformation from target pixel coordinates to source pixels + aTransform.invert(); + + // create bitmap using source, destination and linear back-transformation + return TransformBitmap(fWidth, fHeight, aTransform); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/gdi/print.cxx b/vcl/source/gdi/print.cxx index eb918c2f2602..c5d63daafa20 100644 --- a/vcl/source/gdi/print.cxx +++ b/vcl/source/gdi/print.cxx @@ -171,7 +171,7 @@ void Printer::ImplPrintTransparent( const Bitmap& rBmp, bool Printer::DrawTransformBitmapExDirect( const basegfx::B2DHomMatrix& /*aFullTransform*/, - const BitmapEx& /*rBitmapEx*/, + const Bitmap& /*rBitmap*/, double /*fAlpha*/) { // printers can't draw bitmaps directly diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx index 584143b2b6e4..63f35c52f729 100644 --- a/vcl/source/gdi/salgdilayout.cxx +++ b/vcl/source/gdi/salgdilayout.cxx @@ -90,7 +90,6 @@ bool SalGraphics::drawTransformedBitmap( const basegfx::B2DPoint& /* rX */, const basegfx::B2DPoint& /* rY */, const SalBitmap& /* rSourceBitmap */, - const SalBitmap* /* pAlphaBitmap */, double /* fAlpha */) { // here direct support for transformed bitmaps can be implemented @@ -841,7 +840,6 @@ bool SalGraphics::DrawTransformedBitmap( const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha, const OutputDevice& rOutDev) { @@ -859,11 +857,11 @@ bool SalGraphics::DrawTransformedBitmap( basegfx::B2DPoint aX = aTranslateToMirroredBounds * rX; basegfx::B2DPoint aY = aTranslateToMirroredBounds * rY; - return drawTransformedBitmap(aNull, aX, aY, rSourceBitmap, pAlphaBitmap, fAlpha); + return drawTransformedBitmap(aNull, aX, aY, rSourceBitmap, fAlpha); } } - return drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, pAlphaBitmap, fAlpha); + return drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, fAlpha); } bool SalGraphics::HasFastDrawTransformedBitmap() const diff --git a/vcl/source/outdev/bitmapex.cxx b/vcl/source/outdev/bitmapex.cxx index 6b7ece22051d..ba355f2a8052 100644 --- a/vcl/source/outdev/bitmapex.cxx +++ b/vcl/source/outdev/bitmapex.cxx @@ -186,7 +186,7 @@ void OutputDevice::DrawDeviceBitmapEx( const Point& rDestPt, const Size& rDestSi bool OutputDevice::DrawTransformBitmapExDirect( const basegfx::B2DHomMatrix& aFullTransform, - const BitmapEx& rBitmapEx, + const Bitmap& rBitmap, double fAlpha) { assert(!is_double_buffered_window()); @@ -195,22 +195,13 @@ bool OutputDevice::DrawTransformBitmapExDirect( const basegfx::B2DPoint aNull(aFullTransform * basegfx::B2DPoint(0.0, 0.0)); const basegfx::B2DPoint aTopX(aFullTransform * basegfx::B2DPoint(1.0, 0.0)); const basegfx::B2DPoint aTopY(aFullTransform * basegfx::B2DPoint(0.0, 1.0)); - SalBitmap* pSalSrcBmp = rBitmapEx.GetBitmap().ImplGetSalBitmap().get(); - AlphaMask aAlphaBitmap; - - if(rBitmapEx.IsAlpha()) - { - aAlphaBitmap = rBitmapEx.GetAlphaMask(); - } - - SalBitmap* pSalAlphaBmp = aAlphaBitmap.GetBitmap().ImplGetSalBitmap().get(); + SalBitmap* pSalSrcBmp = rBitmap.ImplGetSalBitmap().get(); return mpGraphics->DrawTransformedBitmap( aNull, aTopX, aTopY, *pSalSrcBmp, - pSalAlphaBmp, fAlpha, *this); }; @@ -326,21 +317,13 @@ void OutputDevice::DrawTransformedBitmapEx( const basegfx::B2DHomMatrix& rTransformation, const Bitmap& rBitmap, double fAlpha) -{ - DrawTransformedBitmapEx(rTransformation, BitmapEx(rBitmap), fAlpha); -} - -void OutputDevice::DrawTransformedBitmapEx( - const basegfx::B2DHomMatrix& rTransformation, - const BitmapEx& rBitmapEx, - double fAlpha) { assert(!is_double_buffered_window()); if( ImplIsRecordLayout() ) return; - if(rBitmapEx.IsEmpty()) + if(rBitmap.IsEmpty()) return; if( fAlpha == 0.0 ) @@ -378,7 +361,7 @@ void OutputDevice::DrawTransformedBitmapEx( : nullptr); #endif - BitmapEx bitmapEx = rBitmapEx; + Bitmap bitmap = rBitmap; const bool bInvert(RasterOp::Invert == meRasterOp); const bool bBitmapChangedColor(mnDrawMode & (DrawModeFlags::BlackBitmap | DrawModeFlags::WhiteBitmap | DrawModeFlags::GrayBitmap )); @@ -393,7 +376,7 @@ void OutputDevice::DrawTransformedBitmapEx( { if(bTryDirectPaint) { - if(DrawTransformBitmapExDirect(aFullTransform, bitmapEx, fAlpha)) + if(DrawTransformBitmapExDirect(aFullTransform, bitmap, fAlpha)) { // we are done return; @@ -401,15 +384,15 @@ void OutputDevice::DrawTransformedBitmapEx( } // Apply the alpha manually. sal_uInt8 nTransparency( static_cast<sal_uInt8>( ::basegfx::fround( 255.0*(1.0 - fAlpha) + .5) ) ); - AlphaMask aAlpha( bitmapEx.GetSizePixel(), &nTransparency ); - if( bitmapEx.IsAlpha()) - aAlpha.BlendWith( bitmapEx.GetAlphaMask()); - bitmapEx = BitmapEx( bitmapEx.GetBitmap(), aAlpha ); + AlphaMask aAlpha( bitmap.GetSizePixel(), &nTransparency ); + if( bitmap.HasAlpha()) + aAlpha.BlendWith( bitmap.CreateAlphaMask()); + bitmap = Bitmap( bitmap.CreateColorBitmap(), aAlpha ); } // If the backend's implementation is known to not need any optimizations here, pass to it directly. // With most backends it's more performant to try to simplify to DrawBitmapEx() first. - if(bTryDirectPaint && mpGraphics->HasFastDrawTransformedBitmap() && DrawTransformBitmapExDirect(aFullTransform, bitmapEx)) + if(bTryDirectPaint && mpGraphics->HasFastDrawTransformedBitmap() && DrawTransformBitmapExDirect(aFullTransform, bitmap)) return; // decompose matrix to check rotation and shear @@ -437,7 +420,7 @@ void OutputDevice::DrawTransformedBitmapEx( EnableMapMode(false); } - DrawBitmapEx(aDestPt, aDestSize, Bitmap(bitmapEx)); + DrawBitmapEx(aDestPt, aDestSize, bitmap); if (!bMetafile && comphelper::LibreOfficeKit::isActive() && GetMapMode().GetMapUnit() != MapUnit::MapPixel) { EnableMapMode(); @@ -447,7 +430,7 @@ void OutputDevice::DrawTransformedBitmapEx( } // Try the backend's implementation before resorting to the slower fallback here. - if(bTryDirectPaint && DrawTransformBitmapExDirect(aFullTransform, bitmapEx)) + if(bTryDirectPaint && DrawTransformBitmapExDirect(aFullTransform, bitmap)) return; // take the fallback when no rotate and shear, but mirror (else we would have done this above) @@ -461,7 +444,7 @@ void OutputDevice::DrawTransformedBitmapEx( basegfx::fround<tools::Long>(aScale.getX() + aTranslate.getX()) - aDestPt.X(), basegfx::fround<tools::Long>(aScale.getY() + aTranslate.getY()) - aDestPt.Y()); - DrawBitmapEx(aDestPt, aDestSize, Bitmap(bitmapEx)); + DrawBitmapEx(aDestPt, aDestSize, bitmap); return; } @@ -476,8 +459,8 @@ void OutputDevice::DrawTransformedBitmapEx( // by using a fixed minimum (allow at least, but no need to utilize) for good smoothing and an area // dependent of original size for good quality when e.g. rotated/sheared. Still, limit to a maximum // to avoid crashes/resource problems (ca. 1500x3000 here) - const Size& rOriginalSizePixel(bitmapEx.GetSizePixel()); - const double fOrigArea(rOriginalSizePixel.Width() * rOriginalSizePixel.Height() * 0.5); + const Size aOriginalSizePixel(bitmap.GetSizePixel()); + const double fOrigArea(aOriginalSizePixel.Width() * aOriginalSizePixel.Height() * 0.5); const double fOrigAreaScaled(fOrigArea * 1.44); double fMaximumArea(std::clamp(fOrigAreaScaled, 1000000.0, 4500000.0)); @@ -490,20 +473,20 @@ void OutputDevice::DrawTransformedBitmapEx( if(aVisibleRange.isEmpty()) return; - BitmapEx aTransformed(bitmapEx); + Bitmap aTransformed(bitmap); // #122923# when the result needs an alpha channel due to being rotated or sheared // and thus uncovering areas, add these channels so that the own transformer (used // in getTransformed) also creates a transformed alpha channel - if(!aTransformed.IsAlpha() && (bSheared || bRotated)) + if(!aTransformed.HasAlpha() && (bSheared || bRotated)) { // parts will be uncovered, extend aTransformed with a mask bitmap - const Bitmap aContent(aTransformed.GetBitmap()); + const Bitmap aContent(aTransformed.CreateColorBitmap()); AlphaMask aMaskBmp(aContent.GetSizePixel()); aMaskBmp.Erase(0); - aTransformed = BitmapEx(aContent, aMaskBmp); + aTransformed = Bitmap(aContent, aMaskBmp); } basegfx::B2DVector aFullScale, aFullTranslate; @@ -511,9 +494,9 @@ void OutputDevice::DrawTransformedBitmapEx( aFullTransform.decompose(aFullScale, aFullTranslate, fFullRotate, fFullShearX); double fSourceRatio = 1.0; - if (rOriginalSizePixel.getHeight() != 0) + if (aOriginalSizePixel.getHeight() != 0) { - fSourceRatio = rOriginalSizePixel.getWidth() / rOriginalSizePixel.getHeight(); + fSourceRatio = aOriginalSizePixel.getWidth() / aOriginalSizePixel.getHeight(); } double fTargetRatio = 1.0; if (aFullScale.getY() != 0) @@ -558,7 +541,7 @@ void OutputDevice::DrawTransformedBitmapEx( basegfx::fround<tools::Long>(aVisibleRange.getMaxX()) - aDestPt.X(), basegfx::fround<tools::Long>(aVisibleRange.getMaxY()) - aDestPt.Y()); - DrawBitmapEx(aDestPt, aDestSize, Bitmap(aTransformed)); + DrawBitmapEx(aDestPt, aDestSize, aTransformed); } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx b/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx index c80caf4c23e1..28b346c2c2e4 100644 --- a/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx +++ b/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx @@ -204,10 +204,9 @@ bool X11CairoSalGraphicsImpl::drawPolyPolygonBezier(sal_uInt32, const sal_uInt32 bool X11CairoSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, - const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) + const SalBitmap& rSourceBitmap, double fAlpha) { - return mrCairoCommon.drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, pAlphaBitmap, fAlpha, + return mrCairoCommon.drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, fAlpha, getAntiAlias()); } diff --git a/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx b/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx index b95d2c90b684..e4b78121ae2d 100644 --- a/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx +++ b/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx @@ -156,7 +156,7 @@ public: /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) override; + double fAlpha) override; bool supportsOperation(OutDevSupportType eType) const override; }; diff --git a/vcl/win/gdi/gdiimpl.cxx b/vcl/win/gdi/gdiimpl.cxx index b1a412093815..440948cfbc87 100644 --- a/vcl/win/gdi/gdiimpl.cxx +++ b/vcl/win/gdi/gdiimpl.cxx @@ -2342,18 +2342,15 @@ bool WinSalGraphicsImpl::drawTransformedBitmap( const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) { assert(dynamic_cast<const WinSalBitmap*>(&rSourceBitmap)); - assert(!pAlphaBitmap || dynamic_cast<const WinSalBitmap*>(pAlphaBitmap)); if( fAlpha != 1.0 ) return false; const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSourceBitmap); - const WinSalBitmap* pSalAlpha = static_cast< const WinSalBitmap* >(pAlphaBitmap); - std::shared_ptr< Gdiplus::Bitmap > aARGB(rSalBitmap.ImplGetGdiPlusBitmap(pSalAlpha)); + std::shared_ptr< Gdiplus::Bitmap > aARGB(rSalBitmap.ImplGetGdiPlusBitmap()); if(!aARGB) return false; diff --git a/vcl/win/gdi/gdiimpl.hxx b/vcl/win/gdi/gdiimpl.hxx index 9eb69fe55974..976b6fd0ebba 100644 --- a/vcl/win/gdi/gdiimpl.hxx +++ b/vcl/win/gdi/gdiimpl.hxx @@ -192,7 +192,6 @@ public: const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) override; virtual bool hasFastDrawTransformedBitmap() const override; diff --git a/vcl/win/gdi/salbmp.cxx b/vcl/win/gdi/salbmp.cxx index a5b27e40f674..8c926d5d35fe 100644 --- a/vcl/win/gdi/salbmp.cxx +++ b/vcl/win/gdi/salbmp.cxx @@ -74,14 +74,11 @@ class SystemDependentData_GdiPlusBitmap : public basegfx::SystemDependentData { private: std::shared_ptr<Gdiplus::Bitmap> mpGdiPlusBitmap; - const WinSalBitmap* mpAssociatedAlpha; public: SystemDependentData_GdiPlusBitmap( - const std::shared_ptr<Gdiplus::Bitmap>& rGdiPlusBitmap, - const WinSalBitmap* pAssociatedAlpha); + const std::shared_ptr<Gdiplus::Bitmap>& rGdiPlusBitmap); - const WinSalBitmap* getAssociatedAlpha() const { return mpAssociatedAlpha; } const std::shared_ptr<Gdiplus::Bitmap>& getGdiPlusBitmap() const { return mpGdiPlusBitmap; } virtual sal_Int64 estimateUsageInBytes() const override; @@ -90,13 +87,11 @@ public: } SystemDependentData_GdiPlusBitmap::SystemDependentData_GdiPlusBitmap( - const std::shared_ptr<Gdiplus::Bitmap>& rGdiPlusBitmap, - const WinSalBitmap* pAssociatedAlpha) + const std::shared_ptr<Gdiplus::Bitmap>& rGdiPlusBitmap) : basegfx::SystemDependentData( Application::GetSystemDependentDataManager(), basegfx::SDD_Type::SDDType_GdiPlusBitmap), - mpGdiPlusBitmap(rGdiPlusBitmap), - mpAssociatedAlpha(pAssociatedAlpha) + mpGdiPlusBitmap(rGdiPlusBitmap) { } @@ -151,7 +146,7 @@ sal_Int64 SystemDependentData_GdiPlusBitmap::estimateUsageInBytes() const return nRetval; } -std::shared_ptr< Gdiplus::Bitmap > WinSalBitmap::ImplGetGdiPlusBitmap(const WinSalBitmap* pAlphaSource) const +std::shared_ptr< Gdiplus::Bitmap > WinSalBitmap::ImplGetGdiPlusBitmap() const { std::shared_ptr< Gdiplus::Bitmap > aRetval; @@ -159,20 +154,6 @@ std::shared_ptr< Gdiplus::Bitmap > WinSalBitmap::ImplGetGdiPlusBitmap(const WinS std::shared_ptr<SystemDependentData_GdiPlusBitmap> pSystemDependentData_GdiPlusBitmap( getSystemDependentData<SystemDependentData_GdiPlusBitmap>(basegfx::SDD_Type::SDDType_GdiPlusBitmap)); - if(pSystemDependentData_GdiPlusBitmap) - { - // check data validity - if(pSystemDependentData_GdiPlusBitmap->getAssociatedAlpha() != pAlphaSource - || 0 == maSize.Width() - || 0 == maSize.Height()) - { - // #122350# if associated alpha with which the GDIPlus was constructed has changed - // it is necessary to remove it from buffer, reset reference to it and reconstruct - // data invalid, forget - pSystemDependentData_GdiPlusBitmap.reset(); - } - } - if(pSystemDependentData_GdiPlusBitmap) { // use from buffer @@ -180,24 +161,9 @@ std::shared_ptr< Gdiplus::Bitmap > WinSalBitmap::ImplGetGdiPlusBitmap(const WinS } else if(!maSize.IsEmpty()) { - // create and set data - const WinSalBitmap* pAssociatedAlpha(nullptr); - - if(pAlphaSource) - { - aRetval = const_cast< WinSalBitmap* >(this)->ImplCreateGdiPlusBitmap(*pAlphaSource); - pAssociatedAlpha = pAlphaSource; - } - else - { - aRetval = const_cast< WinSalBitmap* >(this)->ImplCreateGdiPlusBitmap(); - pAssociatedAlpha = nullptr; - } - // add to buffering mechanism addOrReplaceSystemDependentData<SystemDependentData_GdiPlusBitmap>( - aRetval, - pAssociatedAlpha); + aRetval); } return aRetval; diff --git a/vcl/win/gdi/salgdi_gdiplus.cxx b/vcl/win/gdi/salgdi_gdiplus.cxx index 17fa6264247e..5f3e47b108d5 100644 --- a/vcl/win/gdi/salgdi_gdiplus.cxx +++ b/vcl/win/gdi/salgdi_gdiplus.cxx @@ -79,11 +79,10 @@ bool WinSalGraphics::drawTransformedBitmap( const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap, double fAlpha) { return mpImpl->drawTransformedBitmap(rNull, rX, rY, - rSourceBitmap, pAlphaBitmap, fAlpha); + rSourceBitmap, fAlpha); } bool WinSalGraphics::hasFastDrawTransformedBitmap() const