canvas/source/vcl/canvashelper.cxx       |    5 +-
 canvas/source/vcl/spritehelper.cxx       |   23 -----------
 include/vcl/outdev.hxx                   |    9 +++-
 include/vcl/print.hxx                    |    2 -
 vcl/headless/svpgdi.cxx                  |    6 ++-
 vcl/inc/headless/svpgdi.hxx              |    3 +
 vcl/inc/qt5/Qt5Graphics.hxx              |    2 -
 vcl/inc/quartz/salgdi.h                  |    3 +
 vcl/inc/salgdi.hxx                       |    9 +++-
 vcl/inc/salgdiimpl.hxx                   |    3 +
 vcl/inc/skia/gdiimpl.hxx                 |    2 -
 vcl/inc/unx/genpspgraphics.h             |    3 +
 vcl/inc/unx/salgdi.h                     |    3 +
 vcl/inc/win/salgdi.h                     |    3 +
 vcl/qa/cppunit/BackendTest.cxx           |   36 ++++++++++++++++++
 vcl/qt5/Qt5Graphics_GDI.cxx              |    4 +-
 vcl/quartz/salgdicommon.cxx              |    5 ++
 vcl/skia/gdiimpl.cxx                     |   24 ++++++++++--
 vcl/source/gdi/print.cxx                 |    3 +
 vcl/source/gdi/salgdilayout.cxx          |    9 +++-
 vcl/source/outdev/bitmap.cxx             |   61 ++++++++++++++++++++++++-------
 vcl/unx/generic/gdi/gdiimpl.cxx          |    3 +
 vcl/unx/generic/gdi/gdiimpl.hxx          |    3 +
 vcl/unx/generic/gdi/salgdi2.cxx          |    5 +-
 vcl/unx/generic/print/genpspgraphics.cxx |    3 +
 vcl/win/gdi/gdiimpl.cxx                  |    6 ++-
 vcl/win/gdi/gdiimpl.hxx                  |    3 +
 vcl/win/gdi/salgdi_gdiplus.cxx           |    5 +-
 28 files changed, 177 insertions(+), 69 deletions(-)

New commits:
commit 5ba5ac948db1092712ffeaef41983ea5f5dcb5cc
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Fri Feb 19 18:36:23 2021 +0100
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Wed Feb 24 12:40:13 2021 +0100

    add additional 0-1 alpha argument to DrawTransformedBitmap()
    
    This allows the VCL backends the apply the extra alpha transformation
    as it sees fit, rather than it being done manually elsewhere (and
    even if the backend doesn't implement it, at least do it in one
    place in the function).
    With the document from tdf#136223, going from slide 2 to slide 3,
    this easily saves 10-30% of CPU cycles. As an additional bonus,
    using AlphaMask::BlendWith() rather than AlphaMask::Replace()
    makes edges of shapes noticeably more smooth.
    
    Change-Id: I036dc9b887d6def0c7cdad3982becabdc7cd5206
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111247
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

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
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to