diff options
28 files changed, 177 insertions, 69 deletions
diff --git a/canvas/source/vcl/canvashelper.cxx b/canvas/source/vcl/canvashelper.cxx index 89ee207989c6..bec73b3d336a 100644 --- a/canvas/source/vcl/canvashelper.cxx +++ b/canvas/source/vcl/canvashelper.cxx @@ -723,13 +723,14 @@ namespace vclcanvas // itself serves this purpose return uno::Reference< rendering::XCachedPrimitive >(nullptr); } - else if( !bModulateColors && mpOutDevProvider->getOutDev().HasFastDrawTransformedBitmap()) + else if( mpOutDevProvider->getOutDev().HasFastDrawTransformedBitmap()) { ::basegfx::B2DHomMatrix aSizeTransform; aSizeTransform.scale( aBmpEx.GetSizePixel().Width(), aBmpEx.GetSizePixel().Height() ); aMatrix = aMatrix * aSizeTransform; + const double fAlpha = bModulateColors ? renderState.DeviceColor[3] : 1.0; - mpOutDevProvider->getOutDev().DrawTransformedBitmapEx( aMatrix, aBmpEx ); + mpOutDevProvider->getOutDev().DrawTransformedBitmapEx( aMatrix, aBmpEx, fAlpha ); if( mp2ndOutDevProvider ) { // HACK. Normally, CanvasHelper does not care about diff --git a/canvas/source/vcl/spritehelper.cxx b/canvas/source/vcl/spritehelper.cxx index 31d16032e576..e8d4fa726e10 100644 --- a/canvas/source/vcl/spritehelper.cxx +++ b/canvas/source/vcl/spritehelper.cxx @@ -210,28 +210,7 @@ namespace vclcanvas aMoveTransform.translate( aOutPos.X(), aOutPos.Y() ); aTransform = aMoveTransform * aTransform * aSizeTransform; - if( ::rtl::math::approxEqual(fAlpha, 1.0) ) - { - // no alpha modulation -> just copy to output - rTargetSurface.DrawTransformedBitmapEx( aTransform, *maContent ); - } - else - { - // TODO(P3): Switch to OutputDevice::DrawTransparent() - // here - - // draw semi-transparent - sal_uInt8 nColor( static_cast<sal_uInt8>( ::basegfx::fround( 255.0*(1.0 - fAlpha) + .5) ) ); - AlphaMask aAlpha( maContent->GetSizePixel(), - &nColor ); - - // mask out fully transparent areas - if( maContent->IsTransparent() ) - aAlpha.Replace( maContent->GetMask(), 255 ); - - // alpha-blend to output - rTargetSurface.DrawTransformedBitmapEx( aTransform, BitmapEx( maContent->GetBitmap(), aAlpha ) ); - } + rTargetSurface.DrawTransformedBitmapEx( aTransform, *maContent, fAlpha ); rTargetSurface.Pop(); diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx index 2eb6fd9e882e..a8d77c77b30e 100644 --- a/include/vcl/outdev.hxx +++ b/include/vcl/outdev.hxx @@ -1480,10 +1480,14 @@ public: @param rBitmapEx The BitmapEx to be painted + + @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); + const BitmapEx& rBitmapEx, + double fAlpha = 1.0); /** Return true if DrawTransformedBitmapEx() is fast. @@ -1509,7 +1513,8 @@ protected: */ virtual bool DrawTransformBitmapExDirect( const basegfx::B2DHomMatrix& aFullTransform, - const BitmapEx& rBitmapEx); + const BitmapEx& rBitmapEx, + double fAlpha = 1.0); /** Transform and reduce the area that needs to be drawn of the bitmap and return the new visible range and the maximum area. diff --git a/include/vcl/print.hxx b/include/vcl/print.hxx index 8ddd8bc7fbd3..e787ce40fca8 100644 --- a/include/vcl/print.hxx +++ b/include/vcl/print.hxx @@ -234,7 +234,7 @@ protected: const Point& rSrcPtPixel, const Size& rSrcSizePixel) override; bool DrawTransformBitmapExDirect( const basegfx::B2DHomMatrix& aFullTransform, - const BitmapEx& rBitmapEx) override; + const BitmapEx& rBitmapEx, double fAlpha = 1.0) override; bool TransformAndReduceBitmapExToTargetRange( const basegfx::B2DHomMatrix& aFullTransform, basegfx::B2DRange &aVisibleRange, double &fMaximumArea) override; diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx index 5c713657d755..67f3c9142567 100644 --- a/vcl/headless/svpgdi.cxx +++ b/vcl/headless/svpgdi.cxx @@ -752,7 +752,8 @@ bool SvpSalGraphics::drawTransformedBitmap( const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) + const SalBitmap* pAlphaBitmap, + double fAlpha) { if (pAlphaBitmap && pAlphaBitmap->GetBitCount() != 8 && pAlphaBitmap->GetBitCount() != 1) { @@ -760,6 +761,9 @@ bool SvpSalGraphics::drawTransformedBitmap( return false; } + if( fAlpha != 1.0 ) + return false; + // MM02 try to access buffered BitmapHelper std::shared_ptr<BitmapHelper> aSurface; tryToUseSourceBuffer(rSourceBitmap, aSurface); diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx index a0a20e508d72..e14279978d6d 100644 --- a/vcl/inc/headless/svpgdi.hxx +++ b/vcl/inc/headless/svpgdi.hxx @@ -144,7 +144,8 @@ protected: const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) override; + const SalBitmap* pAlphaBitmap, + double fAlpha) override; virtual bool hasFastDrawTransformedBitmap() const override; virtual bool drawAlphaRect( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt8 nTransparency ) override; diff --git a/vcl/inc/qt5/Qt5Graphics.hxx b/vcl/inc/qt5/Qt5Graphics.hxx index 87ffc938becf..e90731179d53 100644 --- a/vcl/inc/qt5/Qt5Graphics.hxx +++ b/vcl/inc/qt5/Qt5Graphics.hxx @@ -154,7 +154,7 @@ public: bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) override; + const SalBitmap* pAlphaBitmap, double fAlpha) override; virtual bool hasFastDrawTransformedBitmap() const override; virtual bool drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index b3df7550ebf9..421cbffba55b 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -294,7 +294,8 @@ public: const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) override; + const SalBitmap* pAlphaBitmap, + double fAlpha) override; virtual bool hasFastDrawTransformedBitmap() const override; diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx index 44ddf34a50ff..494f03eef5a5 100644 --- a/vcl/inc/salgdi.hxx +++ b/vcl/inc/salgdi.hxx @@ -414,6 +414,7 @@ public: const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, const SalBitmap* pAlphaBitmap, + double fAlpha, const OutputDevice& rOutDev ); bool HasFastDrawTransformedBitmap() const; @@ -574,13 +575,17 @@ protected: const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap ) = 0; - /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ + /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system + + @param fAlpha additional alpha (0 to 1) to apply while drawing + */ virtual bool drawTransformedBitmap( const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) = 0; + const SalBitmap* pAlphaBitmap, + double fAlpha) = 0; /// Used e.g. by canvas to know whether to cache the drawing. virtual bool hasFastDrawTransformedBitmap() const = 0; diff --git a/vcl/inc/salgdiimpl.hxx b/vcl/inc/salgdiimpl.hxx index eb1508dcf7d6..8b310c586e1a 100644 --- a/vcl/inc/salgdiimpl.hxx +++ b/vcl/inc/salgdiimpl.hxx @@ -194,7 +194,8 @@ public: const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) = 0; + const SalBitmap* pAlphaBitmap, + double fAlpha) = 0; /// Used e.g. by canvas to know whether to cache the drawing. virtual bool hasFastDrawTransformedBitmap() const = 0; diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx index 53a9a0ae0978..64707e35d134 100644 --- a/vcl/inc/skia/gdiimpl.hxx +++ b/vcl/inc/skia/gdiimpl.hxx @@ -174,7 +174,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) override; + const SalBitmap* pAlphaBitmap, double fAlpha) override; virtual bool hasFastDrawTransformedBitmap() const override; diff --git a/vcl/inc/unx/genpspgraphics.h b/vcl/inc/unx/genpspgraphics.h index a572a9013c63..d3ff919a9778 100644 --- a/vcl/inc/unx/genpspgraphics.h +++ b/vcl/inc/unx/genpspgraphics.h @@ -189,7 +189,8 @@ public: const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) override; + const SalBitmap* pAlphaBitmap, + double fAlpha) override; virtual bool hasFastDrawTransformedBitmap() const override; virtual bool drawAlphaRect( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt8 nTransparency ) override; diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h index d8e175750813..41e0f57598c8 100644 --- a/vcl/inc/unx/salgdi.h +++ b/vcl/inc/unx/salgdi.h @@ -246,7 +246,8 @@ public: const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) override; + const SalBitmap* pAlphaBitmap, + double fAlpha) override; virtual bool hasFastDrawTransformedBitmap() const override; diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index ca04f2469d66..21f1b46ec016 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -289,7 +289,8 @@ public: const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) override; + 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 56796f8b68c3..018541aa40ab 100644 --- a/vcl/qa/cppunit/BackendTest.cxx +++ b/vcl/qa/cppunit/BackendTest.cxx @@ -465,6 +465,41 @@ public: CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); } + void testDrawTransformedBitmapExAlpha() + { + ScopedVclPtrInstance<VirtualDevice> device; + device->SetOutputSizePixel(Size(16, 16)); + device->SetBackground(Wallpaper(COL_WHITE)); + device->Erase(); + Bitmap aBitmap(Size(16, 16), 24); + { + // Fill the top left quarter with black. + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(COL_WHITE); + for (int i = 0; i < 8; ++i) + 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->GetBitmapEx(Point(0, 0), Size(16, 16)); + CPPUNIT_ASSERT_EQUAL(Color(0x80, 0x80, 0x80), result.GetPixelColor(0, 0)); + CPPUNIT_ASSERT_EQUAL(COL_WHITE, result.GetPixelColor(15, 15)); + // Draw rotated and move to the bottom-left corner. + device->Erase(); + aMatrix.identity(); + aMatrix.scale(16, 16); + aMatrix.rotate(M_PI / 2); + aMatrix.translate(8, 8); + device->DrawTransformedBitmapEx(aMatrix, aBitmapEx, 0.5); + result = device->GetBitmap(Point(0, 0), Size(16, 16)); + CPPUNIT_ASSERT_EQUAL(COL_WHITE, result.GetPixelColor(0, 0)); + CPPUNIT_ASSERT_EQUAL(Color(0x80, 0x80, 0x80), result.GetPixelColor(0, 15)); + } + void testClipRectangle() { vcl::test::OutputDeviceTestClip aOutDevTest; @@ -877,6 +912,7 @@ public: CPPUNIT_TEST(testDrawMask); CPPUNIT_TEST(testDrawBlend); CPPUNIT_TEST(testDrawXor); + CPPUNIT_TEST(testDrawTransformedBitmapExAlpha); CPPUNIT_TEST(testClipRectangle); CPPUNIT_TEST(testClipPolygon); diff --git a/vcl/qt5/Qt5Graphics_GDI.cxx b/vcl/qt5/Qt5Graphics_GDI.cxx index fbcc3d32d0d9..fabed0b3047b 100644 --- a/vcl/qt5/Qt5Graphics_GDI.cxx +++ b/vcl/qt5/Qt5Graphics_GDI.cxx @@ -626,8 +626,10 @@ bool Qt5Graphics::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitmap& rS bool Qt5Graphics::drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) + const SalBitmap* pAlphaBitmap, double fAlpha) { + if (fAlpha != 1.0) + return false; QImage aImage; if (pAlphaBitmap && !getAlphaImage(rSourceBitmap, *pAlphaBitmap, aImage)) return false; diff --git a/vcl/quartz/salgdicommon.cxx b/vcl/quartz/salgdicommon.cxx index b74dbda15360..d82681f1091f 100644 --- a/vcl/quartz/salgdicommon.cxx +++ b/vcl/quartz/salgdicommon.cxx @@ -330,11 +330,14 @@ bool AquaSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR, bool AquaSalGraphics::drawTransformedBitmap( const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, - const SalBitmap& rSrcBitmap, const SalBitmap* pAlphaBmp ) + const SalBitmap& rSrcBitmap, const SalBitmap* pAlphaBmp, double fAlpha ) { if( !CheckContext() ) return true; + if( fAlpha != 1.0 ) + return false; + // get the Quartz image CGImageRef xImage = nullptr; const Size aSize = rSrcBitmap.GetSize(); diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index d8077df48a68..950010183cb1 100644 --- a/vcl/skia/gdiimpl.cxx +++ b/vcl/skia/gdiimpl.cxx @@ -1762,7 +1762,7 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) + const SalBitmap* pAlphaBitmap, double fAlpha) { assert(dynamic_cast<const SkiaSalBitmap*>(&rSourceBitmap)); assert(!pAlphaBitmap || dynamic_cast<const SkiaSalBitmap*>(pAlphaBitmap)); @@ -1787,6 +1787,8 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, // so use mergeCacheBitmaps(), which will cache the result if useful. // It is better to use SkShader if in GPU mode, if the operation is simple or if the temporary // image would be very large. + // The extra fAlpha blending is not cached, with the assumption that it usually gradually changes + // for each invocation. sk_sp<SkImage> imageToDraw = mergeCacheBitmaps( rSkiaBitmap, pSkiaAlphaBitmap, Size(round(aXRel.getLength()), round(aYRel.getLength()))); if (imageToDraw) @@ -1808,7 +1810,15 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, SkPaint paint; if (!matrix.isTranslate()) paint.setFilterQuality(kHigh_SkFilterQuality); - canvas->drawImage(imageToDraw, 0, 0, &paint); + if (fAlpha == 1.0) + canvas->drawImage(imageToDraw, 0, 0, &paint); + else + { + paint.setShader( + SkShaders::Blend(SkBlendMode::kDstIn, imageToDraw->makeShader(), + SkShaders::Color(SkColorSetARGB(fAlpha * 255, 0, 0, 0)))); + canvas->drawRect(SkRect::MakeWH(imageToDraw->width(), imageToDraw->height()), paint); + } } else { @@ -1831,11 +1841,19 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, paint.setShader(SkShaders::Blend(SkBlendMode::kDstOut, // VCL alpha is one-minus-alpha. rSkiaBitmap.GetSkShader(), pSkiaAlphaBitmap->GetAlphaSkShader())); + 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()) + else if (rSkiaBitmap.PreferSkShader() || fAlpha != 1.0) { paint.setShader(rSkiaBitmap.GetSkShader()); + 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 diff --git a/vcl/source/gdi/print.cxx b/vcl/source/gdi/print.cxx index 41548a91c60c..55c0bbdeaac8 100644 --- a/vcl/source/gdi/print.cxx +++ b/vcl/source/gdi/print.cxx @@ -275,7 +275,8 @@ void Printer::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask, bool Printer::DrawTransformBitmapExDirect( const basegfx::B2DHomMatrix& /*aFullTransform*/, - const BitmapEx& /*rBitmapEx*/) + const BitmapEx& /*rBitmapEx*/, + double /*fAlpha*/) { // printers can't draw bitmaps directly return false; diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx index d019b93e816b..adf26d97d9ac 100644 --- a/vcl/source/gdi/salgdilayout.cxx +++ b/vcl/source/gdi/salgdilayout.cxx @@ -28,6 +28,7 @@ #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> #include <FileDefinitionWidgetDraw.hxx> +#include <rtl/math.hxx> // The only common SalFrame method @@ -87,7 +88,8 @@ bool SalGraphics::drawTransformedBitmap( const basegfx::B2DPoint& /* rX */, const basegfx::B2DPoint& /* rY */, const SalBitmap& /* rSourceBitmap */, - const SalBitmap* /* pAlphaBitmap */) + const SalBitmap* /* pAlphaBitmap */, + double /* fAlpha */) { // here direct support for transformed bitmaps can be implemented return false; @@ -836,6 +838,7 @@ bool SalGraphics::DrawTransformedBitmap( const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, const SalBitmap* pAlphaBitmap, + double fAlpha, const OutputDevice& rOutDev) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) @@ -852,11 +855,11 @@ bool SalGraphics::DrawTransformedBitmap( basegfx::B2DPoint aX = aTranslateToMirroredBounds * rX; basegfx::B2DPoint aY = aTranslateToMirroredBounds * rY; - return drawTransformedBitmap(aNull, aX, aY, rSourceBitmap, pAlphaBitmap); + return drawTransformedBitmap(aNull, aX, aY, rSourceBitmap, pAlphaBitmap, fAlpha); } } - return drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, pAlphaBitmap); + return drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, pAlphaBitmap, fAlpha); } bool SalGraphics::HasFastDrawTransformedBitmap() const diff --git a/vcl/source/outdev/bitmap.cxx b/vcl/source/outdev/bitmap.cxx index 8f4fbef24ee0..563989cc366d 100644 --- a/vcl/source/outdev/bitmap.cxx +++ b/vcl/source/outdev/bitmap.cxx @@ -1052,7 +1052,8 @@ void OutputDevice::DrawDeviceAlphaBitmapSlowPath(const Bitmap& rBitmap, bool OutputDevice::DrawTransformBitmapExDirect( const basegfx::B2DHomMatrix& aFullTransform, - const BitmapEx& rBitmapEx) + const BitmapEx& rBitmapEx, + double fAlpha) { assert(!is_double_buffered_window()); @@ -1090,14 +1091,15 @@ bool OutputDevice::DrawTransformBitmapExDirect( aTopY, *pSalSrcBmp, pSalAlphaBmp, + fAlpha, *this); if (mpAlphaVDev) { // Merge bitmap alpha to alpha device - AlphaMask aBlack(rBitmapEx.GetSizePixel()); - aBlack.Erase(0); // opaque - mpAlphaVDev->DrawTransformBitmapExDirect(aFullTransform, BitmapEx(aBlack, aAlphaBitmap)); + AlphaMask aAlpha(rBitmapEx.GetSizePixel()); + aAlpha.Erase( ( 1 - fAlpha ) * 255 ); + mpAlphaVDev->DrawTransformBitmapExDirect(aFullTransform, BitmapEx(aAlpha, aAlphaBitmap)); } return bDone; @@ -1212,7 +1214,8 @@ struct LocalTimeTest void OutputDevice::DrawTransformedBitmapEx( const basegfx::B2DHomMatrix& rTransformation, - const BitmapEx& rBitmapEx) + const BitmapEx& rBitmapEx, + double fAlpha) { assert(!is_double_buffered_window()); @@ -1222,6 +1225,9 @@ void OutputDevice::DrawTransformedBitmapEx( if(rBitmapEx.IsEmpty()) return; + if(rtl::math::approxEqual( fAlpha, 0.0 )) + return; + // MM02 compared to other public methods of OutputDevice // this test was missing and led to zero-ptr-accesses if ( !mpGraphics && !AcquireGraphics() ) @@ -1254,6 +1260,38 @@ void OutputDevice::DrawTransformedBitmapEx( : nullptr); #endif + BitmapEx bitmapEx = rBitmapEx; + + const bool bInvert(RasterOp::Invert == meRasterOp); + const bool bBitmapChangedColor(mnDrawMode & (DrawModeFlags::BlackBitmap | DrawModeFlags::WhiteBitmap | DrawModeFlags::GrayBitmap )); + const bool bTryDirectPaint(!bInvert && !bBitmapChangedColor && !bMetafile); + + // First try to handle additional alpha blending, either directly, or modify the bitmap. + if(!rtl::math::approxEqual( fAlpha, 1.0 )) + { + if(bTryDirectPaint) + { + // tdf#130768 CAUTION(!) using GetViewTransformation() is *not* enough here, it may + // be that mnOutOffX/mnOutOffY is used - see AOO bug 75163, mentioned at + // ImplGetDeviceTransformation declaration + const basegfx::B2DHomMatrix aFullTransform(ImplGetDeviceTransformation() * rTransformation); + + if(DrawTransformBitmapExDirect(aFullTransform, bitmapEx, fAlpha)) + { + // we are done + return; + } + } + // Apply the alpha manually. + sal_uInt8 nColor( static_cast<sal_uInt8>( ::basegfx::fround( 255.0*(1.0 - fAlpha) + .5) ) ); + AlphaMask aAlpha( bitmapEx.GetSizePixel(), &nColor ); + if( bitmapEx.IsTransparent()) + aAlpha.BlendWith( bitmapEx.GetAlpha()); + bitmapEx = BitmapEx( bitmapEx.GetBitmap(), aAlpha ); + } + if(rtl::math::approxEqual( fAlpha, 1.0 )) + fAlpha = 1.0; // avoid the need for approxEqual in backends + // decompose matrix to check rotation and shear basegfx::B2DVector aScale, aTranslate; double fRotate, fShearX; @@ -1279,7 +1317,7 @@ void OutputDevice::DrawTransformedBitmapEx( EnableMapMode(false); } - DrawBitmapEx(aDestPt, aDestSize, rBitmapEx); + DrawBitmapEx(aDestPt, aDestSize, bitmapEx); if (!bMetafile && comphelper::LibreOfficeKit::isActive() && GetMapMode().GetMapUnit() != MapUnit::MapPixel) { EnableMapMode(); @@ -1288,9 +1326,6 @@ void OutputDevice::DrawTransformedBitmapEx( return; } - const bool bInvert(RasterOp::Invert == meRasterOp); - const bool bBitmapChangedColor(mnDrawMode & (DrawModeFlags::BlackBitmap | DrawModeFlags::WhiteBitmap | DrawModeFlags::GrayBitmap )); - const bool bTryDirectPaint(!bInvert && !bBitmapChangedColor && !bMetafile); if(bTryDirectPaint) { // tdf#130768 CAUTION(!) using GetViewTransformation() is *not* enough here, it may @@ -1298,7 +1333,7 @@ void OutputDevice::DrawTransformedBitmapEx( // ImplGetDeviceTransformation declaration const basegfx::B2DHomMatrix aFullTransform(ImplGetDeviceTransformation() * rTransformation); - if(DrawTransformBitmapExDirect(aFullTransform, rBitmapEx)) + if(DrawTransformBitmapExDirect(aFullTransform, bitmapEx)) { // we are done return; @@ -1316,7 +1351,7 @@ void OutputDevice::DrawTransformedBitmapEx( basegfx::fround(aScale.getX() + aTranslate.getX()) - aDestPt.X(), basegfx::fround(aScale.getY() + aTranslate.getY()) - aDestPt.Y()); - DrawBitmapEx(aDestPt, aDestSize, rBitmapEx); + DrawBitmapEx(aDestPt, aDestSize, bitmapEx); return; } @@ -1331,7 +1366,7 @@ 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(rBitmapEx.GetSizePixel()); + const Size& rOriginalSizePixel(bitmapEx.GetSizePixel()); const double fOrigArea(rOriginalSizePixel.Width() * rOriginalSizePixel.Height() * 0.5); const double fOrigAreaScaled(fOrigArea * 1.44); double fMaximumArea(std::clamp(fOrigAreaScaled, 1000000.0, 4500000.0)); @@ -1349,7 +1384,7 @@ void OutputDevice::DrawTransformedBitmapEx( if(aVisibleRange.isEmpty()) return; - BitmapEx aTransformed(rBitmapEx); + BitmapEx aTransformed(bitmapEx); // #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 diff --git a/vcl/unx/generic/gdi/gdiimpl.cxx b/vcl/unx/generic/gdi/gdiimpl.cxx index 680a9e5d14b8..5838c1aef978 100644 --- a/vcl/unx/generic/gdi/gdiimpl.cxx +++ b/vcl/unx/generic/gdi/gdiimpl.cxx @@ -845,7 +845,8 @@ bool X11SalGraphicsImpl::drawTransformedBitmap( const basegfx::B2DPoint&, const basegfx::B2DPoint&, const SalBitmap&, - const SalBitmap*) + const SalBitmap*, + double) { // here direct support for transformed bitmaps can be implemented return false; diff --git a/vcl/unx/generic/gdi/gdiimpl.hxx b/vcl/unx/generic/gdi/gdiimpl.hxx index dcc4f641f3a3..99499e08b444 100644 --- a/vcl/unx/generic/gdi/gdiimpl.hxx +++ b/vcl/unx/generic/gdi/gdiimpl.hxx @@ -270,7 +270,8 @@ public: const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) override; + const SalBitmap* pAlphaBitmap, + double fAlpha) override; virtual bool hasFastDrawTransformedBitmap() const override; diff --git a/vcl/unx/generic/gdi/salgdi2.cxx b/vcl/unx/generic/gdi/salgdi2.cxx index c4954e9e6119..cfdb272005a5 100644 --- a/vcl/unx/generic/gdi/salgdi2.cxx +++ b/vcl/unx/generic/gdi/salgdi2.cxx @@ -136,9 +136,10 @@ bool X11SalGraphics::drawTransformedBitmap( const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) + const SalBitmap* pAlphaBitmap, + double fAlpha) { - return mxImpl->drawTransformedBitmap( rNull, rX, rY, rSourceBitmap, pAlphaBitmap ); + return mxImpl->drawTransformedBitmap( rNull, rX, rY, rSourceBitmap, pAlphaBitmap, fAlpha ); } bool X11SalGraphics::hasFastDrawTransformedBitmap() const diff --git a/vcl/unx/generic/print/genpspgraphics.cxx b/vcl/unx/generic/print/genpspgraphics.cxx index 4218da4ed53b..eb427b2a73af 100644 --- a/vcl/unx/generic/print/genpspgraphics.cxx +++ b/vcl/unx/generic/print/genpspgraphics.cxx @@ -848,7 +848,8 @@ bool GenPspGraphics::drawTransformedBitmap( const basegfx::B2DPoint&, const basegfx::B2DPoint&, const SalBitmap&, - const SalBitmap*) + const SalBitmap*, + double) { // here direct support for transformed bitmaps can be implemented return false; diff --git a/vcl/win/gdi/gdiimpl.cxx b/vcl/win/gdi/gdiimpl.cxx index 40c7bbbbdb84..cedd5f42a802 100644 --- a/vcl/win/gdi/gdiimpl.cxx +++ b/vcl/win/gdi/gdiimpl.cxx @@ -2649,11 +2649,15 @@ bool WinSalGraphicsImpl::drawTransformedBitmap( const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) + 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)); diff --git a/vcl/win/gdi/gdiimpl.hxx b/vcl/win/gdi/gdiimpl.hxx index 0d9d9b30ce2c..3f4d13f1c517 100644 --- a/vcl/win/gdi/gdiimpl.hxx +++ b/vcl/win/gdi/gdiimpl.hxx @@ -226,7 +226,8 @@ public: const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) override; + const SalBitmap* pAlphaBitmap, + double fAlpha) override; virtual bool hasFastDrawTransformedBitmap() const override; diff --git a/vcl/win/gdi/salgdi_gdiplus.cxx b/vcl/win/gdi/salgdi_gdiplus.cxx index 8a85f033783b..13452f5c7a6e 100644 --- a/vcl/win/gdi/salgdi_gdiplus.cxx +++ b/vcl/win/gdi/salgdi_gdiplus.cxx @@ -89,10 +89,11 @@ bool WinSalGraphics::drawTransformedBitmap( const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, - const SalBitmap* pAlphaBitmap) + const SalBitmap* pAlphaBitmap, + double fAlpha) { return mpImpl->drawTransformedBitmap(rNull, rX, rY, - rSourceBitmap, pAlphaBitmap); + rSourceBitmap, pAlphaBitmap, fAlpha); } bool WinSalGraphics::hasFastDrawTransformedBitmap() const |