diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2021-02-19 18:36:23 +0100 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2021-02-24 12:40:13 +0100 |
commit | 5ba5ac948db1092712ffeaef41983ea5f5dcb5cc (patch) | |
tree | 1efc83d9f17c5f458908300eb9d918e665531662 /vcl/source | |
parent | f57872d2da23c8a3f90c67b6ad4a3ad0f699a276 (diff) |
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.lunak@collabora.com>
Diffstat (limited to 'vcl/source')
-rw-r--r-- | vcl/source/gdi/print.cxx | 3 | ||||
-rw-r--r-- | vcl/source/gdi/salgdilayout.cxx | 9 | ||||
-rw-r--r-- | vcl/source/outdev/bitmap.cxx | 61 |
3 files changed, 56 insertions, 17 deletions
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 |