From 088a7c7c451321a800ca8d3523a18b6bb93239b7 Mon Sep 17 00:00:00 2001 From: Noel Grandin Date: Tue, 24 Sep 2024 16:18:11 +0200 Subject: [PATCH] remove alpha device from OutputDevice and render to a combined color+alpha bitmap The strategy is to remove the mpAlphaVDev from OutputDevice, and have the OutputDevice create 32-bit SalBitmap's and then have the various backends correctly render to those 32-bit bitmaps. However, whenever we extract a BitmapEx from OutputDevice (e.g. via VirtualDevice) and hand it to the rest of the system, we split the color and alpha information. So the rest of the codebase doesn't have to deal with this yet. We have some major problems to overcome here: (*) Cairo uses 32-bit data, even if we ask for 24-bit color with no alpha. This is because the current version of cairo does not support RGB 24-bit data. (*) Sometimes we want the bitmap to be initialised with an opaque white background, sometimes we want it to be transparent. (*) Sometimes when we extract a bitmap from a device, we want the alpha channel, sometimes not. (*) There are lots of left-over bits of previous attempts of this change lying around, e.g. in skia. Notes (*) we allow Bitmap (ie. SalBitmap) to hold color+alpha (*) The BitmapEx(Bitmap) constructor checks if the incoming Bitmap is color+alpha, and if so, splits into a color bitmap and an alpha bitmap (*) Because the underlying image data is stored pre-multipled, if we write a transparent pixel with color, and then read the pixel value back, we might lose the color information. Change-Id: I0fc0042d6e5be5edd99b320892fb00a8eb2842fe Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173937 Tested-by: Jenkins Reviewed-by: Noel Grandin --- config_host/config_skia.h.in | 22 -- desktop/qa/desktop_lib/test_desktop_lib.cxx | 1 + include/vcl/BitmapInfoAccess.hxx | 2 - include/vcl/CairoFormats.hxx | 6 +- include/vcl/bitmap.hxx | 6 + include/vcl/outdev.hxx | 13 +- include/vcl/print.hxx | 2 + include/vcl/virdev.hxx | 6 +- sc/qa/unit/tiledrendering/tiledrendering.cxx | 1 + vcl/backendtest/GraphicsRenderTests.cxx | 11 +- vcl/backendtest/outputdevice/common.cxx | 2 +- vcl/headless/CairoCommon.cxx | 61 +++- vcl/headless/SvpGraphicsBackend.cxx | 5 +- vcl/headless/svpbmp.cxx | 15 +- vcl/headless/svpinst.cxx | 7 +- vcl/headless/svpvd.cxx | 20 +- vcl/inc/headless/CairoCommon.hxx | 3 +- vcl/inc/headless/SvpGraphicsBackend.hxx | 2 +- vcl/inc/headless/svpbmp.hxx | 2 +- vcl/inc/headless/svpinst.hxx | 3 +- vcl/inc/headless/svpvd.hxx | 7 +- vcl/inc/osx/salinst.h | 3 +- vcl/inc/qt5/QtGraphics.hxx | 2 +- vcl/inc/qt5/QtInstance.hxx | 6 +- vcl/inc/qt5/QtVirtualDevice.hxx | 3 +- vcl/inc/quartz/salgdi.h | 10 +- vcl/inc/quartz/salgdicommon.hxx | 6 +- vcl/inc/quartz/salvd.h | 4 +- vcl/inc/salgdi.hxx | 9 +- vcl/inc/salgdiimpl.hxx | 2 +- vcl/inc/salinst.hxx | 5 +- vcl/inc/salvd.hxx | 4 +- vcl/inc/skia/gdiimpl.hxx | 18 +- vcl/inc/skia/salbmp.hxx | 3 +- vcl/inc/skia/x11/salvd.hxx | 3 +- vcl/inc/unx/gtk/gtkinst.hxx | 3 +- vcl/inc/unx/salinst.h | 6 +- vcl/inc/unx/salvd.h | 2 +- vcl/inc/win/salgdi.h | 2 +- vcl/inc/win/salinst.h | 3 +- vcl/inc/win/salvd.h | 5 +- vcl/inc/windowdev.hxx | 2 + vcl/osx/salmacos.cxx | 25 +- vcl/qa/cppunit/BackendTest.cxx | 12 +- vcl/qa/cppunit/BitmapExTest.cxx | 5 - vcl/qa/cppunit/BitmapTest.cxx | 7 - vcl/qa/cppunit/animationrenderer.cxx | 1 + .../cppunit/bitmaprender/BitmapRenderTest.cxx | 22 +- vcl/qa/cppunit/outdev.cxx | 1 + vcl/qa/cppunit/skia/skia.cxx | 4 +- vcl/qt5/QtBitmap.cxx | 8 +- vcl/qt5/QtGraphics_GDI.cxx | 5 +- vcl/qt5/QtInstance.cxx | 11 +- vcl/qt5/QtVirtualDevice.cxx | 5 +- vcl/quartz/AquaGraphicsBackend.cxx | 58 +-- vcl/quartz/salbmp.cxx | 6 +- vcl/quartz/salvd.cxx | 11 +- vcl/skia/gdiimpl.cxx | 5 +- vcl/skia/salbmp.cxx | 37 +- vcl/skia/x11/salvd.cxx | 4 +- vcl/source/bitmap/BitmapEx.cxx | 13 +- vcl/source/bitmap/BitmapReadAccess.cxx | 18 - vcl/source/bitmap/BitmapWriteAccess.cxx | 8 - vcl/source/bitmap/bitmap.cxx | 36 ++ vcl/source/filter/png/PngImageReader.cxx | 121 ++----- vcl/source/filter/webp/reader.cxx | 98 ++--- vcl/source/gdi/print.cxx | 10 - vcl/source/gdi/salgdilayout.cxx | 4 +- vcl/source/gdi/virdev.cxx | 56 +-- vcl/source/outdev/background.cxx | 33 -- vcl/source/outdev/bitmap.cxx | 342 ++---------------- vcl/source/outdev/bitmapex.cxx | 37 +- vcl/source/outdev/clipping.cxx | 18 - vcl/source/outdev/curvedshapes.cxx | 12 - vcl/source/outdev/eps.cxx | 3 - vcl/source/outdev/fill.cxx | 10 - vcl/source/outdev/font.cxx | 18 - vcl/source/outdev/gradient.cxx | 8 - vcl/source/outdev/hatch.cxx | 3 - vcl/source/outdev/line.cxx | 13 - vcl/source/outdev/map.cxx | 16 - vcl/source/outdev/mask.cxx | 17 - vcl/source/outdev/outdev.cxx | 75 +--- vcl/source/outdev/pixel.cxx | 15 - vcl/source/outdev/polygon.cxx | 15 - vcl/source/outdev/polyline.cxx | 21 +- vcl/source/outdev/rect.cxx | 9 - vcl/source/outdev/stack.cxx | 6 - vcl/source/outdev/text.cxx | 41 --- vcl/source/outdev/textline.cxx | 20 - vcl/source/outdev/transparent.cxx | 34 +- vcl/source/outdev/wallpaper.cxx | 9 - vcl/source/window/paint.cxx | 3 - vcl/unx/generic/app/salinst.cxx | 4 - .../generic/gdi/X11CairoSalGraphicsImpl.cxx | 5 +- .../generic/gdi/X11CairoSalGraphicsImpl.hxx | 2 +- vcl/unx/generic/gdi/salvd.cxx | 10 +- vcl/unx/gtk3/gtkinst.cxx | 7 +- vcl/win/app/salinst.cxx | 4 - vcl/win/gdi/gdiimpl.cxx | 172 +++++++-- vcl/win/gdi/gdiimpl.hxx | 2 +- vcl/win/gdi/salbmp.cxx | 2 +- vcl/win/gdi/salgdi2.cxx | 4 +- vcl/win/gdi/salvd.cxx | 32 +- 104 files changed, 635 insertions(+), 1276 deletions(-) diff --git a/config_host/config_skia.h.in b/config_host/config_skia.h.in index 322dedb18440..89017284ecbe 100644 --- a/config_host/config_skia.h.in +++ b/config_host/config_skia.h.in @@ -8,28 +8,6 @@ are the same. #ifndef CONFIG_SKIA_H #define CONFIG_SKIA_H -// This is a setting that should be set manually and it affects LO -// code rather than Skia itself. It basically controls setting -// BackendCapabilities::mbSupportsBitmap32, i.e. whether one LO bitmap -// contains all the 32bits of an image including the alpha (premultiplied). -// -// Since Skia does not natively support 24bpp, the preferred setup is -// that the setting should be enabled, it makes the code faster and cleaner. -// -// Unfortunately VCL historically splits alpha into a whole separate -// bitmap and works with 24bpp+8bpp, which is generally more complicated, -// more error-prone and just worse, but that's how LO code has been -// written and so there are many places in LO that expect this and -// do not work correctly with true 32bpp bitmaps. -// -// So ultimately the 24+8 split should be dumped (preferably in all of LO, -// not just the Skia-related code), but until all of LO works correctly -// with 32bpp keep this disabled in order to avoid such breakages. - -//#define SKIA_USE_BITMAP32 1 -#define SKIA_USE_BITMAP32 0 - - // GPU support (set by configure). #undef SK_GANESH // Vulkan support enabled (set by configure). diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx index 231aea8d0f3c..975482466baa 100644 --- a/desktop/qa/desktop_lib/test_desktop_lib.cxx +++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx @@ -2522,6 +2522,7 @@ void DesktopLOKTest::testPaintPartTileDifferentSchemes() constexpr int nPixelX = 128; constexpr int nPixelY = 128 * nCanvasWidth; + // this is BGRA format data std::array aPixels; // Both parts should be painted with dark scheme diff --git a/include/vcl/BitmapInfoAccess.hxx b/include/vcl/BitmapInfoAccess.hxx index e01c2aba7a8f..dece92e76a2d 100644 --- a/include/vcl/BitmapInfoAccess.hxx +++ b/include/vcl/BitmapInfoAccess.hxx @@ -25,8 +25,6 @@ #include #include -bool Bitmap32IsPreMultipled(); - typedef BitmapColor (*FncGetPixel)(ConstScanline pScanline, tools::Long nX); typedef void (*FncSetPixel)(Scanline pScanline, tools::Long nX, const BitmapColor& rBitmapColor); diff --git a/include/vcl/CairoFormats.hxx b/include/vcl/CairoFormats.hxx index 1d2f3b426e8d..487d5ceb35c5 100644 --- a/include/vcl/CairoFormats.hxx +++ b/include/vcl/CairoFormats.hxx @@ -35,21 +35,21 @@ */ #if ENABLE_CAIRO_RGBA #define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcRgb) -#define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcRgbx) +#define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcRgba) #define SVP_CAIRO_BLUE 2 #define SVP_CAIRO_GREEN 1 #define SVP_CAIRO_RED 0 #define SVP_CAIRO_ALPHA 3 #elif defined OSL_BIGENDIAN #define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcRgb) -#define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcXrgb) +#define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcArgb) #define SVP_CAIRO_BLUE 3 #define SVP_CAIRO_GREEN 2 #define SVP_CAIRO_RED 1 #define SVP_CAIRO_ALPHA 0 #else #define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcBgr) -#define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcBgrx) +#define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcBgra) #define SVP_CAIRO_BLUE 0 #define SVP_CAIRO_GREEN 1 #define SVP_CAIRO_RED 2 diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx index cfb2c1a95caa..68bf8d75bb38 100644 --- a/include/vcl/bitmap.hxx +++ b/include/vcl/bitmap.hxx @@ -566,6 +566,12 @@ public: // access to SystemDependentDataHolder, to support overload in derived class(es) const basegfx::SystemDependentDataHolder* accessSystemDependentDataHolder() const; + + /** + Can only be called on 32-bit bitmaps. Returns data split into color bitmap and alpha bitmap. + */ + std::pair SplitIntoColorAndAlpha() const; + public: /** ReassignWithSize and recalculate bitmap. diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx index 47e025f5ff31..c8f11f1f10cf 100644 --- a/include/vcl/outdev.hxx +++ b/include/vcl/outdev.hxx @@ -184,9 +184,6 @@ private: // The canvas interface for this output device. Is persistent after the first GetCanvas() call mutable css::uno::WeakReference< css::rendering::XCanvas > mxCanvas; - // TEMP TEMP TEMP - VclPtr mpAlphaVDev; - /// Additional output pixel offset, applied in LogicToPixel (used by SetPixelOffset/GetPixelOffset) tools::Long mnOutOffOrigX; /// Additional output offset in _logical_ coordinates, applied in PixelToLogic (used by SetPixelOffset/GetPixelOffset) @@ -1357,7 +1354,10 @@ public: virtual Bitmap GetBitmap( const Point& rSrcPt, const Size& rSize ) const; - bool HasAlpha() const { return bool(mpAlphaVDev); } + /** + * Does this device support alpha? + */ + virtual bool HasAlpha() const = 0; /** Query extended bitmap (with alpha channel, if available). */ @@ -1460,14 +1460,11 @@ private: const sal_Int32* pMapX, const sal_Int32* pMapY ); - SAL_DLLPRIVATE Bitmap BlendBitmapWithAlpha( + static SAL_DLLPRIVATE Bitmap BlendBitmapWithAlpha( Bitmap& aBmp, BitmapReadAccess const * pP, BitmapReadAccess const * pA, - const tools::Rectangle& aDstRect, - const sal_Int32 nOffY, const sal_Int32 nDstHeight, - const sal_Int32 nOffX, const sal_Int32 nDstWidth, const sal_Int32* pMapX, const sal_Int32* pMapY ); diff --git a/include/vcl/print.hxx b/include/vcl/print.hxx index cb03346edbd0..2dc9a2e5127b 100644 --- a/include/vcl/print.hxx +++ b/include/vcl/print.hxx @@ -156,6 +156,8 @@ public: css::awt::DeviceInfo GetDeviceInfo() const override; + virtual bool HasAlpha() const override { return false; } + protected: virtual void DrawDeviceMask( const Bitmap& rMask, const Color& rMaskColor, const Point& rDestPt, const Size& rDestSize, diff --git a/include/vcl/virdev.hxx b/include/vcl/virdev.hxx index 0ab91eae8973..84a7df790aec 100644 --- a/include/vcl/virdev.hxx +++ b/include/vcl/virdev.hxx @@ -55,7 +55,7 @@ private: bool mbForceZeroExtleadBug; SAL_DLLPRIVATE void ImplInitVirDev( const OutputDevice* pOutDev, tools::Long nDX, tools::Long nDY, const SystemGraphicsData *pData = nullptr ); - SAL_DLLPRIVATE bool InnerImplSetOutputSizePixel( const Size& rNewSize, bool bErase ); + SAL_DLLPRIVATE bool InnerImplSetOutputSizePixel( const Size& rNewSize, bool bErase, bool bAlphaMaskTransparent ); VirtualDevice (const VirtualDevice &) = delete; VirtualDevice & operator= (const VirtualDevice &) = delete; @@ -144,6 +144,10 @@ public: bool IsScreenComp() const override { return mbScreenComp; } + bool IsWithoutAlpha() const { return meFormatAndAlpha == DeviceFormat::WITHOUT_ALPHA; } + + virtual bool HasAlpha() const override { return meFormatAndAlpha != DeviceFormat::WITHOUT_ALPHA; } + private: SAL_DLLPRIVATE void ImplSetReferenceDevice( RefDevMode, sal_Int32 i_nDPIX, sal_Int32 i_nDPIY ); diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx index e4966adc2f4a..6e3f2c2f8deb 100644 --- a/sc/qa/unit/tiledrendering/tiledrendering.cxx +++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx @@ -1404,6 +1404,7 @@ static Bitmap getTile(ScModelObj* pModelObj, int nTilePosX, int nTilePosY, tools { size_t nCanvasSize = 1024; size_t nTileSize = 256; + // BGRA format data std::vector aPixmap(nCanvasSize * nCanvasSize * 4, 0); ScopedVclPtrInstance xDevice(DeviceFormat::WITHOUT_ALPHA); xDevice->SetBackground(Wallpaper(COL_TRANSPARENT)); diff --git a/vcl/backendtest/GraphicsRenderTests.cxx b/vcl/backendtest/GraphicsRenderTests.cxx index 2683541b15ea..6e0fe7ab1146 100644 --- a/vcl/backendtest/GraphicsRenderTests.cxx +++ b/vcl/backendtest/GraphicsRenderTests.cxx @@ -72,7 +72,6 @@ void exportBitmapExToImage(OUString const& rImageName, const BitmapEx& rBitmapEx SvFileStream aStream(rImageName, StreamMode::WRITE | StreamMode::TRUNC); GraphicFilter::GetGraphicFilter().compressAsPNG(aBitmapEx, aStream); } -bool is32bppSupported() { return ImplGetSVData()->mpDefInst->supportsBitmap32(); } // Some tests need special handling in drawing code (for example, not smoothscaling // when handling HiDPI bitmaps). Temporarily set up the test name to get such special @@ -1787,7 +1786,7 @@ void GraphicsRenderTests::testDrawBitmap32bpp() GraphicsTestZone zone(aTestName); vcl::test::OutputDeviceTestBitmap aOutDevTest; Bitmap aBitmap = aOutDevTest.setupDrawBitmap(vcl::PixelFormat::N32_BPP); - if (!SHOULD_ASSERT || !is32bppSupported()) + if (!SHOULD_ASSERT) { appendTestResult(aTestName, u"SKIPPED"_ustr); return; @@ -1809,7 +1808,7 @@ void GraphicsRenderTests::testDrawTransformedBitmap32bpp() GraphicsTestZone zone(aTestName); vcl::test::OutputDeviceTestBitmap aOutDevTest; Bitmap aBitmap = aOutDevTest.setupDrawTransformedBitmap(vcl::PixelFormat::N32_BPP); - if (!SHOULD_ASSERT || !is32bppSupported()) + if (!SHOULD_ASSERT) { appendTestResult(aTestName, u"SKIPPED"_ustr); return; @@ -1831,7 +1830,7 @@ void GraphicsRenderTests::testDrawBitmapExWithAlpha32bpp() GraphicsTestZone zone(aTestName); vcl::test::OutputDeviceTestBitmap aOutDevTest; Bitmap aBitmap = aOutDevTest.setupDrawBitmapExWithAlpha(vcl::PixelFormat::N32_BPP); - if (!SHOULD_ASSERT || !is32bppSupported()) + if (!SHOULD_ASSERT) { appendTestResult(aTestName, u"SKIPPED"_ustr); return; @@ -1853,7 +1852,7 @@ void GraphicsRenderTests::testDrawMask32bpp() GraphicsTestZone zone(aTestName); vcl::test::OutputDeviceTestBitmap aOutDevTest; Bitmap aBitmap = aOutDevTest.setupDrawMask(vcl::PixelFormat::N32_BPP); - if (!SHOULD_ASSERT || !is32bppSupported()) + if (!SHOULD_ASSERT) { appendTestResult(aTestName, u"SKIPPED"_ustr); return; @@ -1874,7 +1873,7 @@ void GraphicsRenderTests::testDrawBlend32bpp() GraphicsTestZone zone(aTestName); vcl::test::OutputDeviceTestBitmap aOutDevTest; BitmapEx aBitmapEx = aOutDevTest.setupDrawBlend(vcl::PixelFormat::N32_BPP); - if (!SHOULD_ASSERT || !is32bppSupported()) + if (!SHOULD_ASSERT) { appendTestResult(aTestName, u"SKIPPED"_ustr); return; diff --git a/vcl/backendtest/outputdevice/common.cxx b/vcl/backendtest/outputdevice/common.cxx index c8a55fd9478d..0a212f579291 100644 --- a/vcl/backendtest/outputdevice/common.cxx +++ b/vcl/backendtest/outputdevice/common.cxx @@ -1655,7 +1655,7 @@ TestResult OutputDeviceTestBitmap::checkBlend(const BitmapEx& rBitmapEx) std::vector aExpected { - COL_WHITE, COL_WHITE, COL_YELLOW, constBackgroundColor, + COL_BLACK, COL_BLACK, COL_YELLOW, constBackgroundColor, constBackgroundColor, aBlendedColor, constBackgroundColor }; Bitmap aBitmap(rBitmapEx.GetBitmap()); diff --git a/vcl/headless/CairoCommon.cxx b/vcl/headless/CairoCommon.cxx index ff5090b17079..d3323b9c3bcb 100644 --- a/vcl/headless/CairoCommon.cxx +++ b/vcl/headless/CairoCommon.cxx @@ -642,6 +642,27 @@ void CairoCommon::applyColor(cairo_t* cr, Color aColor, double fTransparency) } } +void CairoCommon::applyColor2(cairo_t* cr, Color aColor) +{ + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_content_t eContentType = cairo_surface_get_content(cairo_get_target(cr)); + if (eContentType == CAIRO_CONTENT_COLOR_ALPHA) + { + cairo_set_source_rgba(cr, aColor.GetRed() / 255.0, aColor.GetGreen() / 255.0, + aColor.GetBlue() / 255.0, aColor.GetAlpha() / 255.0); + } + else if (eContentType == CAIRO_CONTENT_COLOR) + { + cairo_set_source_rgba(cr, aColor.GetRed() / 255.0, aColor.GetGreen() / 255.0, + aColor.GetBlue() / 255.0, 1.0); + } + else // CAIRO_CONTENT_ALPHA + { + double fSet = aColor == COL_BLACK ? 1.0 : 0.0; + cairo_set_source_rgba(cr, 1, 1, 1, fSet); + } +} + void CairoCommon::clipRegion(cairo_t* cr, const vcl::Region& rClipRegion) { RectangleVector aRectangles; @@ -713,7 +734,25 @@ void CairoCommon::drawPixel(const std::optional& rLineColor, tools::Long clipRegion(cr); cairo_rectangle(cr, nX, nY, 1, 1); - CairoCommon::applyColor(cr, *rLineColor, 0.0); + + cairo_content_t eContentType = cairo_surface_get_content(cairo_get_target(cr)); + if (eContentType == CAIRO_CONTENT_COLOR_ALPHA) + { + cairo_set_source_rgba(cr, rLineColor->GetRed() / 255.0, rLineColor->GetGreen() / 255.0, + rLineColor->GetBlue() / 255.0, rLineColor->GetAlpha() / 255.0); + } + else if (eContentType == CAIRO_CONTENT_COLOR) + { + cairo_set_source_rgba(cr, rLineColor->GetRed() / 255.0, rLineColor->GetGreen() / 255.0, + rLineColor->GetBlue() / 255.0, 1.0); + } + else // eContentType == CAIRO_CONTENT_ALPHA + { + double fSet = *rLineColor == COL_BLACK ? 1.0 : 0.0; + cairo_set_source_rgba(cr, 1, 1, 1, fSet); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + } + cairo_fill(cr); basegfx::B2DRange extents = getClippedFillDamage(cr); @@ -801,7 +840,6 @@ void CairoCommon::drawRect(double nX, double nY, double nWidth, double nHeight, // fast path for the common case of simply creating a solid block of color if (onlyFillRect(m_oFillColor, m_oLineColor)) { - double fTransparency = 0; // don't bother trying to draw stuff which is effectively invisible if (nWidth < 0.1 || nHeight < 0.1) return; @@ -820,7 +858,7 @@ void CairoCommon::drawRect(double nX, double nY, double nWidth, double nHeight, } cairo_rectangle(cr, nX, nY, nWidth, nHeight); - CairoCommon::applyColor(cr, *m_oFillColor, fTransparency); + CairoCommon::applyColor2(cr, *m_oFillColor); // Get FillDamage basegfx::B2DRange extents = getClippedFillDamage(cr); @@ -1876,14 +1914,15 @@ void CairoCommon::drawMask(const SalTwoRect& rTR, const SalBitmap& rSalBitmap, C } std::shared_ptr CairoCommon::getBitmap(tools::Long nX, tools::Long nY, - tools::Long nWidth, tools::Long nHeight) + tools::Long nWidth, tools::Long nHeight, + bool bWithoutAlpha) { std::shared_ptr pBitmap = std::make_shared(); BitmapPalette aPal; assert(GetBitCount() != 1 && "not supported anymore"); vcl::PixelFormat ePixelFormat = vcl::PixelFormat::N32_BPP; - if (!pBitmap->ImplCreate(Size(nWidth, nHeight), ePixelFormat, aPal, false)) + if (!pBitmap->ImplCreate(Size(nWidth, nHeight), ePixelFormat, aPal, false, bWithoutAlpha)) { SAL_WARN("vcl.gdi", "SvpSalGraphics::getBitmap, cannot create bitmap"); return nullptr; @@ -2023,8 +2062,8 @@ std::optional FastConvert24BitRgbTo32BitCairo(const BitmapBuffer* for (tools::Long x = 0; x < nWidth; ++x) { #if ENABLE_CAIRO_RGBA - static_assert(SVP_CAIRO_FORMAT == ScanlineFormat::N32BitTcRgbx, - "Expected SVP_CAIRO_FORMAT set to N32BitTcRgbx"); + static_assert(SVP_CAIRO_FORMAT == ScanlineFormat::N32BitTcRgba, + "Expected SVP_CAIRO_FORMAT set to N32BitTcRgba"); static_assert(SVP_24BIT_FORMAT == ScanlineFormat::N24BitTcRgb, "Expected SVP_24BIT_FORMAT set to N24BitTcRgb"); pD[0] = pS[0]; @@ -2032,8 +2071,8 @@ std::optional FastConvert24BitRgbTo32BitCairo(const BitmapBuffer* pD[2] = pS[2]; pD[3] = 0xff; // Alpha #elif defined OSL_BIGENDIAN - static_assert(SVP_CAIRO_FORMAT == ScanlineFormat::N32BitTcXrgb, - "Expected SVP_CAIRO_FORMAT set to N32BitTcXrgb"); + static_assert(SVP_CAIRO_FORMAT == ScanlineFormat::N32BitTcArgb, + "Expected SVP_CAIRO_FORMAT set to N32BitTcArgb"); static_assert(SVP_24BIT_FORMAT == ScanlineFormat::N24BitTcRgb, "Expected SVP_24BIT_FORMAT set to N24BitTcRgb"); pD[0] = 0xff; // Alpha @@ -2041,8 +2080,8 @@ std::optional FastConvert24BitRgbTo32BitCairo(const BitmapBuffer* pD[2] = pS[1]; pD[3] = pS[2]; #else - static_assert(SVP_CAIRO_FORMAT == ScanlineFormat::N32BitTcBgrx, - "Expected SVP_CAIRO_FORMAT set to N32BitTcBgrx"); + static_assert(SVP_CAIRO_FORMAT == ScanlineFormat::N32BitTcBgra, + "Expected SVP_CAIRO_FORMAT set to N32BitTcAgrx"); static_assert(SVP_24BIT_FORMAT == ScanlineFormat::N24BitTcBgr, "Expected SVP_24BIT_FORMAT set to N24BitTcBgr"); pD[0] = pS[0]; diff --git a/vcl/headless/SvpGraphicsBackend.cxx b/vcl/headless/SvpGraphicsBackend.cxx index 029e65820209..61f7454b7b66 100644 --- a/vcl/headless/SvpGraphicsBackend.cxx +++ b/vcl/headless/SvpGraphicsBackend.cxx @@ -182,9 +182,10 @@ void SvpGraphicsBackend::drawMask(const SalTwoRect& rTR, const SalBitmap& rSalBi } std::shared_ptr SvpGraphicsBackend::getBitmap(tools::Long nX, tools::Long nY, - tools::Long nWidth, tools::Long nHeight) + tools::Long nWidth, tools::Long nHeight, + bool bWithoutAlpha) { - return m_rCairoCommon.getBitmap(nX, nY, nWidth, nHeight); + return m_rCairoCommon.getBitmap(nX, nY, nWidth, nHeight, bWithoutAlpha); } void SvpGraphicsBackend::drawBitmapBuffer(const SalTwoRect& rTR, const BitmapBuffer* pBuffer, diff --git a/vcl/headless/svpbmp.cxx b/vcl/headless/svpbmp.cxx index 9066791db1f1..de034b2d4c7b 100644 --- a/vcl/headless/svpbmp.cxx +++ b/vcl/headless/svpbmp.cxx @@ -42,7 +42,8 @@ static std::optional ImplCreateDIB( const Size& rSize, vcl::PixelFormat ePixelFormat, const BitmapPalette& rPal, - bool bClear) + bool bClear, + bool bWithoutAlpha) { if (!rSize.Width() || !rSize.Height()) return std::nullopt; @@ -58,7 +59,13 @@ static std::optional ImplCreateDIB( pDIB->meFormat = SVP_24BIT_FORMAT; break; case vcl::PixelFormat::N32_BPP: - pDIB->meFormat = SVP_CAIRO_FORMAT; +#if ENABLE_CAIRO_RGBA + pDIB->meFormat = bWithoutAlpha ? ScanlineFormat::N32BitTcRgbx : SVP_CAIRO_FORMAT; +#elif defined OSL_BIGENDIAN + pDIB->meFormat = bWithoutAlpha ? ScanlineFormat::N32BitTcXrgb : SVP_CAIRO_FORMAT; +#else + pDIB->meFormat = bWithoutAlpha ? ScanlineFormat::N32BitTcBgrx : SVP_CAIRO_FORMAT; +#endif break; case vcl::PixelFormat::INVALID: assert(false); @@ -132,10 +139,10 @@ void SvpSalBitmap::Create(const std::optional& pBuf) } bool SvpSalBitmap::ImplCreate(const Size& rSize, vcl::PixelFormat ePixelFormat, - const BitmapPalette& rPal, bool bClear) + const BitmapPalette& rPal, bool bClear, bool bWithoutAlpha) { Destroy(); - moDIB = ImplCreateDIB(rSize, ePixelFormat, rPal, bClear); + moDIB = ImplCreateDIB(rSize, ePixelFormat, rPal, bClear, bWithoutAlpha); return moDIB.has_value(); } diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx index 8d6fcd9288e9..8a2318db00db 100644 --- a/vcl/headless/svpinst.cxx +++ b/vcl/headless/svpinst.cxx @@ -199,12 +199,13 @@ void SvpSalInstance::DestroyObject( SalObject* pObject ) std::unique_ptr SvpSalInstance::CreateVirtualDevice(SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat /*eFormat*/) + DeviceFormat /*eFormat*/, + bool bAlphaMaskTransparent) { SvpSalGraphics *pSvpSalGraphics = dynamic_cast(&rGraphics); assert(pSvpSalGraphics); std::unique_ptr xNew(new SvpSalVirtualDevice(pSvpSalGraphics->getSurface(), /*pPreExistingTarget*/nullptr)); - if (!xNew->SetSize(nDX, nDY)) + if (!xNew->SetSize(nDX, nDY, bAlphaMaskTransparent)) xNew.reset(); return xNew; } @@ -227,7 +228,7 @@ std::unique_ptr SvpSalInstance::CreateVirtualDevice(SalGraphic cairo_surface_t* pPreExistingTarget = nullptr; #endif std::unique_ptr xNew(new SvpSalVirtualDevice(pSvpSalGraphics->getSurface(), pPreExistingTarget)); - if (!xNew->SetSize(nDX, nDY)) + if (!xNew->SetSize(nDX, nDY, /*bAlphaMaskTransparent*/false)) xNew.reset(); return xNew; } diff --git a/vcl/headless/svpvd.cxx b/vcl/headless/svpvd.cxx index c9524aa65065..00b8014c9cb9 100644 --- a/vcl/headless/svpvd.cxx +++ b/vcl/headless/svpvd.cxx @@ -63,7 +63,7 @@ void SvpSalVirtualDevice::ReleaseGraphics( SalGraphics* pGraphics ) delete pGraphics; } -bool SvpSalVirtualDevice::SetSize( tools::Long nNewDX, tools::Long nNewDY ) +bool SvpSalVirtualDevice::SetSize( tools::Long nNewDX, tools::Long nNewDY, bool bAlphaMaskTransparent ) { if (nNewDX == 0) nNewDX = 1; @@ -78,7 +78,7 @@ bool SvpSalVirtualDevice::SetSize( tools::Long nNewDX, tools::Long nNewDY ) m_aFrameSize = basegfx::B2IVector(nNewDX, nNewDY); if (m_bOwnsSurface) - bSuccess = CreateSurface(nNewDX, nNewDY); + bSuccess = CreateSurface(nNewDX, nNewDY, bAlphaMaskTransparent); assert(m_pSurface); @@ -112,7 +112,7 @@ bool SvpSalVirtualDevice::CreateSurface(tools::Long nNewDX, tools::Long nNewDY, return cairo_surface_status(m_pSurface) == CAIRO_STATUS_SUCCESS; } -bool SvpSalVirtualDevice::CreateSurface(tools::Long nNewDX, tools::Long nNewDY) +bool SvpSalVirtualDevice::CreateSurface(tools::Long nNewDX, tools::Long nNewDY, bool bAlphaMaskTransparent) { if (m_pSurface) { @@ -132,11 +132,25 @@ bool SvpSalVirtualDevice::CreateSurface(tools::Long nNewDX, tools::Long nNewDY) // in software (which should be fairly cheap for small surfaces anyway). m_pSurface = cairo_surface_create_similar_image(m_pRefSurface, CAIRO_FORMAT_ARGB32, nNewDX, nNewDY); dl_cairo_surface_set_device_scale(m_pSurface, fXScale, fYScale); + + cairo_t* cr = cairo_create(m_pSurface); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_rectangle(cr, 0, 0, nNewDX, nNewDY); + cairo_set_source_rgba(cr, 0, 0, 0, bAlphaMaskTransparent ? 0 : 1); + cairo_fill(cr); + cairo_destroy(cr); } else { m_pSurface = cairo_surface_create_similar(m_pRefSurface, CAIRO_CONTENT_COLOR_ALPHA, nNewDX, nNewDY); // Device scale is inherited in this case. + + cairo_t* cr = cairo_create(m_pSurface); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_rectangle(cr, 0, 0, nNewDX, nNewDY); + cairo_set_source_rgba(cr, 1, 1, 1, bAlphaMaskTransparent ? 0 : 1); + cairo_fill(cr); + cairo_destroy(cr); } SAL_WARN_IF(cairo_surface_status(m_pSurface) != CAIRO_STATUS_SUCCESS, "vcl", "surface of size " << nNewDX << " by " << nNewDY << " creation failed with status of: " << cairo_status_to_string(cairo_surface_status(m_pSurface))); diff --git a/vcl/inc/headless/CairoCommon.hxx b/vcl/inc/headless/CairoCommon.hxx index 96630f39b681..b1423b7f6e03 100644 --- a/vcl/inc/headless/CairoCommon.hxx +++ b/vcl/inc/headless/CairoCommon.hxx @@ -152,6 +152,7 @@ struct VCL_DLLPUBLIC CairoCommon cairo_t* createTmpCompatibleCairoContext() const; static void applyColor(cairo_t* cr, Color rColor, double fTransparency = 0.0); + static void applyColor2(cairo_t* cr, Color rColor); void clipRegion(cairo_t* cr); static void clipRegion(cairo_t* cr, const vcl::Region& rClipRegion); @@ -224,7 +225,7 @@ struct VCL_DLLPUBLIC CairoCommon bool bAntiAlias); std::shared_ptr getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight); + tools::Long nHeight, bool bWithoutAlpha); static cairo_surface_t* createCairoSurface(const BitmapBuffer* pBuffer); diff --git a/vcl/inc/headless/SvpGraphicsBackend.hxx b/vcl/inc/headless/SvpGraphicsBackend.hxx index a631cb161e8b..28851fb0e112 100644 --- a/vcl/inc/headless/SvpGraphicsBackend.hxx +++ b/vcl/inc/headless/SvpGraphicsBackend.hxx @@ -93,7 +93,7 @@ public: Color nMaskColor) override; std::shared_ptr getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight) override; + tools::Long nHeight, bool bWithoutAlpha) override; Color getPixel(tools::Long nX, tools::Long nY) override; diff --git a/vcl/inc/headless/svpbmp.hxx b/vcl/inc/headless/svpbmp.hxx index e60f8ce91690..439f7e626189 100644 --- a/vcl/inc/headless/svpbmp.hxx +++ b/vcl/inc/headless/svpbmp.hxx @@ -35,7 +35,7 @@ public: SAL_DLLPRIVATE bool ImplCreate(const Size& rSize, vcl::PixelFormat ePixelFormat, const BitmapPalette& rPalette, - bool bClear); + bool bClear, bool bWithoutAlpha = false); // SalBitmap SAL_DLLPRIVATE virtual bool Create(const Size& rSize, diff --git a/vcl/inc/headless/svpinst.hxx b/vcl/inc/headless/svpinst.hxx index 2a420d15c80d..6cb7668e9d89 100644 --- a/vcl/inc/headless/svpinst.hxx +++ b/vcl/inc/headless/svpinst.hxx @@ -135,7 +135,8 @@ public: SAL_DLLPRIVATE virtual std::unique_ptr CreateVirtualDevice( SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat ) override; + DeviceFormat eFormat, + bool bAlphaMaskTransparent = false ) override; // VirtualDevice // nDX and nDY in Pixel diff --git a/vcl/inc/headless/svpvd.hxx b/vcl/inc/headless/svpvd.hxx index 4bc796f32a60..44647dd7e122 100644 --- a/vcl/inc/headless/svpvd.hxx +++ b/vcl/inc/headless/svpvd.hxx @@ -36,7 +36,7 @@ class VCL_DLLPUBLIC SvpSalVirtualDevice : public SalVirtualDevice std::vector< SvpSalGraphics* > m_aGraphics; bool CreateSurface(tools::Long nNewDX, tools::Long nNewDY, sal_uInt8 *const pBuffer); - bool CreateSurface(tools::Long nNewDX, tools::Long nNewDY); + bool CreateSurface(tools::Long nNewDX, tools::Long nNewDY, bool bAlphaMaskTransparent = false); protected: SvpSalGraphics* AddGraphics(SvpSalGraphics* aGraphics); @@ -49,10 +49,9 @@ public: virtual SalGraphics* AcquireGraphics() override; virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; - virtual bool SetSize( tools::Long nNewDX, tools::Long nNewDY ) override; + virtual bool SetSize( tools::Long nNewDX, tools::Long nNewDY, bool bAlphaMaskTransparent ) override; virtual bool SetSizeUsingBuffer( tools::Long nNewDX, tools::Long nNewDY, - sal_uInt8 * pBuffer - ) override; + sal_uInt8 * pBuffer) override; cairo_surface_t* GetSurface() const { return m_pSurface; } diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h index 443b370498f5..f6ef23541004 100644 --- a/vcl/inc/osx/salinst.h +++ b/vcl/inc/osx/salinst.h @@ -109,7 +109,8 @@ public: virtual std::unique_ptr CreateVirtualDevice( SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat ) override; + DeviceFormat eFormat, + bool bAlphaMaskTransparent = false ) override; virtual std::unique_ptr CreateVirtualDevice( SalGraphics& rGraphics, tools::Long &nDX, tools::Long &nDY, diff --git a/vcl/inc/qt5/QtGraphics.hxx b/vcl/inc/qt5/QtGraphics.hxx index 4c7deb5d3f68..898a0e3f9943 100644 --- a/vcl/inc/qt5/QtGraphics.hxx +++ b/vcl/inc/qt5/QtGraphics.hxx @@ -122,7 +122,7 @@ public: Color nMaskColor) override; std::shared_ptr getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight) override; + tools::Long nHeight, bool bWithoutAlpha) override; Color getPixel(tools::Long nX, tools::Long nY) override; diff --git a/vcl/inc/qt5/QtInstance.hxx b/vcl/inc/qt5/QtInstance.hxx index 51308c6ede84..699c04139f06 100644 --- a/vcl/inc/qt5/QtInstance.hxx +++ b/vcl/inc/qt5/QtInstance.hxx @@ -159,9 +159,9 @@ public: bool bShow) override; virtual void DestroyObject(SalObject* pObject) override; - virtual std::unique_ptr CreateVirtualDevice(SalGraphics& rGraphics, - tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat) override; + virtual std::unique_ptr + CreateVirtualDevice(SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, + DeviceFormat eFormat, bool bAlphaMaskTransparent = false) override; virtual std::unique_ptr CreateVirtualDevice(SalGraphics& rGraphics, tools::Long& nDX, tools::Long& nDY, diff --git a/vcl/inc/qt5/QtVirtualDevice.hxx b/vcl/inc/qt5/QtVirtualDevice.hxx index f20b937d5488..50bea3155338 100644 --- a/vcl/inc/qt5/QtVirtualDevice.hxx +++ b/vcl/inc/qt5/QtVirtualDevice.hxx @@ -44,7 +44,8 @@ public: virtual SalGraphics* AcquireGraphics() override; virtual void ReleaseGraphics(SalGraphics* pGraphics) override; - virtual bool SetSize(tools::Long nNewDX, tools::Long nNewDY) override; + virtual bool SetSize(tools::Long nNewDX, tools::Long nNewDY, + bool bAlphaMaskTransparent) override; // SalGeometryProvider virtual tools::Long GetWidth() const override; diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index 0b8e01b569ba..c3213832f5a7 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -146,13 +146,13 @@ struct AquaSharedAttributes bool checkContext(); void setState(); - bool isPenVisible() const + bool isPenActive() const { - return maLineColor.IsVisible(); + return maLineColor.IsActive(); } - bool isBrushVisible() const + bool isBrushActive() const { - return maFillColor.IsVisible(); + return maFillColor.IsActive(); } void refreshRect(float lX, float lY, float lWidth, float lHeight) @@ -331,7 +331,7 @@ public: Color nMaskColor) override; std::shared_ptr getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight) override; + tools::Long nHeight, bool bWithoutAlpha) override; Color getPixel(tools::Long nX, tools::Long nY) override; diff --git a/vcl/inc/quartz/salgdicommon.hxx b/vcl/inc/quartz/salgdicommon.hxx index 3cd0845b0671..b5d2ee58bc8b 100644 --- a/vcl/inc/quartz/salgdicommon.hxx +++ b/vcl/inc/quartz/salgdicommon.hxx @@ -39,7 +39,8 @@ public: RGBAColor( ::Color ); RGBAColor( float fRed, float fGreen, float fBlue, float fAlpha ); //NOTUSEDYET const CGFloat* AsArray() const { return m_fRGBA; } - bool IsVisible() const { return m_fRGBA[3] > 0; } + bool IsActive() const { return m_bActive; } + void SetActive(bool b) { m_bActive = b; } void SetAlpha( float fAlpha ) { m_fRGBA[3] = fAlpha; } CGFloat GetRed() const { return m_fRGBA[0]; } @@ -47,6 +48,7 @@ public: CGFloat GetBlue() const { return m_fRGBA[2]; } CGFloat GetAlpha() const { return m_fRGBA[3]; } private: + bool m_bActive { true }; CGFloat m_fRGBA[4]; // red, green, blue, alpha }; @@ -55,7 +57,7 @@ inline RGBAColor::RGBAColor( ::Color nColor ) m_fRGBA[0] = nColor.GetRed() * (1.0/255); m_fRGBA[1] = nColor.GetGreen() * (1.0/255); m_fRGBA[2] = nColor.GetBlue() * (1.0/255); - m_fRGBA[3] = 1.0; // opaque + m_fRGBA[3] = nColor.GetAlpha() * (1.0/255); } inline RGBAColor::RGBAColor( float fRed, float fGreen, float fBlue, float fAlpha ) diff --git a/vcl/inc/quartz/salvd.h b/vcl/inc/quartz/salvd.h index a489dc9662fa..a0ccdac64607 100644 --- a/vcl/inc/quartz/salvd.h +++ b/vcl/inc/quartz/salvd.h @@ -51,13 +51,13 @@ private: void Destroy(); public: - AquaSalVirtualDevice( AquaSalGraphics* pGraphic, tools::Long nDX, tools::Long nDY, DeviceFormat eFormat ); + AquaSalVirtualDevice( AquaSalGraphics* pGraphic, tools::Long nDX, tools::Long nDY, DeviceFormat eFormat, bool bAlphaMaskTransparent ); AquaSalVirtualDevice( tools::Long &nDX, tools::Long &nDY, DeviceFormat eFormat, const SystemGraphicsData& rData ); virtual ~AquaSalVirtualDevice() override; virtual SalGraphics* AcquireGraphics() override; virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; - virtual bool SetSize( tools::Long nNewDX, tools::Long nNewDY ) override; + virtual bool SetSize( tools::Long nNewDX, tools::Long nNewDY, bool bAlphaMaskTransparent ) override; tools::Long GetWidth() const override { diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx index a1e6ba238e0b..4bd2f31d487b 100644 --- a/vcl/inc/salgdi.hxx +++ b/vcl/inc/salgdi.hxx @@ -274,7 +274,8 @@ public: SAL_DLLPRIVATE std::shared_ptr GetBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, - const OutputDevice& rOutDev ); + const OutputDevice& rOutDev, + bool bWithoutAlpha ); SAL_DLLPRIVATE Color GetPixel( tools::Long nX, tools::Long nY, @@ -497,7 +498,7 @@ protected: const SalBitmap& rSalBitmap, Color nMaskColor ) = 0; - virtual std::shared_ptr getBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight ) = 0; + virtual std::shared_ptr getBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, bool bWithoutAlpha ) = 0; virtual Color getPixel( tools::Long nX, tools::Long nY ) = 0; @@ -812,9 +813,9 @@ public: GetImpl()->drawMask(rPosAry, rSalBitmap, nMaskColor); } - std::shared_ptr getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight) override + std::shared_ptr getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, bool bWithoutAlpha) override { - return GetImpl()->getBitmap(nX, nY, nWidth, nHeight); + return GetImpl()->getBitmap(nX, nY, nWidth, nHeight, bWithoutAlpha); } Color getPixel(tools::Long nX, tools::Long nY) override diff --git a/vcl/inc/salgdiimpl.hxx b/vcl/inc/salgdiimpl.hxx index f656b68058c8..54578b480f29 100644 --- a/vcl/inc/salgdiimpl.hxx +++ b/vcl/inc/salgdiimpl.hxx @@ -163,7 +163,7 @@ public: const SalBitmap& rSalBitmap, Color nMaskColor ) = 0; - virtual std::shared_ptr getBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight ) = 0; + virtual std::shared_ptr getBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, bool bWithoutAlpha ) = 0; virtual Color getPixel( tools::Long nX, tools::Long nY ) = 0; diff --git a/vcl/inc/salinst.hxx b/vcl/inc/salinst.hxx index 15ef93c6236d..a31e09cd6530 100644 --- a/vcl/inc/salinst.hxx +++ b/vcl/inc/salinst.hxx @@ -82,14 +82,12 @@ private: css::uno::Reference m_clipboard; protected: - bool m_bSupportsBitmap32 = false; bool m_bSupportsOpenGL = false; public: SalInstance(std::unique_ptr pMutex); virtual ~SalInstance(); - bool supportsBitmap32() const { return m_bSupportsBitmap32; } bool supportsOpenGL() const { return m_bSupportsOpenGL; } //called directly after Application::Init @@ -114,7 +112,8 @@ public: virtual std::unique_ptr CreateVirtualDevice( SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat ) = 0; + DeviceFormat eFormat, + bool bAlphaMaskTransparent = false ) = 0; // VirtualDevice // nDX and nDY in pixels diff --git a/vcl/inc/salvd.hxx b/vcl/inc/salvd.hxx index 1f6bb9c201bd..390c2dfe6a7f 100644 --- a/vcl/inc/salvd.hxx +++ b/vcl/inc/salvd.hxx @@ -40,13 +40,13 @@ public: virtual void ReleaseGraphics( SalGraphics* pGraphics ) = 0; // Set new size, without saving the old contents - virtual bool SetSize( tools::Long nNewDX, tools::Long nNewDY ) = 0; + virtual bool SetSize( tools::Long nNewDX, tools::Long nNewDY, bool bAlphaMaskTransparent ) = 0; // Set new size using a buffer at the given address virtual bool SetSizeUsingBuffer( tools::Long /*nNewDX*/, tools::Long /*nNewDY*/, sal_uInt8 * /*pBuffer*/) { - // Only the headless virtual device has an implementation. + // Only the headless/svp virtual device has an implementation. assert(false && "unsupported"); return false; } diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx index 9389e8426f94..ff11958f30bc 100644 --- a/vcl/inc/skia/gdiimpl.hxx +++ b/vcl/inc/skia/gdiimpl.hxx @@ -139,7 +139,7 @@ public: Color nMaskColor) override; virtual std::shared_ptr getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight) override; + tools::Long nHeight, bool bWithoutAlpha) override; virtual Color getPixel(tools::Long nX, tools::Long nY) override; @@ -387,6 +387,8 @@ inline SkPaint SkiaSalGraphicsImpl::makePaintInternal() const SkiaHelper::setBlenderInvert(&paint); else if (mXorMode == XorMode::Xor) SkiaHelper::setBlenderXor(&paint); + else + paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha return paint; } @@ -415,7 +417,19 @@ inline SkPaint SkiaSalGraphicsImpl::makeFillPaint(double transparency) const return paint; } -inline SkPaint SkiaSalGraphicsImpl::makeBitmapPaint() const { return makePaintInternal(); } +inline SkPaint SkiaSalGraphicsImpl::makeBitmapPaint() const +{ + SkPaint paint; + // Invert could be done using a blend mode like invert() does, but + // intentionally use SkBlender to make sure it's not overwritten + // by a blend mode set later (which would be probably a mistake), + // and so that the drawing color does not actually matter. + if (mXorMode == XorMode::Invert) + SkiaHelper::setBlenderInvert(&paint); + else if (mXorMode == XorMode::Xor) + SkiaHelper::setBlenderXor(&paint); + return paint; +} inline SkPaint SkiaSalGraphicsImpl::makeGradientPaint() const { return makePaintInternal(); } diff --git a/vcl/inc/skia/salbmp.hxx b/vcl/inc/skia/salbmp.hxx index dd6225649c55..449516759d6d 100644 --- a/vcl/inc/skia/salbmp.hxx +++ b/vcl/inc/skia/salbmp.hxx @@ -32,7 +32,7 @@ class VCL_PLUGIN_PUBLIC SkiaSalBitmap final : public SalBitmap { public: SkiaSalBitmap(); - SkiaSalBitmap(const sk_sp& image); + SkiaSalBitmap(const sk_sp& image, bool bWithoutAlpha); virtual ~SkiaSalBitmap() override; // SalBitmap methods @@ -199,6 +199,7 @@ private: BitmapPalette mPalette; int mBitCount = 0; // bpp + bool m_bWithoutAlpha = false; Size mSize; // The contents of the bitmap may be stored in several different ways: // As mBuffer buffer, which normally stores pixels in the given format. diff --git a/vcl/inc/skia/x11/salvd.hxx b/vcl/inc/skia/x11/salvd.hxx index 1cb14d5de47a..fcdc2925b4ea 100644 --- a/vcl/inc/skia/x11/salvd.hxx +++ b/vcl/inc/skia/x11/salvd.hxx @@ -41,7 +41,8 @@ public: virtual void ReleaseGraphics(SalGraphics* pGraphics) override; // Set new size, without saving the old contents - virtual bool SetSize(tools::Long nNewDX, tools::Long nNewDY) override; + virtual bool SetSize(tools::Long nNewDX, tools::Long nNewDY, + bool bAlphaMaskTransparent) override; }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/gtkinst.hxx b/vcl/inc/unx/gtk/gtkinst.hxx index 3834768355c7..02528e12d699 100644 --- a/vcl/inc/unx/gtk/gtkinst.hxx +++ b/vcl/inc/unx/gtk/gtkinst.hxx @@ -248,7 +248,8 @@ public: virtual std::unique_ptr CreateVirtualDevice( SalGraphics&, tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat ) override; + DeviceFormat eFormat, + bool bAlphaMaskTransparent = false ) override; virtual std::unique_ptr CreateVirtualDevice( SalGraphics&, tools::Long &nDX, tools::Long &nDY, diff --git a/vcl/inc/unx/salinst.h b/vcl/inc/unx/salinst.h index 2d6deb0c76d1..9431ec6d86c5 100644 --- a/vcl/inc/unx/salinst.h +++ b/vcl/inc/unx/salinst.h @@ -51,14 +51,16 @@ public: /// Gtk vclplug needs to pass GtkSalGraphics to X11SalVirtualDevice, so create it, and pass as pNewGraphics. static std::unique_ptr CreateX11VirtualDevice(const SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat, std::unique_ptr pNewGraphics); + DeviceFormat eFormat, std::unique_ptr pNewGraphics, + bool bAlphaMaskTransparent); static std::unique_ptr CreateX11VirtualDevice(const SalGraphics& rGraphics, tools::Long &nDX, tools::Long &nDY, DeviceFormat eFormat, const SystemGraphicsData& rData, std::unique_ptr pNewGraphics); virtual std::unique_ptr CreateVirtualDevice( SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat ) override; + DeviceFormat eFormat, + bool bAlphaMaskTransparent = false ) override; virtual std::unique_ptr CreateVirtualDevice( SalGraphics& rGraphics, tools::Long &nDX, tools::Long &nDY, diff --git a/vcl/inc/unx/salvd.h b/vcl/inc/unx/salvd.h index 268ce719fbe4..a0cfb1b30105 100644 --- a/vcl/inc/unx/salvd.h +++ b/vcl/inc/unx/salvd.h @@ -73,7 +73,7 @@ public: virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; /// Set new size, without saving the old contents - virtual bool SetSize( tools::Long nNewDX, tools::Long nNewDY ) override; + virtual bool SetSize( tools::Long nNewDX, tools::Long nNewDY, bool bAlphaMaskTransparent ) override; // SalGeometryProvider virtual tools::Long GetWidth() const override { return nDX_; } diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index 65988c2867d4..2423af293539 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -262,7 +262,7 @@ protected: const SalBitmap& rSalBitmap, Color nMaskColor ) override; - virtual std::shared_ptr getBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight ) override; + virtual std::shared_ptr getBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, bool bWithoutAlpha ) override; virtual Color getPixel( tools::Long nX, tools::Long nY ) override; // invert --> ClipRegion (only Windows or VirDevs) diff --git a/vcl/inc/win/salinst.h b/vcl/inc/win/salinst.h index a603aa7fcef0..0a0f133df89e 100644 --- a/vcl/inc/win/salinst.h +++ b/vcl/inc/win/salinst.h @@ -52,7 +52,8 @@ public: virtual std::unique_ptr CreateVirtualDevice( SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat ) override; + DeviceFormat eFormat, + bool bAlphaMaskTransparent = false ) override; virtual std::unique_ptr CreateVirtualDevice( SalGraphics& rGraphics, tools::Long &nDX, tools::Long &nDY, diff --git a/vcl/inc/win/salvd.h b/vcl/inc/win/salvd.h index 530fe4fb4cad..564a468c86d8 100644 --- a/vcl/inc/win/salvd.h +++ b/vcl/inc/win/salvd.h @@ -54,9 +54,10 @@ public: virtual SalGraphics* AcquireGraphics() override; virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; - virtual bool SetSize( tools::Long nNewDX, tools::Long nNewDY ) override; + virtual bool SetSize( tools::Long nNewDX, tools::Long nNewDY, bool bAlphaMaskTransparent ) override; - static HBITMAP ImplCreateVirDevBitmap(HDC hDC, tools::Long nDX, tools::Long nDY, sal_uInt16 nBitCount, void **ppDummy); + static HBITMAP ImplCreateVirDevBitmap(HDC hDC, tools::Long nDX, tools::Long nDY, sal_uInt16 nBitCount, + void **ppDummy, bool bAlphaMaskTransparent = false); // SalGeometryProvider virtual tools::Long GetWidth() const override { return mnWidth; } diff --git a/vcl/inc/windowdev.hxx b/vcl/inc/windowdev.hxx index 013cfbc69cd0..13522ae0fe23 100644 --- a/vcl/inc/windowdev.hxx +++ b/vcl/inc/windowdev.hxx @@ -62,6 +62,8 @@ public: virtual css::uno::Reference ImplGetCanvas(bool bSpriteCanvas) const override; + virtual bool HasAlpha() const override { return true; } + private: virtual void InitClipRegion() override; diff --git a/vcl/osx/salmacos.cxx b/vcl/osx/salmacos.cxx index 14e2a80695d9..ce2a12d82095 100644 --- a/vcl/osx/salmacos.cxx +++ b/vcl/osx/salmacos.cxx @@ -126,7 +126,8 @@ void AquaGraphicsBackend::copyBits(const SalTwoRect &rPosAry, SalGraphics *pSrcG mrShared.applyXorContext(); pSrcShared->applyXorContext(); std::shared_ptr pBitmap = pSrcGraphics->GetImpl()->getBitmap(rPosAry.mnSrcX, rPosAry.mnSrcY, - rPosAry.mnSrcWidth, rPosAry.mnSrcHeight); + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, + /*bWithoutAlpha*/false); if (pBitmap) { SalTwoRect aPosAry(rPosAry); @@ -460,7 +461,7 @@ void AquaSalVirtualDevice::Destroy() } } -bool AquaSalVirtualDevice::SetSize(tools::Long nDX, tools::Long nDY) +bool AquaSalVirtualDevice::SetSize(tools::Long nDX, tools::Long nDY, bool bAlphaMaskTransparent) { SAL_INFO("vcl.virdev", "AquaSalVirtualDevice::SetSize() this=" << this << " (" << nDX << "x" << nDY << ") mbForeignContext=" << (mbForeignContext ? "YES" : "NO")); @@ -504,7 +505,7 @@ bool AquaSalVirtualDevice::SetSize(tools::Long nDX, tools::Long nDY) mnBitmapDepth = 32; aColorSpace = GetSalData()->mxRGBSpace; - nFlags = uint32_t(kCGImageAlphaNoneSkipFirst) | uint32_t(kCGBitmapByteOrder32Host); + nFlags = uint32_t(kCGImageAlphaPremultipliedFirst) | uint32_t(kCGBitmapByteOrder32Host); } if (SkiaHelper::isVCLSkiaEnabled()) @@ -520,6 +521,24 @@ bool AquaSalVirtualDevice::SetSize(tools::Long nDX, tools::Long nDY) size_t nBytesPerRow = mnBitmapDepth * nScaledWidth / 8; maBitmapContext.set(CGBitmapContextCreate(nullptr, nScaledWidth, nScaledHeight, 8, nBytesPerRow, aColorSpace, nFlags)); + if (mnBitmapDepth == 32) + { + if (bAlphaMaskTransparent) + { + CGColorRef transparentCol = CGColorCreateGenericRGB(0, 0, 0, 0); + CGContextSetFillColorWithColor(maBitmapContext.get(), transparentCol); + CGContextFillRect(maBitmapContext.get(), CGRectMake(0, 0, nScaledWidth, nScaledHeight)); + CGColorRelease(transparentCol); + } + else + { + CGColorRef opaqueCol = CGColorCreateGenericRGB(0, 0, 0, 1.0); + CGContextSetFillColorWithColor(maBitmapContext.get(), opaqueCol); + CGContextFillRect(maBitmapContext.get(), CGRectMake(0, 0, nScaledWidth, nScaledHeight)); + CGColorRelease(opaqueCol); + } + } + SAL_INFO("vcl.virdev", "AquaSalVirtualDevice::SetSize() this=" << this << " fScale=" << fScale << " mnBitmapDepth=" << mnBitmapDepth); diff --git a/vcl/qa/cppunit/BackendTest.cxx b/vcl/qa/cppunit/BackendTest.cxx index 4c2ae7cfcfd7..d26248151fb7 100644 --- a/vcl/qa/cppunit/BackendTest.cxx +++ b/vcl/qa/cppunit/BackendTest.cxx @@ -61,8 +61,6 @@ class BackendTest : public test::BootstrapFixture } } - bool is32bppSupported() { return ImplGetSVData()->mpDefInst->supportsBitmap32(); } - public: BackendTest() : BootstrapFixture(true, false) @@ -543,7 +541,7 @@ public: Bitmap aBitmap = aOutDevTest.setupDrawBitmap(vcl::PixelFormat::N32_BPP); exportImage(u"09-01_bitmap_test_32bpp.png"_ustr, aBitmap); auto eResult = vcl::test::OutputDeviceTestBitmap::checkTransformedBitmap(aBitmap); - if (SHOULD_ASSERT && is32bppSupported()) + if (SHOULD_ASSERT) CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); } @@ -555,7 +553,7 @@ public: Bitmap aBitmap = aOutDevTest.setupDrawTransformedBitmap(vcl::PixelFormat::N32_BPP); auto eResult = vcl::test::OutputDeviceTestBitmap::checkTransformedBitmap(aBitmap); exportImage(u"09-02_transformed_bitmap_test_32bpp.png"_ustr, aBitmap); - if (SHOULD_ASSERT && is32bppSupported()) + if (SHOULD_ASSERT) CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); } @@ -567,7 +565,7 @@ public: Bitmap aBitmap = aOutDevTest.setupDrawBitmapExWithAlpha(vcl::PixelFormat::N32_BPP); auto eResult = vcl::test::OutputDeviceTestBitmap::checkBitmapExWithAlpha(aBitmap); exportImage(u"09-03_bitmapex_with_alpha_test_32bpp.png"_ustr, aBitmap); - if (SHOULD_ASSERT && is32bppSupported()) + if (SHOULD_ASSERT) CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); } @@ -579,7 +577,7 @@ public: Bitmap aBitmap = aOutDevTest.setupDrawMask(vcl::PixelFormat::N32_BPP); auto eResult = vcl::test::OutputDeviceTestBitmap::checkMask(aBitmap); exportImage(u"09-04_mask_test_32bpp.png"_ustr, aBitmap); - if (SHOULD_ASSERT && is32bppSupported()) + if (SHOULD_ASSERT) CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); } @@ -591,7 +589,7 @@ public: BitmapEx aBitmapEx = aOutDevTest.setupDrawBlend(vcl::PixelFormat::N32_BPP); auto eResult = vcl::test::OutputDeviceTestBitmap::checkBlend(aBitmapEx); exportImage(u"09-05_blend_test_32bpp.png"_ustr, aBitmapEx); - if (SHOULD_ASSERT && is32bppSupported()) + if (SHOULD_ASSERT) CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); } diff --git a/vcl/qa/cppunit/BitmapExTest.cxx b/vcl/qa/cppunit/BitmapExTest.cxx index 56b91afe5049..517d7574accf 100644 --- a/vcl/qa/cppunit/BitmapExTest.cxx +++ b/vcl/qa/cppunit/BitmapExTest.cxx @@ -58,11 +58,6 @@ void BitmapExTest::testGetPixelColor24_8() void BitmapExTest::testGetPixelColor32() { - // Check backend capabilities and return from the test successfully - // if the backend doesn't support 32-bit bitmap - if (!ImplGetSVData()->mpDefInst->supportsBitmap32()) - return; - Bitmap aBitmap(Size(3, 3), vcl::PixelFormat::N32_BPP); { BitmapScopedWriteAccess pWriteAccess(aBitmap); diff --git a/vcl/qa/cppunit/BitmapTest.cxx b/vcl/qa/cppunit/BitmapTest.cxx index 0534718ed14b..f280ed05f3ba 100644 --- a/vcl/qa/cppunit/BitmapTest.cxx +++ b/vcl/qa/cppunit/BitmapTest.cxx @@ -115,8 +115,6 @@ void BitmapTest::testCreation() } // Check backend capabilities and return from the test successfully - // if the backend doesn't support 32-bit bitmap - if (ImplGetSVData()->mpDefInst->supportsBitmap32()) { Bitmap aBmp(Size(10, 10), vcl::PixelFormat::N32_BPP); Size aSize = aBmp.GetSizePixel(); @@ -482,11 +480,6 @@ void BitmapTest::testErase() void BitmapTest::testBitmap32() { - // Check backend capabilities and return from the test successfully - // if the backend doesn't support 32-bit bitmap - if (!ImplGetSVData()->mpDefInst->supportsBitmap32()) - return; - Bitmap aBitmap(Size(3, 3), vcl::PixelFormat::N32_BPP); { BitmapScopedWriteAccess pWriteAccess(aBitmap); diff --git a/vcl/qa/cppunit/animationrenderer.cxx b/vcl/qa/cppunit/animationrenderer.cxx index aa5edcc5dff2..b6f0b53dd249 100644 --- a/vcl/qa/cppunit/animationrenderer.cxx +++ b/vcl/qa/cppunit/animationrenderer.cxx @@ -31,6 +31,7 @@ public: void ReleaseGraphics(bool) override {} bool UsePolyPolygonForComplexGradient() override { return false; } bool CanAnimate() const override { return false; } + virtual bool HasAlpha() const override { return false; } }; Animation createAnimation() diff --git a/vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx b/vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx index 4ec0e62527d5..65e0db417084 100644 --- a/vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx +++ b/vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx @@ -146,17 +146,9 @@ void BitmapRenderTest::testDrawAlphaBitmapEx() BitmapEx aBitmapEx; aPngReader.read(aBitmapEx); - // Check backend capabilities, if the backend support 32-bit bitmap - if (ImplGetSVData()->mpDefInst->supportsBitmap32()) - { - CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N32_BPP, aBitmapEx.GetBitmap().getPixelFormat()); - } - else - { - CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N24_BPP, aBitmapEx.GetBitmap().getPixelFormat()); - CPPUNIT_ASSERT_EQUAL(true, aBitmapEx.IsAlpha()); - CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP, aBitmapEx.GetAlphaMask().getPixelFormat()); - } + CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N24_BPP, aBitmapEx.GetBitmap().getPixelFormat()); + CPPUNIT_ASSERT_EQUAL(true, aBitmapEx.IsAlpha()); + CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N8_BPP, aBitmapEx.GetAlphaMask().getPixelFormat()); // Check the bitmap has pixels we expect CPPUNIT_ASSERT_EQUAL(Color(ColorTransparency, 0xFF, 0x00, 0x00, 0x00), @@ -190,15 +182,21 @@ void BitmapRenderTest::testAlphaVirtualDevice() // Set it up pAlphaVirtualDevice->SetOutputSizePixel(Size(4, 4)); + CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xff, 0xff, 0xff, 0xff), + pAlphaVirtualDevice->GetPixel(Point(1, 1))); pAlphaVirtualDevice->SetBackground(Wallpaper(COL_TRANSPARENT)); pAlphaVirtualDevice->Erase(); + // the backends use pre-multipled alpha, so pure transparency does not round-trip properly + CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0x00, 0x00, 0x00, 0x00), + pAlphaVirtualDevice->GetPixel(Point(1, 1))); // Get a BitmapEx from the VirDev -> Colors should have alpha BitmapEx aBitmap = pAlphaVirtualDevice->GetBitmapEx(Point(), Size(4, 4)); CPPUNIT_ASSERT_EQUAL(tools::Long(4), aBitmap.GetSizePixel().Width()); CPPUNIT_ASSERT_EQUAL(tools::Long(4), aBitmap.GetSizePixel().Height()); Color aColor = aBitmap.GetPixelColor(1, 1); - CPPUNIT_ASSERT_EQUAL(COL_TRANSPARENT, aColor); + // the backends use pre-multipled alpha, so pure transparency does not round-trip properly + CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0x00, 0x00, 0x00, 0x00), aColor); // Draw an opaque pixel to the VirDev pAlphaVirtualDevice->DrawPixel(Point(1, 1), Color(0x0022ff55)); diff --git a/vcl/qa/cppunit/outdev.cxx b/vcl/qa/cppunit/outdev.cxx index d0cb54376728..82972b64e6cc 100644 --- a/vcl/qa/cppunit/outdev.cxx +++ b/vcl/qa/cppunit/outdev.cxx @@ -890,6 +890,7 @@ public: void ReleaseGraphics(bool) override {} bool UsePolyPolygonForComplexGradient() override { return false; } bool CanAnimate() const override { return false; } + virtual bool HasAlpha() const override { return false; } bool testShouldDrawWavePixelAsRect(tools::Long nLineWidth) { diff --git a/vcl/qa/cppunit/skia/skia.cxx b/vcl/qa/cppunit/skia/skia.cxx index fbe3899cb4f8..bb40421f5df5 100644 --- a/vcl/qa/cppunit/skia/skia.cxx +++ b/vcl/qa/cppunit/skia/skia.cxx @@ -365,7 +365,7 @@ void SkiaTest::testDelayedScale() CPPUNIT_ASSERT_EQUAL(tools::Long(20), buffer1->mnHeight); skiaBitmap1->ReleaseBuffer(buffer1, BitmapAccessMode::Read); // Do scaling based on mImage. - SkiaSalBitmap skiaBitmap2(skiaBitmap1->GetSkImage()); + SkiaSalBitmap skiaBitmap2(skiaBitmap1->GetSkImage(), /*bWithoutAlpha*/ false); CPPUNIT_ASSERT(!skiaBitmap2.unittestHasBuffer()); CPPUNIT_ASSERT(skiaBitmap2.unittestHasImage()); CPPUNIT_ASSERT(skiaBitmap2.Scale(2, 3, BmpScaleFlag::Default)); @@ -388,7 +388,7 @@ void SkiaTest::testDelayedScaleAlphaImage() CPPUNIT_ASSERT(bitmapTmp->Create(Size(10, 10), vcl::PixelFormat::N24_BPP, BitmapPalette())); bitmapTmp->Erase(COL_RED); // Create a bitmap that has only an image, not a pixel buffer. - SkiaSalBitmap bitmap(bitmapTmp->GetSkImage()); + SkiaSalBitmap bitmap(bitmapTmp->GetSkImage(), /*bWithoutAlpha*/ false); bitmapTmp.release(); CPPUNIT_ASSERT(!bitmap.unittestHasBuffer()); CPPUNIT_ASSERT(bitmap.unittestHasImage()); diff --git a/vcl/qt5/QtBitmap.cxx b/vcl/qt5/QtBitmap.cxx index a69ee562046b..9bf28b1492cc 100644 --- a/vcl/qt5/QtBitmap.cxx +++ b/vcl/qt5/QtBitmap.cxx @@ -136,13 +136,9 @@ BitmapBuffer* QtBitmap::AcquireBuffer(BitmapAccessMode /*nMode*/) case 32: { #ifdef OSL_BIGENDIAN - pBuffer->meFormat = ImplGetSVData()->mpDefInst->supportsBitmap32() - ? ScanlineFormat::N32BitTcArgb - : ScanlineFormat::N32BitTcXrgb; + pBuffer->meFormat = ScanlineFormat::N32BitTcArgb; #else - pBuffer->meFormat = ImplGetSVData()->mpDefInst->supportsBitmap32() - ? ScanlineFormat::N32BitTcBgra - : ScanlineFormat::N32BitTcBgrx; + pBuffer->meFormat = ScanlineFormat::N32BitTcBgra; #endif pBuffer->maPalette = aEmptyPalette; break; diff --git a/vcl/qt5/QtGraphics_GDI.cxx b/vcl/qt5/QtGraphics_GDI.cxx index 4cc10454ce6b..70a78086545f 100644 --- a/vcl/qt5/QtGraphics_GDI.cxx +++ b/vcl/qt5/QtGraphics_GDI.cxx @@ -523,8 +523,11 @@ void QtGraphicsBackend::drawMask(const SalTwoRect& rPosAry, const SalBitmap& /*r } std::shared_ptr QtGraphicsBackend::getBitmap(tools::Long nX, tools::Long nY, - tools::Long nWidth, tools::Long nHeight) + tools::Long nWidth, tools::Long nHeight, + bool bWithoutAlpha) { + assert(!bWithoutAlpha && "not supported here"); + (void)bWithoutAlpha; return std::make_shared(m_pQImage->copy(nX, nY, nWidth, nHeight)); } diff --git a/vcl/qt5/QtInstance.cxx b/vcl/qt5/QtInstance.cxx index cb65d7b3e974..ed37179fb471 100644 --- a/vcl/qt5/QtInstance.cxx +++ b/vcl/qt5/QtInstance.cxx @@ -404,7 +404,8 @@ void QtInstance::DestroyObject(SalObject* pObject) std::unique_ptr QtInstance::CreateVirtualDevice(SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat /*eFormat*/) + DeviceFormat /*eFormat*/, + bool bAlphaMaskTransparent) { if (m_bUseCairo) { @@ -413,13 +414,13 @@ std::unique_ptr QtInstance::CreateVirtualDevice(SalGraphics& r // tdf#127529 see SvpSalInstance::CreateVirtualDevice for the rare case of a non-null pPreExistingTarget std::unique_ptr pVD( new QtSvpVirtualDevice(pSvpSalGraphics->getSurface(), /*pPreExistingTarget*/ nullptr)); - pVD->SetSize(nDX, nDY); + pVD->SetSize(nDX, nDY, bAlphaMaskTransparent); return pVD; } else { std::unique_ptr pVD(new QtVirtualDevice(/*scale*/ 1)); - pVD->SetSize(nDX, nDY); + pVD->SetSize(nDX, nDY, bAlphaMaskTransparent); return pVD; } } @@ -436,13 +437,13 @@ QtInstance::CreateVirtualDevice(SalGraphics& rGraphics, tools::Long& nDX, tools: cairo_surface_t* pPreExistingTarget = static_cast(rGd.pSurface); std::unique_ptr pVD( new QtSvpVirtualDevice(pSvpSalGraphics->getSurface(), pPreExistingTarget)); - pVD->SetSize(nDX, nDY); + pVD->SetSize(nDX, nDY, /*bAlphaMaskTransparent*/ false); return pVD; } else { std::unique_ptr pVD(new QtVirtualDevice(/*scale*/ 1)); - pVD->SetSize(nDX, nDY); + pVD->SetSize(nDX, nDY, /*bAlphaMaskTransparent*/ false); return pVD; } } diff --git a/vcl/qt5/QtVirtualDevice.cxx b/vcl/qt5/QtVirtualDevice.cxx index c52316eeb7c5..de3a96d5773c 100644 --- a/vcl/qt5/QtVirtualDevice.cxx +++ b/vcl/qt5/QtVirtualDevice.cxx @@ -43,8 +43,11 @@ void QtVirtualDevice::ReleaseGraphics(SalGraphics* pGraphics) delete pGraphics; } -bool QtVirtualDevice::SetSize(tools::Long nNewDX, tools::Long nNewDY) +bool QtVirtualDevice::SetSize(tools::Long nNewDX, tools::Long nNewDY, bool bAlphaMaskTransparent) { + assert(!bAlphaMaskTransparent && "TODO"); + (void)bAlphaMaskTransparent; + if (nNewDX == 0) nNewDX = 1; if (nNewDY == 0) diff --git a/vcl/quartz/AquaGraphicsBackend.cxx b/vcl/quartz/AquaGraphicsBackend.cxx index f6d1134072c6..507ee139a043 100644 --- a/vcl/quartz/AquaGraphicsBackend.cxx +++ b/vcl/quartz/AquaGraphicsBackend.cxx @@ -270,12 +270,12 @@ tools::Long AquaGraphicsBackend::GetGraphicsWidth() const void AquaGraphicsBackend::SetLineColor() { - mrShared.maLineColor.SetAlpha(0.0); // transparent + mrShared.maLineColor.SetActive(false); if (mrShared.checkContext()) { CGContextSetRGBStrokeColor(mrShared.maContextHolder.get(), mrShared.maLineColor.GetRed(), mrShared.maLineColor.GetGreen(), mrShared.maLineColor.GetBlue(), - mrShared.maLineColor.GetAlpha()); + 0.0); // alpha, transparent } } @@ -292,12 +292,12 @@ void AquaGraphicsBackend::SetLineColor(Color nColor) void AquaGraphicsBackend::SetFillColor() { - mrShared.maFillColor.SetAlpha(0.0); // transparent + mrShared.maFillColor.SetActive(false); if (mrShared.checkContext()) { CGContextSetRGBFillColor(mrShared.maContextHolder.get(), mrShared.maFillColor.GetRed(), mrShared.maFillColor.GetGreen(), mrShared.maFillColor.GetBlue(), - mrShared.maFillColor.GetAlpha()); + 0.0); // alpha, transparent } } @@ -444,7 +444,7 @@ void AquaGraphicsBackend::drawRect(tools::Long nX, tools::Long nY, tools::Long n return; CGRect aRect = CGRectMake(nX, nY, nWidth, nHeight); - if (mrShared.isPenVisible()) + if (mrShared.isPenActive()) { aRect.origin.x += 0.5; aRect.origin.y += 0.5; @@ -452,13 +452,22 @@ void AquaGraphicsBackend::drawRect(tools::Long nX, tools::Long nY, tools::Long n aRect.size.height -= 1; } - if (mrShared.isBrushVisible()) + if (mrShared.isBrushActive() && mrShared.maFillColor.GetAlpha() == 0) { - CGContextFillRect(mrShared.maContextHolder.get(), aRect); + CGContextSetBlendMode(mrShared.maContextHolder.get(), kCGBlendModeClear); + CGContextClearRect(mrShared.maContextHolder.get(), aRect); + CGContextSetBlendMode(mrShared.maContextHolder.get(), kCGBlendModeNormal); } - if (mrShared.isPenVisible()) + else { - CGContextStrokeRect(mrShared.maContextHolder.get(), aRect); + if (mrShared.isBrushActive()) + { + CGContextFillRect(mrShared.maContextHolder.get(), aRect); + } + if (mrShared.isPenActive()) + { + CGContextStrokeRect(mrShared.maContextHolder.get(), aRect); + } } mrShared.refreshRect(nX, nY, nWidth, nHeight); } @@ -502,15 +511,15 @@ void AquaGraphicsBackend::drawPolygon(sal_uInt32 nPoints, const Point* pPointArr getBoundRect(nPoints, pPointArray, nX, nY, nWidth, nHeight); CGPathDrawingMode eMode; - if (mrShared.isBrushVisible() && mrShared.isPenVisible()) + if (mrShared.isBrushActive() && mrShared.isPenActive()) { eMode = kCGPathEOFillStroke; } - else if (mrShared.isPenVisible()) + else if (mrShared.isPenActive()) { eMode = kCGPathStroke; } - else if (mrShared.isBrushVisible()) + else if (mrShared.isBrushActive()) { eMode = kCGPathEOFill; } @@ -522,7 +531,7 @@ void AquaGraphicsBackend::drawPolygon(sal_uInt32 nPoints, const Point* pPointArr CGContextBeginPath(mrShared.maContextHolder.get()); - if (mrShared.isPenVisible()) + if (mrShared.isPenActive()) { float fX, fY; alignLinePoint(pPointArray, fX, fY); @@ -592,15 +601,15 @@ void AquaGraphicsBackend::drawPolyPolygon(sal_uInt32 nPolyCount, const sal_uInt3 // prepare drawing mode CGPathDrawingMode eMode; - if (mrShared.isBrushVisible() && mrShared.isPenVisible()) + if (mrShared.isBrushActive() && mrShared.isPenActive()) { eMode = kCGPathEOFillStroke; } - else if (mrShared.isPenVisible()) + else if (mrShared.isPenActive()) { eMode = kCGPathStroke; } - else if (mrShared.isBrushVisible()) + else if (mrShared.isBrushActive()) { eMode = kCGPathEOFill; } @@ -612,7 +621,7 @@ void AquaGraphicsBackend::drawPolyPolygon(sal_uInt32 nPolyCount, const sal_uInt3 // convert to CGPath CGContextBeginPath(mrShared.maContextHolder.get()); - if (mrShared.isPenVisible()) + if (mrShared.isPenActive()) { for (sal_uInt32 nPoly = 0; nPoly < nPolyCount; nPoly++) { @@ -688,7 +697,7 @@ void AquaGraphicsBackend::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectTo // the transformation is not used here...) for (auto const& rPolygon : std::as_const(aPolyPolygon)) { - AddPolygonToPath(xPath, rPolygon, true, !getAntiAlias(), mrShared.isPenVisible()); + AddPolygonToPath(xPath, rPolygon, true, !getAntiAlias(), mrShared.isPenActive()); } const CGRect aRefreshRect = CGPathGetBoundingBox(xPath); @@ -697,15 +706,15 @@ void AquaGraphicsBackend::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectTo { // prepare drawing mode CGPathDrawingMode eMode; - if (mrShared.isBrushVisible() && mrShared.isPenVisible()) + if (mrShared.isBrushActive() && mrShared.isPenActive()) { eMode = kCGPathEOFillStroke; } - else if (mrShared.isPenVisible()) + else if (mrShared.isPenActive()) { eMode = kCGPathStroke; } - else if (mrShared.isBrushVisible()) + else if (mrShared.isBrushActive()) { eMode = kCGPathEOFill; } @@ -949,7 +958,8 @@ void AquaGraphicsBackend::drawMask(const SalTwoRect& rPosAry, const SalBitmap& r } std::shared_ptr AquaGraphicsBackend::getBitmap(tools::Long nX, tools::Long nY, - tools::Long nDX, tools::Long nDY) + tools::Long nDX, tools::Long nDY, + bool /*bWithoutAlpha*/) { SAL_WARN_IF(!mrShared.maLayer.isSet(), "vcl.quartz", "AquaSalGraphics::getBitmap() with no layer this=" << this); @@ -1006,7 +1016,7 @@ Color AquaGraphicsBackend::getPixel(tools::Long nX, tools::Long nY) CGContextRelease(xOnePixelContext); - Color nColor(aPixel.r, aPixel.g, aPixel.b); + Color nColor(ColorAlpha, aPixel.a, aPixel.r, aPixel.g, aPixel.b); return nColor; } @@ -1305,7 +1315,7 @@ bool AquaGraphicsBackend::drawAlphaRect(tools::Long nX, tools::Long nY, tools::L CGContextSetAlpha(mrShared.maContextHolder.get(), (100 - nTransparency) * (1.0 / 100)); CGRect aRect = CGRectMake(nX, nY, nWidth - 1, nHeight - 1); - if (mrShared.isPenVisible()) + if (mrShared.isPenActive()) { aRect.origin.x += 0.5; aRect.origin.y += 0.5; diff --git a/vcl/quartz/salbmp.cxx b/vcl/quartz/salbmp.cxx index 4c6c57874f04..7fc4ab50d15c 100644 --- a/vcl/quartz/salbmp.cxx +++ b/vcl/quartz/salbmp.cxx @@ -276,7 +276,7 @@ void QuartzSalBitmap::ConvertBitmapData( sal_uInt32 nWidth, sal_uInt32 nHeight, aSrcBuf.mnBitCount = nSrcBits; aSrcBuf.mnScanlineSize = nSrcBytesPerRow; BitmapBuffer aDstBuf; - aDstBuf.meFormat = ImplGetSVData()->mpDefInst->supportsBitmap32() ? ScanlineFormat::N32BitTcArgb : ScanlineFormat::N32BitTcXrgb; + aDstBuf.meFormat = ScanlineFormat::N32BitTcArgb; aDstBuf.mpBits = pDestData; aDstBuf.mnBitCount = nDestBits; aDstBuf.mnScanlineSize = nDestBytesPerRow; @@ -439,10 +439,8 @@ BitmapBuffer* QuartzSalBitmap::AcquireBuffer( BitmapAccessMode /*nMode*/ ) pBuffer->meFormat = ScanlineFormat::N24BitTcBgr; break; case 32: - { - pBuffer->meFormat = ImplGetSVData()->mpDefInst->supportsBitmap32() ? ScanlineFormat::N32BitTcArgb : ScanlineFormat::N32BitTcXrgb; + pBuffer->meFormat = ScanlineFormat::N32BitTcArgb; break; - } default: assert(false); } diff --git a/vcl/quartz/salvd.cxx b/vcl/quartz/salvd.cxx index b813f7c0421d..27b2c96fdd6f 100644 --- a/vcl/quartz/salvd.cxx +++ b/vcl/quartz/salvd.cxx @@ -39,19 +39,20 @@ std::unique_ptr AquaSalInstance::CreateVirtualDevice( SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat ) + DeviceFormat eFormat, + bool bAlphaMaskTransparent) { // #i92075# can be called first in a thread SalData::ensureThreadAutoreleasePool(); #ifdef IOS (void)rGraphics; - std::unique_ptr pNew(new AquaSalVirtualDevice( nullptr, nDX, nDY, eFormat )); + std::unique_ptr pNew(new AquaSalVirtualDevice( nullptr, nDX, nDY, eFormat, bAlphaMaskTransparent )); pNew->SetSize( nDX, nDY ); return pNew; #else return std::unique_ptr(new AquaSalVirtualDevice( static_cast< AquaSalGraphics* >(&rGraphics), - nDX, nDY, eFormat )); + nDX, nDY, eFormat, bAlphaMaskTransparent )); #endif } @@ -69,7 +70,7 @@ std::unique_ptr AquaSalInstance::CreateVirtualDevice( SalGraph AquaSalVirtualDevice::AquaSalVirtualDevice( AquaSalGraphics* pGraphic, tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat ) + DeviceFormat eFormat, bool bAlphaMaskTransparent ) : mbGraphicsUsed( false ) , mnBitmapDepth( 0 ) , mnWidth(0) @@ -109,7 +110,7 @@ AquaSalVirtualDevice::AquaSalVirtualDevice( #endif if( nDX && nDY ) { - SetSize( nDX, nDY ); + SetSize( nDX, nDY, bAlphaMaskTransparent ); } // NOTE: if SetSize does not succeed, we just ignore the nDX and nDY } diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index 52f8021785ef..9933350bc256 100644 --- a/vcl/skia/gdiimpl.cxx +++ b/vcl/skia/gdiimpl.cxx @@ -1452,7 +1452,8 @@ void SkiaSalGraphicsImpl::drawMask(const SalTwoRect& rPosAry, const SalBitmap& r } std::shared_ptr SkiaSalGraphicsImpl::getBitmap(tools::Long nX, tools::Long nY, - tools::Long nWidth, tools::Long nHeight) + tools::Long nWidth, tools::Long nHeight, + bool bWithoutAlpha) { SkiaZone zone; checkSurface(); @@ -1464,7 +1465,7 @@ std::shared_ptr SkiaSalGraphicsImpl::getBitmap(tools::Long nX, tools: // in blendAlphaBitmap(), where we could simply use the proper rect of the image. sk_sp image = makeCheckedImageSnapshot( mSurface, scaleRect(SkIRect::MakeXYWH(nX, nY, nWidth, nHeight), mScaling)); - std::shared_ptr bitmap = std::make_shared(image); + std::shared_ptr bitmap = std::make_shared(image, bWithoutAlpha); // If the surface is scaled for HiDPI, the bitmap needs to be scaled down, otherwise // it would have incorrect size from the API point of view. The DirectImage::Yes handling // in mergeCacheBitmaps() should access the original unscaled bitmap data to avoid diff --git a/vcl/skia/salbmp.cxx b/vcl/skia/salbmp.cxx index 6dee8b0b5252..c12d08bb9aac 100644 --- a/vcl/skia/salbmp.cxx +++ b/vcl/skia/salbmp.cxx @@ -58,16 +58,13 @@ SkiaSalBitmap::SkiaSalBitmap() {} SkiaSalBitmap::~SkiaSalBitmap() {} -SkiaSalBitmap::SkiaSalBitmap(const sk_sp& image) +SkiaSalBitmap::SkiaSalBitmap(const sk_sp& image, bool bWithoutAlpha) { ResetAllData(); mImage = image; mPalette = BitmapPalette(); -#if SKIA_USE_BITMAP32 mBitCount = 32; -#else - mBitCount = 24; -#endif + m_bWithoutAlpha = bWithoutAlpha; mSize = mPixelsSize = Size(image->width(), image->height()); ComputeScanlineSize(); mReadAccessCount = 0; @@ -300,14 +297,16 @@ BitmapBuffer* SkiaSalBitmap::AcquireBuffer(BitmapAccessMode nMode) : ScanlineFormat::N24BitTcRgb; break; case 32: -#if SKIA_USE_BITMAP32 - // this tracks the m_bSupportsBitmap32 field - buffer->meFormat = kN32_SkColorTypeIsBGRA ? ScanlineFormat::N32BitTcBgra - : ScanlineFormat::N32BitTcRgba; -#else - buffer->meFormat = kN32_SkColorTypeIsBGRA ? ScanlineFormat::N32BitTcBgrx - : ScanlineFormat::N32BitTcRgbx; -#endif + if (m_bWithoutAlpha) + { + buffer->meFormat = kN32_SkColorTypeIsBGRA ? ScanlineFormat::N32BitTcBgrx + : ScanlineFormat::N32BitTcRgbx; + } + else + { + buffer->meFormat = kN32_SkColorTypeIsBGRA ? ScanlineFormat::N32BitTcBgra + : ScanlineFormat::N32BitTcRgba; + } break; default: abort(); @@ -1125,12 +1124,8 @@ SkAlphaType SkiaSalBitmap::alphaType() const { if (mEraseColorSet) return mEraseColor.IsTransparent() ? kPremul_SkAlphaType : kOpaque_SkAlphaType; -#if SKIA_USE_BITMAP32 - // The bitmap's alpha matters only if SKIA_USE_BITMAP32 is set, otherwise - // the alpha is in a separate bitmap. if (mBitCount == 32) return kPremul_SkAlphaType; -#endif return kOpaque_SkAlphaType; } @@ -1251,18 +1246,12 @@ void SkiaSalBitmap::EnsureBitmapData() // Try to fill mBuffer from mImage. assert(mImage->colorType() == kN32_SkColorType); SkiaZone zone; - // If the source image has no alpha, then use no alpha (faster to convert), otherwise - // use kUnpremul_SkAlphaType to make Skia convert from premultiplied alpha when reading - // from the SkImage (the alpha will be ignored if converting to bpp<32 formats, but - // the color channels must be unpremultiplied. Unless bpp==32 and SKIA_USE_BITMAP32, - // in which case use kPremul_SkAlphaType, since SKIA_USE_BITMAP32 implies premultiplied alpha. + // If the source image has no alpha, then use no alpha (faster to convert). SkAlphaType alphaType = kUnpremul_SkAlphaType; if (mImage->imageInfo().alphaType() == kOpaque_SkAlphaType) alphaType = kOpaque_SkAlphaType; -#if SKIA_USE_BITMAP32 if (mBitCount == 32) alphaType = kPremul_SkAlphaType; -#endif SkBitmap bitmap; SkPixmap pixmap; if (imageSize(mImage) == mSize && mImage->imageInfo().alphaType() == alphaType diff --git a/vcl/skia/x11/salvd.cxx b/vcl/skia/x11/salvd.cxx index c517a165efa1..15ffaf880283 100644 --- a/vcl/skia/x11/salvd.cxx +++ b/vcl/skia/x11/salvd.cxx @@ -78,8 +78,10 @@ SalGraphics* X11SkiaSalVirtualDevice::AcquireGraphics() void X11SkiaSalVirtualDevice::ReleaseGraphics(SalGraphics*) { mbGraphicsAcquired = false; } -bool X11SkiaSalVirtualDevice::SetSize(tools::Long nDX, tools::Long nDY) +bool X11SkiaSalVirtualDevice::SetSize(tools::Long nDX, tools::Long nDY, bool bAlphaMaskTransparent) { + assert(!bAlphaMaskTransparent && "TODO"); + (void)bAlphaMaskTransparent; if (!nDX) nDX = 1; if (!nDY) diff --git a/vcl/source/bitmap/BitmapEx.cxx b/vcl/source/bitmap/BitmapEx.cxx index a366541e8da8..02da01d79b66 100644 --- a/vcl/source/bitmap/BitmapEx.cxx +++ b/vcl/source/bitmap/BitmapEx.cxx @@ -104,9 +104,18 @@ void BitmapEx::loadFromIconTheme( const OUString& rIconName ) } BitmapEx::BitmapEx( const Bitmap& rBmp ) : - maBitmap ( rBmp ), - maBitmapSize ( maBitmap.GetSizePixel() ) + maBitmapSize ( rBmp.GetSizePixel() ) { + if (rBmp.getPixelFormat() == vcl::PixelFormat::N32_BPP) + { + std::pair aPair = rBmp.SplitIntoColorAndAlpha(); + maBitmap = std::move(aPair.first); + maAlphaMask = std::move(aPair.second); + } + else + { + maBitmap = rBmp; + } } BitmapEx::BitmapEx( const Bitmap& rBmp, const Bitmap& rMask ) : diff --git a/vcl/source/bitmap/BitmapReadAccess.cxx b/vcl/source/bitmap/BitmapReadAccess.cxx index b009534cd6f4..e39823c4d611 100644 --- a/vcl/source/bitmap/BitmapReadAccess.cxx +++ b/vcl/source/bitmap/BitmapReadAccess.cxx @@ -53,8 +53,6 @@ BitmapReadAccess::BitmapReadAccess(const Bitmap& rBitmap, BitmapAccessMode nMode BitmapReadAccess::~BitmapReadAccess() {} -bool Bitmap32IsPreMultipled() { return ImplGetSVData()->mpDefInst->supportsBitmap32(); } - FncGetPixel BitmapReadAccess::GetPixelFunction(ScanlineFormat nFormat) { switch (nFormat) @@ -68,28 +66,20 @@ FncGetPixel BitmapReadAccess::GetPixelFunction(ScanlineFormat nFormat) case ScanlineFormat::N24BitTcRgb: return GetPixelForN24BitTcRgb; case ScanlineFormat::N32BitTcAbgr: - assert(Bitmap32IsPreMultipled()); return GetPixelForN32BitTcAbgr; case ScanlineFormat::N32BitTcXbgr: - assert(!Bitmap32IsPreMultipled()); return GetPixelForN32BitTcXbgr; case ScanlineFormat::N32BitTcArgb: - assert(Bitmap32IsPreMultipled()); return GetPixelForN32BitTcArgb; case ScanlineFormat::N32BitTcXrgb: - assert(!Bitmap32IsPreMultipled()); return GetPixelForN32BitTcXrgb; case ScanlineFormat::N32BitTcBgra: - assert(Bitmap32IsPreMultipled()); return GetPixelForN32BitTcBgra; case ScanlineFormat::N32BitTcBgrx: - assert(!Bitmap32IsPreMultipled()); return GetPixelForN32BitTcBgrx; case ScanlineFormat::N32BitTcRgba: - assert(Bitmap32IsPreMultipled()); return GetPixelForN32BitTcRgba; case ScanlineFormat::N32BitTcRgbx: - assert(!Bitmap32IsPreMultipled()); return GetPixelForN32BitTcRgbx; default: @@ -110,28 +100,20 @@ FncSetPixel BitmapReadAccess::SetPixelFunction(ScanlineFormat nFormat) case ScanlineFormat::N24BitTcRgb: return SetPixelForN24BitTcRgb; case ScanlineFormat::N32BitTcAbgr: - assert(Bitmap32IsPreMultipled()); return SetPixelForN32BitTcAbgr; case ScanlineFormat::N32BitTcXbgr: - assert(!Bitmap32IsPreMultipled()); return SetPixelForN32BitTcXbgr; case ScanlineFormat::N32BitTcArgb: - assert(Bitmap32IsPreMultipled()); return SetPixelForN32BitTcArgb; case ScanlineFormat::N32BitTcXrgb: - assert(!Bitmap32IsPreMultipled()); return SetPixelForN32BitTcXrgb; case ScanlineFormat::N32BitTcBgra: - assert(Bitmap32IsPreMultipled()); return SetPixelForN32BitTcBgra; case ScanlineFormat::N32BitTcBgrx: - assert(!Bitmap32IsPreMultipled()); return SetPixelForN32BitTcBgrx; case ScanlineFormat::N32BitTcRgba: - assert(Bitmap32IsPreMultipled()); return SetPixelForN32BitTcRgba; case ScanlineFormat::N32BitTcRgbx: - assert(!Bitmap32IsPreMultipled()); return SetPixelForN32BitTcRgbx; default: diff --git a/vcl/source/bitmap/BitmapWriteAccess.cxx b/vcl/source/bitmap/BitmapWriteAccess.cxx index cf5686e031fe..842819c254ef 100644 --- a/vcl/source/bitmap/BitmapWriteAccess.cxx +++ b/vcl/source/bitmap/BitmapWriteAccess.cxx @@ -101,35 +101,27 @@ void BitmapWriteAccess::CopyScanline(tools::Long nY, ConstScanline aSrcScanline, pFncGetPixel = GetPixelForN24BitTcRgb; break; case ScanlineFormat::N32BitTcAbgr: - assert(Bitmap32IsPreMultipled()); pFncGetPixel = GetPixelForN32BitTcAbgr; break; case ScanlineFormat::N32BitTcXbgr: - assert(!Bitmap32IsPreMultipled()); pFncGetPixel = GetPixelForN32BitTcXbgr; break; case ScanlineFormat::N32BitTcArgb: - assert(Bitmap32IsPreMultipled()); pFncGetPixel = GetPixelForN32BitTcArgb; break; case ScanlineFormat::N32BitTcXrgb: - assert(!Bitmap32IsPreMultipled()); pFncGetPixel = GetPixelForN32BitTcXrgb; break; case ScanlineFormat::N32BitTcBgra: - assert(Bitmap32IsPreMultipled()); pFncGetPixel = GetPixelForN32BitTcBgra; break; case ScanlineFormat::N32BitTcBgrx: - assert(!Bitmap32IsPreMultipled()); pFncGetPixel = GetPixelForN32BitTcBgrx; break; case ScanlineFormat::N32BitTcRgba: - assert(Bitmap32IsPreMultipled()); pFncGetPixel = GetPixelForN32BitTcRgba; break; case ScanlineFormat::N32BitTcRgbx: - assert(!Bitmap32IsPreMultipled()); pFncGetPixel = GetPixelForN32BitTcRgbx; break; diff --git a/vcl/source/bitmap/bitmap.cxx b/vcl/source/bitmap/bitmap.cxx index 9423d7a70d09..bfcc06f169ba 100644 --- a/vcl/source/bitmap/bitmap.cxx +++ b/vcl/source/bitmap/bitmap.cxx @@ -1777,4 +1777,40 @@ const basegfx::SystemDependentDataHolder* Bitmap::accessSystemDependentDataHolde return mxSalBmp.get(); } +std::pair Bitmap::SplitIntoColorAndAlpha() const +{ + assert(getPixelFormat() == vcl::PixelFormat::N32_BPP && "only valid to call this when this is a 32-bit combined color+alpha bitmap"); + Bitmap aColorBmp(GetSizePixel(), vcl::PixelFormat::N24_BPP); + AlphaMask aAlphaBmp(GetSizePixel()); + + // We will probably need to make this more efficient by pushing it down to the *SalBitmap implementations, + // but for now, do the simple and safe thing. + { + BitmapScopedReadAccess pThisAcc(*this); + BitmapScopedWriteAccess pColorAcc(aColorBmp); + BitmapScopedWriteAccess pAlphaAcc(aAlphaBmp); + + const tools::Long nHeight(pThisAcc->Height()); + const tools::Long nWidth(pThisAcc->Width()); + + for (tools::Long y = 0; y < nHeight; ++y) + { + Scanline pScanlineRead = pThisAcc->GetScanline( y ); + Scanline pScanlineColor = pColorAcc->GetScanline( y ); + Scanline pScanlineAlpha = pAlphaAcc->GetScanline( y ); + for (tools::Long x = 0; x < nWidth; ++x) + { + BitmapColor aColor = pThisAcc->GetPixelFromData(pScanlineRead, x); + + // write result back + pColorAcc->SetPixelOnData(pScanlineColor, x, aColor); + pAlphaAcc->SetPixelOnData(pScanlineAlpha, x, BitmapColor(aColor.GetAlpha())); + } + } + } + + return { std::move(aColorBmp), std::move(aAlphaBmp) }; +} + + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/png/PngImageReader.cxx b/vcl/source/filter/png/PngImageReader.cxx index 1af01a71610e..977787e90e95 100644 --- a/vcl/source/filter/png/PngImageReader.cxx +++ b/vcl/source/filter/png/PngImageReader.cxx @@ -364,7 +364,6 @@ bool reader(SvStream& rStream, ImportOutput& rImportOutput, BitmapScopedWriteAccess pWriteAccessInstance; BitmapScopedWriteAccess pWriteAccessAlphaInstance; const bool bFuzzing = comphelper::IsFuzzing(); - const bool bSupportsBitmap32 = bFuzzing || ImplGetSVData()->mpDefInst->supportsBitmap32(); const bool bOnlyCreateBitmap = static_cast(nImportFlags & GraphicFilterImportFlags::OnlyCreateBitmap); const bool bUseExistingBitmap @@ -462,14 +461,9 @@ bool reader(SvStream& rStream, ImportOutput& rImportOutput, aBitmap = Bitmap(Size(width, height), vcl::PixelFormat::N24_BPP); break; case PNG_COLOR_TYPE_RGBA: - if (bSupportsBitmap32) - aBitmap = Bitmap(Size(width, height), vcl::PixelFormat::N32_BPP); - else - { - aBitmap = Bitmap(Size(width, height), vcl::PixelFormat::N24_BPP); - aBitmapAlpha = AlphaMask(Size(width, height), nullptr); - aBitmapAlpha.Erase(0); // opaque - } + aBitmap = Bitmap(Size(width, height), vcl::PixelFormat::N24_BPP); + aBitmapAlpha = AlphaMask(Size(width, height), nullptr); + aBitmapAlpha.Erase(0); // opaque break; case PNG_COLOR_TYPE_GRAY: aBitmap = Bitmap(Size(width, height), vcl::PixelFormat::N8_BPP, @@ -551,81 +545,43 @@ bool reader(SvStream& rStream, ImportOutput& rImportOutput, else if (colorType == PNG_COLOR_TYPE_RGB_ALPHA) { size_t aRowSizeBytes = png_get_rowbytes(pPng, pInfo); + ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat(); + if (eFormat == ScanlineFormat::N24BitTcBgr) + png_set_bgr(pPng); - if (bSupportsBitmap32) + if (nNumberOfPasses == 1) { - ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat(); - if (eFormat == ScanlineFormat::N32BitTcAbgr || eFormat == ScanlineFormat::N32BitTcBgra) - png_set_bgr(pPng); - - for (int pass = 0; pass < nNumberOfPasses; pass++) + // optimise the common case, where we can use a buffer of only a single row + std::vector aRow(aRowSizeBytes, 0); + for (png_uint_32 y = 0; y < height; y++) { - for (png_uint_32 y = 0; y < height; y++) + Scanline pScanline = pWriteAccess->GetScanline(y); + Scanline pScanAlpha = pWriteAccessAlpha->GetScanline(y); + png_bytep pRow = aRow.data(); + png_read_row(pPng, pRow, nullptr); + size_t iAlpha = 0; + size_t iColor = 0; + for (size_t i = 0; i < aRowSizeBytes; i += 4) { - Scanline pScanline = pWriteAccess->GetScanline(y); - png_read_row(pPng, pScanline, nullptr); - } - } -#if !ENABLE_WASM_STRIP_PREMULTIPLY - const vcl::bitmap::lookup_table& premultiply = vcl::bitmap::get_premultiply_table(); -#endif - if (eFormat == ScanlineFormat::N32BitTcAbgr || eFormat == ScanlineFormat::N32BitTcArgb) - { // alpha first and premultiply - for (png_uint_32 y = 0; y < height; y++) - { - Scanline pScanline = pWriteAccess->GetScanline(y); - for (size_t i = 0; i < aRowSizeBytes; i += 4) - { - const sal_uInt8 alpha = pScanline[i + 3]; -#if ENABLE_WASM_STRIP_PREMULTIPLY - pScanline[i + 3] = vcl::bitmap::premultiply(pScanline[i + 2], alpha); - pScanline[i + 2] = vcl::bitmap::premultiply(pScanline[i + 1], alpha); - pScanline[i + 1] = vcl::bitmap::premultiply(pScanline[i], alpha); -#else - pScanline[i + 3] = premultiply[alpha][pScanline[i + 2]]; - pScanline[i + 2] = premultiply[alpha][pScanline[i + 1]]; - pScanline[i + 1] = premultiply[alpha][pScanline[i]]; -#endif - pScanline[i] = alpha; - } - } - } - else - { // keep alpha last, only premultiply - for (png_uint_32 y = 0; y < height; y++) - { - Scanline pScanline = pWriteAccess->GetScanline(y); - for (size_t i = 0; i < aRowSizeBytes; i += 4) - { - const sal_uInt8 alpha = pScanline[i + 3]; -#if ENABLE_WASM_STRIP_PREMULTIPLY - pScanline[i] = vcl::bitmap::premultiply(pScanline[i], alpha); - pScanline[i + 1] = vcl::bitmap::premultiply(pScanline[i + 1], alpha); - pScanline[i + 2] = vcl::bitmap::premultiply(pScanline[i + 2], alpha); -#else - pScanline[i] = premultiply[alpha][pScanline[i]]; - pScanline[i + 1] = premultiply[alpha][pScanline[i + 1]]; - pScanline[i + 2] = premultiply[alpha][pScanline[i + 2]]; -#endif - } + pScanline[iColor++] = pRow[i + 0]; + pScanline[iColor++] = pRow[i + 1]; + pScanline[iColor++] = pRow[i + 2]; + pScanAlpha[iAlpha++] = pRow[i + 3]; } } } else { - ScanlineFormat eFormat = pWriteAccess->GetScanlineFormat(); - if (eFormat == ScanlineFormat::N24BitTcBgr) - png_set_bgr(pPng); - - if (nNumberOfPasses == 1) + std::vector> aRows(height); + for (auto& rRow : aRows) + rRow.resize(aRowSizeBytes, 0); + for (int pass = 0; pass < nNumberOfPasses; pass++) { - // optimise the common case, where we can use a buffer of only a single row - std::vector aRow(aRowSizeBytes, 0); for (png_uint_32 y = 0; y < height; y++) { Scanline pScanline = pWriteAccess->GetScanline(y); Scanline pScanAlpha = pWriteAccessAlpha->GetScanline(y); - png_bytep pRow = aRow.data(); + png_bytep pRow = aRows[y].data(); png_read_row(pPng, pRow, nullptr); size_t iAlpha = 0; size_t iColor = 0; @@ -638,31 +594,6 @@ bool reader(SvStream& rStream, ImportOutput& rImportOutput, } } } - else - { - std::vector> aRows(height); - for (auto& rRow : aRows) - rRow.resize(aRowSizeBytes, 0); - for (int pass = 0; pass < nNumberOfPasses; pass++) - { - for (png_uint_32 y = 0; y < height; y++) - { - Scanline pScanline = pWriteAccess->GetScanline(y); - Scanline pScanAlpha = pWriteAccessAlpha->GetScanline(y); - png_bytep pRow = aRows[y].data(); - png_read_row(pPng, pRow, nullptr); - size_t iAlpha = 0; - size_t iColor = 0; - for (size_t i = 0; i < aRowSizeBytes; i += 4) - { - pScanline[iColor++] = pRow[i + 0]; - pScanline[iColor++] = pRow[i + 1]; - pScanline[iColor++] = pRow[i + 2]; - pScanAlpha[iAlpha++] = pRow[i + 3]; - } - } - } - } } } else if (colorType == PNG_COLOR_TYPE_GRAY) diff --git a/vcl/source/filter/webp/reader.cxx b/vcl/source/filter/webp/reader.cxx index 901974a92b9b..d9cff9997ada 100644 --- a/vcl/source/filter/webp/reader.cxx +++ b/vcl/source/filter/webp/reader.cxx @@ -72,21 +72,10 @@ static bool readWebp(SvStream& stream, Graphic& graphic) if (width > SAL_MAX_INT32 / 8 || height > SAL_MAX_INT32 / 8) return false; // avoid overflows later - const bool bFuzzing = comphelper::IsFuzzing(); - const bool bSupportsBitmap32 = bFuzzing || ImplGetSVData()->mpDefInst->supportsBitmap32(); - - Bitmap bitmap; AlphaMask bitmapAlpha; - if (bSupportsBitmap32 && has_alpha) - { - bitmap = Bitmap(Size(width, height), vcl::PixelFormat::N32_BPP); - } - else - { - bitmap = Bitmap(Size(width, height), vcl::PixelFormat::N24_BPP); - if (has_alpha) - bitmapAlpha = AlphaMask(Size(width, height)); - } + Bitmap bitmap(Size(width, height), vcl::PixelFormat::N24_BPP); + if (has_alpha) + bitmapAlpha = AlphaMask(Size(width, height)); BitmapScopedWriteAccess access(bitmap); if (!access) @@ -104,25 +93,17 @@ static bool readWebp(SvStream& stream, Graphic& graphic) config.output.width = width; config.output.height = height; config.output.is_external_memory = 1; - if (bSupportsBitmap32 && has_alpha) + if (has_alpha) { switch (access->GetScanlineFormat()) { - // Our bitmap32 code expects premultiplied. - case ScanlineFormat::N32BitTcRgba: - case ScanlineFormat::N32BitTcRgbx: - config.output.colorspace = MODE_rgbA; - pixelMode = PixelMode::DirectRead; + case ScanlineFormat::N24BitTcRgb: + config.output.colorspace = MODE_RGBA; + pixelMode = PixelMode::Split; break; - case ScanlineFormat::N32BitTcBgra: - case ScanlineFormat::N32BitTcBgrx: - config.output.colorspace = MODE_bgrA; - pixelMode = PixelMode::DirectRead; - break; - case ScanlineFormat::N32BitTcArgb: - case ScanlineFormat::N32BitTcXrgb: - config.output.colorspace = MODE_Argb; - pixelMode = PixelMode::DirectRead; + case ScanlineFormat::N24BitTcBgr: + config.output.colorspace = MODE_BGRA; + pixelMode = PixelMode::Split; break; default: config.output.colorspace = MODE_RGBA; @@ -132,43 +113,23 @@ static bool readWebp(SvStream& stream, Graphic& graphic) } else { - if (has_alpha) + switch (access->GetScanlineFormat()) { - switch (access->GetScanlineFormat()) - { - case ScanlineFormat::N24BitTcRgb: - config.output.colorspace = MODE_RGBA; - pixelMode = PixelMode::Split; - break; - case ScanlineFormat::N24BitTcBgr: - config.output.colorspace = MODE_BGRA; - pixelMode = PixelMode::Split; - break; - default: - config.output.colorspace = MODE_RGBA; - pixelMode = PixelMode::SetPixel; - break; - } - } - else - { - switch (access->GetScanlineFormat()) - { - case ScanlineFormat::N24BitTcRgb: - config.output.colorspace = MODE_RGB; - pixelMode = PixelMode::DirectRead; - break; - case ScanlineFormat::N24BitTcBgr: - config.output.colorspace = MODE_BGR; - pixelMode = PixelMode::DirectRead; - break; - default: - config.output.colorspace = MODE_RGB; - pixelMode = PixelMode::SetPixel; - break; - } + case ScanlineFormat::N24BitTcRgb: + config.output.colorspace = MODE_RGB; + pixelMode = PixelMode::DirectRead; + break; + case ScanlineFormat::N24BitTcBgr: + config.output.colorspace = MODE_BGR; + pixelMode = PixelMode::DirectRead; + break; + default: + config.output.colorspace = MODE_RGB; + pixelMode = PixelMode::SetPixel; + break; } } + if (pixelMode == PixelMode::DirectRead) { config.output.u.RGBA.rgba = access->GetBuffer(); @@ -286,15 +247,10 @@ static bool readWebp(SvStream& stream, Graphic& graphic) } access.reset(); // Flush BitmapScopedWriteAccess. - if (bSupportsBitmap32 && has_alpha) - graphic = BitmapEx(bitmap); + if (has_alpha) + graphic = BitmapEx(bitmap, bitmapAlpha); else - { - if (has_alpha) - graphic = BitmapEx(bitmap, bitmapAlpha); - else - graphic = BitmapEx(bitmap); - } + graphic = BitmapEx(bitmap); return success; } diff --git a/vcl/source/gdi/print.cxx b/vcl/source/gdi/print.cxx index daebda8fb0d4..0e598df58baa 100644 --- a/vcl/source/gdi/print.cxx +++ b/vcl/source/gdi/print.cxx @@ -221,13 +221,6 @@ void Printer::DrawDeviceBitmapEx( const Point& rDestPt, const Size& rDestSize, void Printer::EmulateDrawTransparent ( const tools::PolyPolygon& rPolyPoly, sal_uInt16 nTransparencePercent ) { - // #110958# Disable alpha VDev, we perform the necessary - VirtualDevice* pOldAlphaVDev = mpAlphaVDev; - - // operation explicitly further below. - if( mpAlphaVDev ) - mpAlphaVDev = nullptr; - GDIMetaFile* pOldMetaFile = mpMetaFile; mpMetaFile = nullptr; @@ -285,9 +278,6 @@ void Printer::EmulateDrawTransparent ( const tools::PolyPolygon& rPolyPoly, Pop(); mpMetaFile = pOldMetaFile; - - // #110958# Restore disabled alpha VDev - mpAlphaVDev = pOldAlphaVDev; } void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/, diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx index 2b465ce19c38..939b8c5b0dbb 100644 --- a/vcl/source/gdi/salgdilayout.cxx +++ b/vcl/source/gdi/salgdilayout.cxx @@ -681,11 +681,11 @@ void SalGraphics::DrawMask( const SalTwoRect& rPosAry, drawMask( rPosAry, rSalBitmap, nMaskColor ); } -std::shared_ptr SalGraphics::GetBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, const OutputDevice& rOutDev ) +std::shared_ptr SalGraphics::GetBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, const OutputDevice& rOutDev, bool bWithoutAlpha ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) mirror( nX, nWidth, rOutDev ); - return getBitmap( nX, nY, nWidth, nHeight ); + return getBitmap( nX, nY, nWidth, nHeight, bWithoutAlpha ); } Color SalGraphics::GetPixel( tools::Long nX, tools::Long nY, const OutputDevice& rOutDev ) diff --git a/vcl/source/gdi/virdev.cxx b/vcl/source/gdi/virdev.cxx index 40977754b31b..906311e89cec 100644 --- a/vcl/source/gdi/virdev.cxx +++ b/vcl/source/gdi/virdev.cxx @@ -203,21 +203,6 @@ void VirtualDevice::ImplInitVirDev( const OutputDevice* pOutDev, if ( mpNext ) mpNext->mpPrev = this; pSVData->maGDIData.mpFirstVirDev = this; - - // initialise alpha layer - if (meFormatAndAlpha != DeviceFormat::WITHOUT_ALPHA) - { - mpAlphaVDev = VclPtr::Create(*this, DeviceFormat::WITHOUT_ALPHA); - mpAlphaVDev->InnerImplSetOutputSizePixel(Size(nDX, nDY), bErase); - mpAlphaVDev->SetBackground( Wallpaper(COL_ALPHA_OPAQUE) ); - mpAlphaVDev->Erase(); - if( GetLineColor() != COL_TRANSPARENT ) - mpAlphaVDev->SetLineColor( COL_ALPHA_OPAQUE ); - if( GetFillColor() != COL_TRANSPARENT ) - mpAlphaVDev->SetFillColor( COL_ALPHA_OPAQUE ); - mpAlphaVDev->SetMapMode( GetMapMode() ); - mpAlphaVDev->SetAntialiasing( GetAntialiasing() ); - } } VirtualDevice::VirtualDevice(const OutputDevice* pCompDev, DeviceFormat eFormatAndAlpha, @@ -269,7 +254,7 @@ void VirtualDevice::dispose() OutputDevice::dispose(); } -bool VirtualDevice::InnerImplSetOutputSizePixel( const Size& rNewSize, bool bErase) +bool VirtualDevice::InnerImplSetOutputSizePixel( const Size& rNewSize, bool bErase, bool bAlphaMaskTransparent) { SAL_INFO( "vcl.virdev", "VirtualDevice::InnerImplSetOutputSizePixel( " << rNewSize.Width() << ", " @@ -296,7 +281,7 @@ bool VirtualDevice::InnerImplSetOutputSizePixel( const Size& rNewSize, bool bEra if ( bErase ) { - bRet = mpVirDev->SetSize( nNewWidth, nNewHeight ); + bRet = mpVirDev->SetSize( nNewWidth, nNewHeight, bAlphaMaskTransparent ); if ( bRet ) { mnOutWidth = rNewSize.Width(); @@ -315,7 +300,7 @@ bool VirtualDevice::InnerImplSetOutputSizePixel( const Size& rNewSize, bool bEra assert(mpGraphics); - pNewVirDev = pSVData->mpDefInst->CreateVirtualDevice(*mpGraphics, nNewWidth, nNewHeight, meFormatAndAlpha); + pNewVirDev = pSVData->mpDefInst->CreateVirtualDevice(*mpGraphics, nNewWidth, nNewHeight, meFormatAndAlpha, bAlphaMaskTransparent); if ( pNewVirDev ) { SalGraphics* pGraphics = pNewVirDev->AcquireGraphics(); @@ -368,40 +353,7 @@ void VirtualDevice::ImplFillOpaqueRectangle( const tools::Rectangle& rRect ) bool VirtualDevice::SetOutputSizePixel( const Size& rNewSize, bool bErase, bool bAlphaMaskTransparent ) { - if( InnerImplSetOutputSizePixel(rNewSize, bErase) ) - { - if (meFormatAndAlpha != DeviceFormat::WITHOUT_ALPHA) - { - // #110958# Setup alpha bitmap - if(mpAlphaVDev && mpAlphaVDev->GetOutputSizePixel() != rNewSize) - { - mpAlphaVDev.disposeAndClear(); - } - - if( !mpAlphaVDev ) - { - mpAlphaVDev = VclPtr::Create(*this, DeviceFormat::WITHOUT_ALPHA); - mpAlphaVDev->InnerImplSetOutputSizePixel(rNewSize, bErase); - mpAlphaVDev->SetBackground( Wallpaper(bAlphaMaskTransparent ? COL_ALPHA_TRANSPARENT : COL_ALPHA_OPAQUE) ); - mpAlphaVDev->Erase(); - } - - // TODO: copy full outdev state to new one, here. Also needed in outdev2.cxx:DrawOutDev - if( GetLineColor() != COL_TRANSPARENT ) - mpAlphaVDev->SetLineColor( COL_ALPHA_OPAQUE ); - - if( GetFillColor() != COL_TRANSPARENT ) - mpAlphaVDev->SetFillColor( COL_ALPHA_OPAQUE ); - - mpAlphaVDev->SetMapMode( GetMapMode() ); - - mpAlphaVDev->SetAntialiasing( GetAntialiasing() ); - } - - return true; - } - - return false; + return InnerImplSetOutputSizePixel(rNewSize, bErase, bAlphaMaskTransparent); } void VirtualDevice::EnableRTL( bool bEnable ) diff --git a/vcl/source/outdev/background.cxx b/vcl/source/outdev/background.cxx index d73cb786682d..4271399ddc6b 100644 --- a/vcl/source/outdev/background.cxx +++ b/vcl/source/outdev/background.cxx @@ -26,51 +26,18 @@ Color OutputDevice::GetBackgroundColor() const void OutputDevice::SetBackground() { - maBackground = Wallpaper(); mbBackground = false; - - if( mpAlphaVDev ) - mpAlphaVDev->SetBackground(); } void OutputDevice::SetBackground( const Wallpaper& rBackground ) { - maBackground = rBackground; if( rBackground.GetStyle() == WallpaperStyle::NONE ) mbBackground = false; else mbBackground = true; - - if( !mpAlphaVDev ) - return; - - // Some of these are probably wrong (e.g. if the gradient has transparency), - // but hopefully nobody uses that. If you do, feel free to implement it properly. - if( rBackground.GetStyle() == WallpaperStyle::NONE ) - { - mpAlphaVDev->SetBackground( rBackground ); - } - else if( rBackground.IsBitmap()) - { - const BitmapEx& bitmap = rBackground.GetBitmap(); - if( bitmap.IsAlpha()) - mpAlphaVDev->SetBackground( Wallpaper( BitmapEx( bitmap.GetAlphaMask().GetBitmap() ) ) ); - else - mpAlphaVDev->SetBackground( Wallpaper( COL_ALPHA_OPAQUE )); - } - else if( rBackground.IsGradient()) - { - mpAlphaVDev->SetBackground( Wallpaper( COL_ALPHA_OPAQUE )); - } - else - { - // Color background. - int alpha = rBackground.GetColor().GetAlpha(); - mpAlphaVDev->SetBackground( Wallpaper( Color( alpha, alpha, alpha ))); - } } diff --git a/vcl/source/outdev/bitmap.cxx b/vcl/source/outdev/bitmap.cxx index 1a23db131a77..441e2f370eeb 100644 --- a/vcl/source/outdev/bitmap.cxx +++ b/vcl/source/outdev/bitmap.cxx @@ -180,12 +180,6 @@ void OutputDevice::DrawBitmap( const Point& rDestPt, const Size& rDestSize, } } } - - if( mpAlphaVDev ) - { - // #i32109#: Make bitmap area opaque - mpAlphaVDev->ImplFillOpaqueRectangle( tools::Rectangle(rDestPt, rDestSize) ); - } } Bitmap OutputDevice::GetBitmap( const Point& rSrcPt, const Size& rSize ) const @@ -271,7 +265,12 @@ Bitmap OutputDevice::GetBitmap( const Point& rSrcPt, const Size& rSize ) const if ( !bClipped ) { - std::shared_ptr pSalBmp = mpGraphics->GetBitmap( nX, nY, nWidth, nHeight, *this ); + std::shared_ptr pSalBmp; + // if we are a virtual device, we might need to remove the unused alpha channel + bool bWithoutAlpha = false; + if (OUTDEV_VIRDEV == GetOutDevType()) + bWithoutAlpha = static_cast(this)->IsWithoutAlpha(); + pSalBmp = mpGraphics->GetBitmap( nX, nY, nWidth, nHeight, *this, bWithoutAlpha ); if( pSalBmp ) { @@ -333,36 +332,14 @@ void OutputDevice::DrawDeviceAlphaBitmap( const Bitmap& rBmp, const AlphaMask& r SalBitmap* pSalSrcBmp = bitmap.ImplGetSalBitmap().get(); SalBitmap* pSalAlphaBmp = alpha.GetBitmap().ImplGetSalBitmap().get(); - // #i83087# Naturally, system alpha blending (SalGraphics::DrawAlphaBitmap) cannot work - // with separate alpha VDev - - // try to blend the alpha bitmap with the alpha virtual device - if (mpAlphaVDev) - { - if (ImplLogicToDevicePixel(aOutSz).IsEmpty()) // nothing to draw - return; - Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( aRelPt, aOutSz ) ); - if (SalBitmap* pSalAlphaBmp2 = aAlphaBitmap.ImplGetSalBitmap().get()) - { - if (mpGraphics->BlendAlphaBitmap(aTR, *pSalSrcBmp, *pSalAlphaBmp, *pSalAlphaBmp2, *this)) - { - mpAlphaVDev->BlendBitmap(aTR, rAlpha.GetBitmap()); - return; - } - } - } - else - { - if (mpGraphics->DrawAlphaBitmap(aTR, *pSalSrcBmp, *pSalAlphaBmp, *this)) - return; - } + if (mpGraphics->DrawAlphaBitmap(aTR, *pSalSrcBmp, *pSalAlphaBmp, *this)) + return; // we need to make sure Skia never reaches this slow code path // (but do not fail in no-op cases) assert(!SkiaHelper::isVCLSkiaEnabled() || !SkiaHelper::isAlphaMaskBlendingEnabled() || tools::Rectangle(Point(), rBmp.GetSizePixel()) - .Intersection(tools::Rectangle(rSrcPtPixel, rSrcSizePixel)).IsEmpty() - || mpAlphaVDev->LogicToPixel(mpAlphaVDev->GetOutputSizePixel()).IsEmpty()); + .Intersection(tools::Rectangle(rSrcPtPixel, rSrcSizePixel)).IsEmpty()); } tools::Rectangle aBmpRect(Point(), rBmp.GetSizePixel()); @@ -375,7 +352,7 @@ void OutputDevice::DrawDeviceAlphaBitmap( const Bitmap& rBmp, const AlphaMask& r // HACK: The function is broken with alpha vdev and mirroring, mirror here. Bitmap bitmap(rBmp); AlphaMask alpha(rAlpha); - if(mpAlphaVDev && (bHMirr || bVMirr)) + if(bHMirr || bVMirr) { bitmap.Mirror(mirrorFlags); alpha.Mirror(mirrorFlags); @@ -388,173 +365,6 @@ void OutputDevice::DrawDeviceAlphaBitmap( const Bitmap& rBmp, const AlphaMask& r namespace { -struct LinearScaleContext -{ - std::unique_ptr mpMapX; - std::unique_ptr mpMapY; - - std::unique_ptr mpMapXOffset; - std::unique_ptr mpMapYOffset; - - LinearScaleContext(tools::Rectangle const & aDstRect, tools::Rectangle const & aBitmapRect, - Size const & aOutSize, tools::Long nOffX, tools::Long nOffY) - - : mpMapX(new sal_Int32[aDstRect.GetWidth()]) - , mpMapY(new sal_Int32[aDstRect.GetHeight()]) - , mpMapXOffset(new sal_Int32[aDstRect.GetWidth()]) - , mpMapYOffset(new sal_Int32[aDstRect.GetHeight()]) - { - const tools::Long nSrcWidth = aBitmapRect.GetWidth(); - const tools::Long nSrcHeight = aBitmapRect.GetHeight(); - - generateSimpleMap( - nSrcWidth, aDstRect.GetWidth(), aBitmapRect.Left(), - aOutSize.Width(), nOffX, mpMapX.get(), mpMapXOffset.get()); - - generateSimpleMap( - nSrcHeight, aDstRect.GetHeight(), aBitmapRect.Top(), - aOutSize.Height(), nOffY, mpMapY.get(), mpMapYOffset.get()); - } - -private: - - static void generateSimpleMap(tools::Long nSrcDimension, tools::Long nDstDimension, tools::Long nDstLocation, - tools::Long nOutDimension, tools::Long nOffset, sal_Int32* pMap, sal_Int32* pMapOffset) - { - - const double fReverseScale = (std::abs(nOutDimension) > 1) ? (nSrcDimension - 1) / double(std::abs(nOutDimension) - 1) : 0.0; - - tools::Long nSampleRange = std::max(tools::Long(0), nSrcDimension - 2); - - for (tools::Long i = 0; i < nDstDimension; i++) - { - double fTemp = std::abs((nOffset + i) * fReverseScale); - - pMap[i] = std::clamp(nDstLocation + tools::Long(fTemp), tools::Long(0), nSampleRange); - pMapOffset[i] = static_cast((fTemp - pMap[i]) * 128.0); - } - } - -public: - bool blendBitmap( - const BitmapWriteAccess* pDestination, - const BitmapReadAccess* pSource, - const BitmapReadAccess* pSourceAlpha, - const tools::Long nDstWidth, - const tools::Long nDstHeight) - { - if (!pSource || !pSourceAlpha || !pDestination) - return false; - - ScanlineFormat nSourceFormat = pSource->GetScanlineFormat(); - ScanlineFormat nDestinationFormat = pDestination->GetScanlineFormat(); - - switch (nSourceFormat) - { - case ScanlineFormat::N24BitTcRgb: - case ScanlineFormat::N24BitTcBgr: - { - if ( (nSourceFormat == ScanlineFormat::N24BitTcBgr && nDestinationFormat == ScanlineFormat::N32BitTcBgra) - || (nSourceFormat == ScanlineFormat::N24BitTcRgb && nDestinationFormat == ScanlineFormat::N32BitTcRgba)) - { - blendBitmap24(pDestination, pSource, pSourceAlpha, nDstWidth, nDstHeight); - return true; - } - } - break; - default: break; - } - return false; - } - - void blendBitmap24( - const BitmapWriteAccess* pDestination, - const BitmapReadAccess* pSource, - const BitmapReadAccess* pSourceAlpha, - const tools::Long nDstWidth, - const tools::Long nDstHeight) - { - Scanline pLine0, pLine1; - Scanline pLineAlpha0, pLineAlpha1; - Scanline pColorSample1, pColorSample2; - Scanline pDestScanline; - - tools::Long nColor1Line1, nColor2Line1, nColor3Line1; - tools::Long nColor1Line2, nColor2Line2, nColor3Line2; - tools::Long nAlphaLine1, nAlphaLine2; - - sal_uInt8 nColor1, nColor2, nColor3, nAlpha; - - for (tools::Long nY = 0; nY < nDstHeight; nY++) - { - const tools::Long nMapY = mpMapY[nY]; - const tools::Long nMapFY = mpMapYOffset[nY]; - - pLine0 = pSource->GetScanline(nMapY); - // tdf#95481 guard nMapY + 1 to be within bounds - pLine1 = (nMapY + 1 < pSource->Height()) ? pSource->GetScanline(nMapY + 1) : pLine0; - - pLineAlpha0 = pSourceAlpha->GetScanline(nMapY); - // tdf#95481 guard nMapY + 1 to be within bounds - pLineAlpha1 = (nMapY + 1 < pSourceAlpha->Height()) ? pSourceAlpha->GetScanline(nMapY + 1) : pLineAlpha0; - - pDestScanline = pDestination->GetScanline(nY); - - for (tools::Long nX = 0; nX < nDstWidth; nX++) - { - const tools::Long nMapX = mpMapX[nX]; - const tools::Long nMapFX = mpMapXOffset[nX]; - - pColorSample1 = pLine0 + 3 * nMapX; - pColorSample2 = (nMapX + 1 < pSource->Width()) ? pColorSample1 + 3 : pColorSample1; - nColor1Line1 = (static_cast(*pColorSample1) << 7) + nMapFX * (static_cast(*pColorSample2) - *pColorSample1); - - pColorSample1++; - pColorSample2++; - nColor2Line1 = (static_cast(*pColorSample1) << 7) + nMapFX * (static_cast(*pColorSample2) - *pColorSample1); - - pColorSample1++; - pColorSample2++; - nColor3Line1 = (static_cast(*pColorSample1) << 7) + nMapFX * (static_cast(*pColorSample2) - *pColorSample1); - - pColorSample1 = pLine1 + 3 * nMapX; - pColorSample2 = (nMapX + 1 < pSource->Width()) ? pColorSample1 + 3 : pColorSample1; - nColor1Line2 = (static_cast(*pColorSample1) << 7) + nMapFX * (static_cast(*pColorSample2) - *pColorSample1); - - pColorSample1++; - pColorSample2++; - nColor2Line2 = (static_cast(*pColorSample1) << 7) + nMapFX * (static_cast(*pColorSample2) - *pColorSample1); - - pColorSample1++; - pColorSample2++; - nColor3Line2 = (static_cast(*pColorSample1) << 7) + nMapFX * (static_cast(*pColorSample2) - *pColorSample1); - - pColorSample1 = pLineAlpha0 + nMapX; - pColorSample2 = (nMapX + 1 < pSourceAlpha->Width()) ? pColorSample1 + 1 : pColorSample1; - nAlphaLine1 = (static_cast(*pColorSample1) << 7) + nMapFX * (static_cast(*pColorSample2) - *pColorSample1); - - pColorSample1 = pLineAlpha1 + nMapX; - pColorSample2 = (nMapX + 1 < pSourceAlpha->Width()) ? pColorSample1 + 1 : pColorSample1; - nAlphaLine2 = (static_cast(*pColorSample1) << 7) + nMapFX * (static_cast(*pColorSample2) - *pColorSample1); - - nColor1 = (nColor1Line1 + nMapFY * ((nColor1Line2 >> 7) - (nColor1Line1 >> 7))) >> 7; - nColor2 = (nColor2Line1 + nMapFY * ((nColor2Line2 >> 7) - (nColor2Line1 >> 7))) >> 7; - nColor3 = (nColor3Line1 + nMapFY * ((nColor3Line2 >> 7) - (nColor3Line1 >> 7))) >> 7; - - nAlpha = (nAlphaLine1 + nMapFY * ((nAlphaLine2 >> 7) - (nAlphaLine1 >> 7))) >> 7; - - *pDestScanline = color::ColorChannelMerge(*pDestScanline, nColor1, nAlpha); - pDestScanline++; - *pDestScanline = color::ColorChannelMerge(*pDestScanline, nColor2, nAlpha); - pDestScanline++; - *pDestScanline = color::ColorChannelMerge(*pDestScanline, nColor3, nAlpha); - pDestScanline++; - pDestScanline++; - } - } - } -}; - struct TradScaleContext { std::unique_ptr mpMapX; @@ -608,11 +418,6 @@ void OutputDevice::DrawDeviceAlphaBitmapSlowPath(const Bitmap& rBitmap, { assert(!is_double_buffered_window()); - VirtualDevice* pOldVDev = mpAlphaVDev; - - const bool bHMirr = aOutSize.Width() < 0; - const bool bVMirr = aOutSize.Height() < 0; - // The scaling in this code path produces really ugly results - it // does the most trivial scaling with no smoothing. GDIMetaFile* pOldMetaFile = mpMetaFile; @@ -661,45 +466,12 @@ void OutputDevice::DrawDeviceAlphaBitmapSlowPath(const Bitmap& rBitmap, { Bitmap aNewBitmap; - if (mpAlphaVDev) - { - aNewBitmap = BlendBitmapWithAlpha( - aBmp, pBitmapReadAccess.get(), pAlphaReadAccess.get(), - aDstRect, - nOffY, nDstHeight, - nOffX, nDstWidth, - aTradContext.mpMapX.get(), aTradContext.mpMapY.get() ); - } - else - { - LinearScaleContext aLinearContext(aDstRect, aBmpRect, aOutSize, nOffX, nOffY); - - if (aLinearContext.blendBitmap( BitmapScopedWriteAccess(aBmp).get(), pBitmapReadAccess.get(), pAlphaReadAccess.get(), - nDstWidth, nDstHeight)) - { - aNewBitmap = std::move(aBmp); - } - else - { - aNewBitmap = BlendBitmap( - aBmp, pBitmapReadAccess.get(), pAlphaReadAccess.get(), - nOffY, nDstHeight, - nOffX, nDstWidth, - aBmpRect, aOutSize, - bHMirr, bVMirr, - aTradContext.mpMapX.get(), aTradContext.mpMapY.get() ); - } - } - - // #110958# Disable alpha VDev, we're doing the necessary - // stuff explicitly further below - if (mpAlphaVDev) - mpAlphaVDev = nullptr; - + aNewBitmap = BlendBitmapWithAlpha( + aBmp, pBitmapReadAccess.get(), pAlphaReadAccess.get(), + nDstHeight, + nDstWidth, + aTradContext.mpMapX.get(), aTradContext.mpMapY.get() ); DrawBitmap(aDstRect.TopLeft(), aNewBitmap); - - // #110958# Enable alpha VDev again - mpAlphaVDev = pOldVDev; } mbMap = bOldMap; @@ -759,23 +531,22 @@ namespace const tools::Long nMapY, BitmapReadAccess const * pP, BitmapReadAccess const * pA, - BitmapReadAccess const * pB, - BitmapWriteAccess const * pAlphaW, - sal_uInt8& nResAlpha ) + BitmapReadAccess const * pB) { BitmapColor aDstCol,aSrcCol; aSrcCol = pP->GetColor( nMapY, nMapX ); aDstCol = pB->GetColor( nY, nX ); const sal_uInt8 nSrcAlpha = pA->GetPixelIndex( nMapY, nMapX ); - const sal_uInt8 nDstAlpha = pAlphaW->GetPixelIndex( nY, nX ); + const sal_uInt8 nDstAlpha = aDstCol.GetAlpha(); // Perform porter-duff compositing 'over' operation // Co = Cs + Cd*(1-As) // Ad = As + Ad*(1-As) - nResAlpha = static_cast(nSrcAlpha) + static_cast(nDstAlpha) - static_cast(nDstAlpha)*nSrcAlpha/255; - + sal_uInt8 nResAlpha = static_cast(nSrcAlpha) + static_cast(nDstAlpha) + - static_cast(nDstAlpha) * nSrcAlpha / 255; + aDstCol.SetAlpha(nResAlpha); aDstCol.SetRed( CalcColor( aSrcCol.GetRed(), nSrcAlpha, nDstAlpha, nResAlpha, aDstCol.GetRed() ) ); aDstCol.SetBlue( CalcColor( aSrcCol.GetBlue(), nSrcAlpha, nDstAlpha, nResAlpha, aDstCol.GetBlue() ) ); aDstCol.SetGreen( CalcColor( aSrcCol.GetGreen(), nSrcAlpha, nDstAlpha, nResAlpha, aDstCol.GetGreen() ) ); @@ -795,88 +566,29 @@ Bitmap OutputDevice::BlendBitmapWithAlpha( Bitmap& aBmp, BitmapReadAccess const * pP, BitmapReadAccess const * pA, - const tools::Rectangle& aDstRect, - const sal_Int32 nOffY, const sal_Int32 nDstHeight, - const sal_Int32 nOffX, const sal_Int32 nDstWidth, const sal_Int32* pMapX, const sal_Int32* pMapY ) { - BitmapColor aDstCol; Bitmap res; - int nX, nY; - sal_uInt8 nResAlpha; - SAL_WARN_IF( !mpAlphaVDev, "vcl.gdi", "BlendBitmapWithAlpha(): call me only with valid alpha VirtualDevice!" ); - - bool bOldMapMode( mpAlphaVDev->IsMapModeEnabled() ); - mpAlphaVDev->EnableMapMode(false); - - Bitmap aAlphaBitmap( mpAlphaVDev->GetBitmap( aDstRect.TopLeft(), aDstRect.GetSize() ) ); - BitmapScopedWriteAccess pAlphaW(aAlphaBitmap); - - if( GetBitCount() <= 8 ) - { - Bitmap aDither(aBmp.GetSizePixel(), vcl::PixelFormat::N8_BPP); - BitmapColor aIndex( 0 ); - BitmapScopedReadAccess pB(aBmp); - BitmapScopedWriteAccess pW(aDither); - - if (pB && pP && pA && pW && pAlphaW) - { - int nOutY; - - for( nY = 0, nOutY = nOffY; nY < nDstHeight; nY++, nOutY++ ) - { - const tools::Long nMapY = pMapY[ nY ]; - const tools::Long nModY = ( nOutY & 0x0FL ) << 4; - int nOutX; - - Scanline pScanline = pW->GetScanline(nY); - Scanline pScanlineAlpha = pAlphaW->GetScanline(nY); - for( nX = 0, nOutX = nOffX; nX < nDstWidth; nX++, nOutX++ ) - { - const tools::Long nMapX = pMapX[ nX ]; - const sal_uLong nD = nVCLDitherLut[ nModY | ( nOutX & 0x0FL ) ]; - - aDstCol = AlphaBlend( nX, nY, nMapX, nMapY, pP, pA, pB.get(), pAlphaW.get(), nResAlpha ); - - aIndex.SetIndex( static_cast( nVCLRLut[ ( nVCLLut[ aDstCol.GetRed() ] + nD ) >> 16 ] + - nVCLGLut[ ( nVCLLut[ aDstCol.GetGreen() ] + nD ) >> 16 ] + - nVCLBLut[ ( nVCLLut[ aDstCol.GetBlue() ] + nD ) >> 16 ] ) ); - pW->SetPixelOnData( pScanline, nX, aIndex ); - - aIndex.SetIndex( static_cast( nVCLRLut[ ( nVCLLut[ nResAlpha ] + nD ) >> 16 ] + - nVCLGLut[ ( nVCLLut[ nResAlpha ] + nD ) >> 16 ] + - nVCLBLut[ ( nVCLLut[ nResAlpha ] + nD ) >> 16 ] ) ); - pAlphaW->SetPixelOnData( pScanlineAlpha, nX, aIndex ); - } - } - } - pB.reset(); - pW.reset(); - res = std::move(aDither); - } - else { BitmapScopedWriteAccess pB(aBmp); - if (pB && pP && pA && pAlphaW) + if (pB && pP && pA) { - for( nY = 0; nY < nDstHeight; nY++ ) + for( int nY = 0; nY < nDstHeight; nY++ ) { const tools::Long nMapY = pMapY[ nY ]; Scanline pScanlineB = pB->GetScanline(nY); - Scanline pScanlineAlpha = pAlphaW->GetScanline(nY); - for( nX = 0; nX < nDstWidth; nX++ ) + for( int nX = 0; nX < nDstWidth; nX++ ) { const tools::Long nMapX = pMapX[ nX ]; - aDstCol = AlphaBlend( nX, nY, nMapX, nMapY, pP, pA, pB.get(), pAlphaW.get(), nResAlpha ); + BitmapColor aDstCol = AlphaBlend(nX, nY, nMapX, nMapY, pP, pA, pB.get()); - pB->SetPixelOnData(pScanlineB, nX, pB->GetBestMatchingColor(aDstCol)); - pAlphaW->SetPixelOnData(pScanlineAlpha, nX, pB->GetBestMatchingColor(Color(nResAlpha, nResAlpha, nResAlpha))); + pB->SetPixelOnData(pScanlineB, nX, aDstCol); } } } @@ -884,10 +596,6 @@ Bitmap OutputDevice::BlendBitmapWithAlpha( res = aBmp; } - pAlphaW.reset(); - mpAlphaVDev->DrawBitmap( aDstRect.TopLeft(), aAlphaBitmap ); - mpAlphaVDev->EnableMapMode( bOldMapMode ); - return res; } diff --git a/vcl/source/outdev/bitmapex.cxx b/vcl/source/outdev/bitmapex.cxx index 2fcc8792474c..8e65756d58b9 100644 --- a/vcl/source/outdev/bitmapex.cxx +++ b/vcl/source/outdev/bitmapex.cxx @@ -150,16 +150,7 @@ void OutputDevice::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize, BitmapEx OutputDevice::GetBitmapEx( const Point& rSrcPt, const Size& rSize ) const { - if (!mpAlphaVDev) - return BitmapEx(GetBitmap(rSrcPt, rSize)); - - // #110958# Extract alpha value from VDev, if any - Bitmap aAlphaBitmap(mpAlphaVDev->GetBitmap(rSrcPt, rSize)); - - if (aAlphaBitmap.getPixelFormat() > vcl::PixelFormat::N8_BPP) - aAlphaBitmap.Convert(BmpConversion::N8BitNoConversion); - - return BitmapEx(GetBitmap(rSrcPt, rSize), AlphaMask(aAlphaBitmap)); + return BitmapEx(GetBitmap( rSrcPt, rSize )); } void OutputDevice::DrawDeviceBitmapEx( const Point& rDestPt, const Size& rDestSize, @@ -198,12 +189,6 @@ void OutputDevice::DrawDeviceBitmapEx( const Point& rDestPt, const Size& rDestSi && "I removed some code here that will need to be restored"); mpGraphics->DrawBitmap(aPosAry, *pSalSrcBmp, *this); - - if (mpAlphaVDev) - { - // #i32109#: Make bitmap area opaque - mpAlphaVDev->ImplFillOpaqueRectangle(tools::Rectangle(rDestPt, rDestSize)); - } } bool OutputDevice::DrawTransformBitmapExDirect( @@ -224,33 +209,17 @@ bool OutputDevice::DrawTransformBitmapExDirect( { aAlphaBitmap = rBitmapEx.GetAlphaMask(); } - else if (mpAlphaVDev) - { - aAlphaBitmap = AlphaMask(rBitmapEx.GetSizePixel()); - aAlphaBitmap.Erase(0); // opaque - } SalBitmap* pSalAlphaBmp = aAlphaBitmap.GetBitmap().ImplGetSalBitmap().get(); - if (!mpGraphics->DrawTransformedBitmap( + return mpGraphics->DrawTransformedBitmap( aNull, aTopX, aTopY, *pSalSrcBmp, pSalAlphaBmp, fAlpha, - *this)) - return false; - - if (mpAlphaVDev) - { - // Merge bitmap alpha to alpha device - AlphaMask aAlpha(rBitmapEx.GetSizePixel()); - aAlpha.Erase( ( 1 - fAlpha ) * 255 ); - mpAlphaVDev->DrawTransformBitmapExDirect(aFullTransform, BitmapEx(aAlpha.GetBitmap(), aAlphaBitmap)); - } - - return true; + *this); }; bool OutputDevice::TransformAndReduceBitmapExToTargetRange( diff --git a/vcl/source/outdev/clipping.cxx b/vcl/source/outdev/clipping.cxx index 6efc9df9d052..74c30d0ae0b5 100644 --- a/vcl/source/outdev/clipping.cxx +++ b/vcl/source/outdev/clipping.cxx @@ -45,9 +45,6 @@ void OutputDevice::SetClipRegion() mpMetaFile->AddAction( new MetaClipRegionAction( vcl::Region(), false ) ); SetDeviceClipRegion( nullptr ); - - if( mpAlphaVDev ) - mpAlphaVDev->SetClipRegion(); } void OutputDevice::SetClipRegion( const vcl::Region& rRegion ) @@ -65,9 +62,6 @@ void OutputDevice::SetClipRegion( const vcl::Region& rRegion ) vcl::Region aRegion = LogicToPixel( rRegion ); SetDeviceClipRegion( &aRegion ); } - - if( mpAlphaVDev ) - mpAlphaVDev->SetClipRegion( rRegion ); } bool OutputDevice::SelectClipRegion( const vcl::Region& rRegion, SalGraphics* pGraphics ) @@ -88,7 +82,6 @@ bool OutputDevice::SelectClipRegion( const vcl::Region& rRegion, SalGraphics* pG void OutputDevice::MoveClipRegion( tools::Long nHorzMove, tools::Long nVertMove ) { - if ( mbClipRegion ) { if( mpMetaFile ) @@ -98,14 +91,10 @@ void OutputDevice::MoveClipRegion( tools::Long nHorzMove, tools::Long nVertMove ImplLogicHeightToDevicePixel( nVertMove ) ); mbInitClipRegion = true; } - - if( mpAlphaVDev ) - mpAlphaVDev->MoveClipRegion( nHorzMove, nVertMove ); } void OutputDevice::IntersectClipRegion( const tools::Rectangle& rRect ) { - if ( mpMetaFile ) mpMetaFile->AddAction( new MetaISectRectClipRegionAction( rRect ) ); @@ -113,14 +102,10 @@ void OutputDevice::IntersectClipRegion( const tools::Rectangle& rRect ) maRegion.Intersect( aRect ); mbClipRegion = true; mbInitClipRegion = true; - - if( mpAlphaVDev ) - mpAlphaVDev->IntersectClipRegion( rRect ); } void OutputDevice::IntersectClipRegion( const vcl::Region& rRegion ) { - if(!rRegion.IsNull()) { if ( mpMetaFile ) @@ -131,9 +116,6 @@ void OutputDevice::IntersectClipRegion( const vcl::Region& rRegion ) mbClipRegion = true; mbInitClipRegion = true; } - - if( mpAlphaVDev ) - mpAlphaVDev->IntersectClipRegion( rRegion ); } void OutputDevice::InitClipRegion() diff --git a/vcl/source/outdev/curvedshapes.cxx b/vcl/source/outdev/curvedshapes.cxx index b5a13fb721d9..884587dcac50 100644 --- a/vcl/source/outdev/curvedshapes.cxx +++ b/vcl/source/outdev/curvedshapes.cxx @@ -64,9 +64,6 @@ void OutputDevice::DrawEllipse( const tools::Rectangle& rRect ) mpGraphics->DrawPolygon( aRectPoly.GetSize(), pPtAry, *this ); } } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawEllipse( rRect ); } void OutputDevice::DrawArc( const tools::Rectangle& rRect, @@ -106,9 +103,6 @@ void OutputDevice::DrawArc( const tools::Rectangle& rRect, Point* pPtAry = aArcPoly.GetPointAry(); mpGraphics->DrawPolyLine( aArcPoly.GetSize(), pPtAry, *this ); } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawArc( rRect, rStartPt, rEndPt ); } void OutputDevice::DrawPie( const tools::Rectangle& rRect, @@ -155,9 +149,6 @@ void OutputDevice::DrawPie( const tools::Rectangle& rRect, mpGraphics->DrawPolygon( aPiePoly.GetSize(), pPtAry, *this ); } } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawPie( rRect, rStartPt, rEndPt ); } void OutputDevice::DrawChord( const tools::Rectangle& rRect, @@ -204,9 +195,6 @@ void OutputDevice::DrawChord( const tools::Rectangle& rRect, mpGraphics->DrawPolygon( aChordPoly.GetSize(), pPtAry, *this ); } } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawChord( rRect, rStartPt, rEndPt ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/outdev/eps.cxx b/vcl/source/outdev/eps.cxx index 3f436ee327c9..4d529d11919b 100644 --- a/vcl/source/outdev/eps.cxx +++ b/vcl/source/outdev/eps.cxx @@ -75,9 +75,6 @@ bool OutputDevice::DrawEPS( const Point& rPoint, const Size& rSize, } } - if( mpAlphaVDev ) - mpAlphaVDev->DrawEPS( rPoint, rSize, rGfxLink, pSubst ); - return bDrawn; } diff --git a/vcl/source/outdev/fill.cxx b/vcl/source/outdev/fill.cxx index 067762d17838..b108328e3d8b 100644 --- a/vcl/source/outdev/fill.cxx +++ b/vcl/source/outdev/fill.cxx @@ -28,7 +28,6 @@ void OutputDevice::SetFillColor() { - if ( mpMetaFile ) mpMetaFile->AddAction( new MetaFillColorAction( Color(), false ) ); @@ -38,9 +37,6 @@ void OutputDevice::SetFillColor() mbFillColor = false; maFillColor = COL_TRANSPARENT; } - - if( mpAlphaVDev ) - mpAlphaVDev->SetFillColor(); } void OutputDevice::SetFillColor( const Color& rColor ) @@ -56,12 +52,6 @@ void OutputDevice::SetFillColor( const Color& rColor ) mbFillColor = true; maFillColor = aColor; } - - if( mpAlphaVDev ) - { - sal_uInt8 nAlpha = rColor.GetAlpha(); - mpAlphaVDev->SetFillColor( Color(nAlpha, nAlpha, nAlpha) ); - } } void OutputDevice::InitFillColor() diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx index b3d4022eb53b..7b45f7782893 100644 --- a/vcl/source/outdev/font.cxx +++ b/vcl/source/outdev/font.cxx @@ -82,21 +82,6 @@ void OutputDevice::SetFont( const vcl::Font& rNewFont ) } maFont = aFont; mbNewFont = true; - - if( !mpAlphaVDev ) - return; - - // #i30463# - // Since SetFont might change the text color, apply that only - // selectively to alpha vdev (which normally paints opaque text - // with COL_BLACK) - if( aFont.GetColor() != COL_TRANSPARENT ) - { - mpAlphaVDev->SetTextColor( COL_ALPHA_OPAQUE ); - aFont.SetColor( COL_TRANSPARENT ); - } - - mpAlphaVDev->SetFont( aFont ); } FontMetric OutputDevice::GetFontMetricFromCollection(int nDevFontIndex) const @@ -148,9 +133,6 @@ bool OutputDevice::AddTempDevFont( const OUString& rFileURL, const OUString& rFo if( !bRC ) return false; - if( mpAlphaVDev ) - mpAlphaVDev->AddTempDevFont( rFileURL, rFontName ); - return true; } diff --git a/vcl/source/outdev/gradient.cxx b/vcl/source/outdev/gradient.cxx index 1a2c3c7c00bd..d2251799b7e0 100644 --- a/vcl/source/outdev/gradient.cxx +++ b/vcl/source/outdev/gradient.cxx @@ -143,14 +143,6 @@ void OutputDevice::DrawGradient( const tools::PolyPolygon& rPolyPoly, } } } - - if( mpAlphaVDev ) - { - mpAlphaVDev->Push(vcl::PushFlags::FILLCOLOR); - mpAlphaVDev->SetFillColor( COL_ALPHA_OPAQUE ); - mpAlphaVDev->DrawPolyPolygon( rPolyPoly ); - mpAlphaVDev->Pop(); - } } void OutputDevice::ClipAndDrawGradientMetafile ( const Gradient &rGradient, const tools::PolyPolygon &rPolyPoly ) diff --git a/vcl/source/outdev/hatch.cxx b/vcl/source/outdev/hatch.cxx index 09629d7eedcc..ccf148d43b9e 100644 --- a/vcl/source/outdev/hatch.cxx +++ b/vcl/source/outdev/hatch.cxx @@ -92,9 +92,6 @@ void OutputDevice::DrawHatch( const tools::PolyPolygon& rPolyPoly, const Hatch& EnableMapMode( bOldMap ); mpMetaFile = pOldMetaFile; } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawHatch( rPolyPoly, rHatch ); } void OutputDevice::AddHatchActions( const tools::PolyPolygon& rPolyPoly, const Hatch& rHatch, diff --git a/vcl/source/outdev/line.cxx b/vcl/source/outdev/line.cxx index e4387a3498ed..f4d590fe5311 100644 --- a/vcl/source/outdev/line.cxx +++ b/vcl/source/outdev/line.cxx @@ -36,7 +36,6 @@ void OutputDevice::SetLineColor() { - if ( mpMetaFile ) mpMetaFile->AddAction( new MetaLineColorAction( Color(), false ) ); @@ -46,9 +45,6 @@ void OutputDevice::SetLineColor() mbLineColor = false; maLineColor = COL_TRANSPARENT; } - - if( mpAlphaVDev ) - mpAlphaVDev->SetLineColor(); } void OutputDevice::SetLineColor( const Color& rColor ) @@ -76,9 +72,6 @@ void OutputDevice::SetLineColor( const Color& rColor ) maLineColor = aColor; } } - - if( mpAlphaVDev ) - mpAlphaVDev->SetLineColor( COL_ALPHA_OPAQUE ); } void OutputDevice::InitLineColor() @@ -152,9 +145,6 @@ void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt, { mpGraphics->DrawLine( aStartPt.X(), aStartPt.Y(), aEndPt.X(), aEndPt.Y(), *this ); } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawLine( rStartPt, rEndPt, rLineInfo ); } void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt ) @@ -214,9 +204,6 @@ void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt ) const Point aEndPt(ImplLogicToDevicePixel(rEndPt)); mpGraphics->DrawLine( aStartPt.X(), aStartPt.Y(), aEndPt.X(), aEndPt.Y(), *this ); } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawLine( rStartPt, rEndPt ); } void OutputDevice::drawLine( basegfx::B2DPolyPolygon aLinePolyPolygon, const LineInfo& rInfo ) diff --git a/vcl/source/outdev/map.cxx b/vcl/source/outdev/map.cxx index 8edf0f3be14a..5ef6e922e6aa 100644 --- a/vcl/source/outdev/map.cxx +++ b/vcl/source/outdev/map.cxx @@ -620,14 +620,10 @@ vcl::Region OutputDevice::ImplPixelToDevicePixel( const vcl::Region& rRegion ) c void OutputDevice::EnableMapMode( bool bEnable ) { mbMap = bEnable; - - if( mpAlphaVDev ) - mpAlphaVDev->EnableMapMode( bEnable ); } void OutputDevice::SetMapMode() { - if ( mpMetaFile ) mpMetaFile->AddAction( new MetaMapModeAction( MapMode() ) ); @@ -648,9 +644,6 @@ void OutputDevice::SetMapMode() // #i75163# ImplInvalidateViewTransform(); } - - if( mpAlphaVDev ) - mpAlphaVDev->SetMapMode(); } void OutputDevice::SetMapMode( const MapMode& rNewMapMode ) @@ -667,9 +660,6 @@ void OutputDevice::SetMapMode( const MapMode& rNewMapMode ) if ( maMapMode == rNewMapMode ) return; - if( mpAlphaVDev ) - mpAlphaVDev->SetMapMode( rNewMapMode ); - // if default MapMode calculate nothing bool bOldMap = mbMap; mbMap = !rNewMapMode.IsDefault(); @@ -815,9 +805,6 @@ void OutputDevice::SetRelativeMapMode( const MapMode& rNewMapMode ) maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX ); mnOutOffLogicY = ImplPixelToLogic( mnOutOffOrigY, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY ); - - if( mpAlphaVDev ) - mpAlphaVDev->SetRelativeMapMode( rNewMapMode ); } // #i75163# @@ -1867,9 +1854,6 @@ void OutputDevice::SetPixelOffset( const Size& rOffset ) maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX ); mnOutOffLogicY = ImplPixelToLogic( mnOutOffOrigY, mnDPIY, maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY ); - - if( mpAlphaVDev ) - mpAlphaVDev->SetPixelOffset( rOffset ); } diff --git a/vcl/source/outdev/mask.cxx b/vcl/source/outdev/mask.cxx index 9a7b57c6b3bb..cd07b33ae0dd 100644 --- a/vcl/source/outdev/mask.cxx +++ b/vcl/source/outdev/mask.cxx @@ -140,23 +140,6 @@ void OutputDevice::DrawDeviceMask( const Bitmap& rMask, const Color& rMaskColor, } } - - // TODO: Use mask here - if( !mpAlphaVDev ) - return; - - const Bitmap aAlphaMask( rMask.CreateMask( rMaskColor ) ); - - // #i25167# Restrict mask painting to _opaque_ areas - // of the mask, otherwise we spoil areas where no - // bitmap content was ever visible. Interestingly - // enough, this can be achieved by taking the mask as - // the transparency mask of itself - mpAlphaVDev->DrawBitmapEx( rDestPt, - rDestSize, - rSrcPtPixel, - rSrcSizePixel, - BitmapEx( aAlphaMask, rMask ) ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/outdev/outdev.cxx b/vcl/source/outdev/outdev.cxx index 43b6650ce4e8..288d25ab8a3a 100644 --- a/vcl/source/outdev/outdev.cxx +++ b/vcl/source/outdev/outdev.cxx @@ -70,7 +70,6 @@ OutputDevice::OutputDevice(OutDevType eOutDevType) : mpFontInstance = nullptr; mpForcedFallbackInstance = nullptr; mpFontFaceCollection = nullptr; - mpAlphaVDev = nullptr; mpExtOutDevData = nullptr; mnOutOffX = 0; mnOutOffY = 0; @@ -178,7 +177,6 @@ void OutputDevice::dispose() // release ImplFontList specific to this OutputDevice mxFontCollection.reset(); - mpAlphaVDev.disposeAndClear(); mpPrevGraphics.reset(); mpNextGraphics.reset(); VclReferenceBase::dispose(); @@ -217,9 +215,6 @@ void OutputDevice::SetConnectMetaFile( GDIMetaFile* pMtf ) void OutputDevice::SetSettings( const AllSettings& rSettings ) { *moSettings = rSettings; - - if( mpAlphaVDev ) - mpAlphaVDev->SetSettings( rSettings ); } SystemGraphicsData OutputDevice::GetSystemGfxData() const @@ -307,9 +302,6 @@ void OutputDevice::SetRefPoint() mbRefPoint = false; maRefPoint.setX(0); maRefPoint.setY(0); - - if( mpAlphaVDev ) - mpAlphaVDev->SetRefPoint(); } void OutputDevice::SetRefPoint( const Point& rRefPoint ) @@ -319,9 +311,6 @@ void OutputDevice::SetRefPoint( const Point& rRefPoint ) mbRefPoint = true; maRefPoint = rRefPoint; - - if( mpAlphaVDev ) - mpAlphaVDev->SetRefPoint( rRefPoint ); } void OutputDevice::SetRasterOp( RasterOp eRasterOp ) @@ -340,17 +329,11 @@ void OutputDevice::SetRasterOp( RasterOp eRasterOp ) mpGraphics->SetXORMode( (RasterOp::Invert == meRasterOp) || (RasterOp::Xor == meRasterOp), RasterOp::Invert == meRasterOp ); } } - - if( mpAlphaVDev ) - mpAlphaVDev->SetRasterOp( eRasterOp ); } void OutputDevice::EnableOutput( bool bEnable ) { mbOutput = bEnable; - - if( mpAlphaVDev ) - mpAlphaVDev->EnableOutput( bEnable ); } void OutputDevice::SetAntialiasing( AntialiasingFlags nMode ) @@ -363,17 +346,11 @@ void OutputDevice::SetAntialiasing( AntialiasingFlags nMode ) if (mpGraphics) mpGraphics->setAntiAlias(bool(mnAntialiasing & AntialiasingFlags::Enable)); } - - if( mpAlphaVDev ) - mpAlphaVDev->SetAntialiasing( nMode ); } void OutputDevice::SetDrawMode(DrawModeFlags nDrawMode) { mnDrawMode = nDrawMode; - - if (mpAlphaVDev) - mpAlphaVDev->SetDrawMode(nDrawMode); } sal_uInt16 OutputDevice::GetBitCount() const @@ -469,9 +446,6 @@ void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize, if ( aPosAry.mnSrcWidth && aPosAry.mnSrcHeight && aPosAry.mnDestWidth && aPosAry.mnDestHeight ) mpGraphics->CopyBits(aPosAry, *this); } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawOutDev( rDestPt, rDestSize, rSrcPt, rSrcSize ); } void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize, @@ -489,16 +463,8 @@ void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize, if ( mpMetaFile ) { - if (rOutDev.mpAlphaVDev) - { - const BitmapEx aBmpEx(rOutDev.GetBitmapEx(rSrcPt, rSrcSize)); - mpMetaFile->AddAction(new MetaBmpExScaleAction(rDestPt, rDestSize, aBmpEx)); - } - else - { - const Bitmap aBmp(rOutDev.GetBitmap(rSrcPt, rSrcSize)); - mpMetaFile->AddAction(new MetaBmpScaleAction(rDestPt, rDestSize, aBmp)); - } + const BitmapEx aBmpEx(rOutDev.GetBitmapEx(rSrcPt, rSrcSize)); + mpMetaFile->AddAction(new MetaBmpExScaleAction(rDestPt, rDestSize, aBmpEx)); } if ( !IsDeviceOutputNecessary() ) @@ -514,28 +480,17 @@ void OutputDevice::DrawOutDev( const Point& rDestPt, const Size& rDestSize, if ( mbOutputClipped ) return; - if (rOutDev.mpAlphaVDev) - { - // alpha-blend source over destination - DrawBitmapEx(rDestPt, rDestSize, rOutDev.GetBitmapEx(rSrcPt, rSrcSize)); - } - else - { - SalTwoRect aPosAry(rOutDev.ImplLogicXToDevicePixel(rSrcPt.X()), - rOutDev.ImplLogicYToDevicePixel(rSrcPt.Y()), - rOutDev.ImplLogicWidthToDevicePixel(rSrcSize.Width()), - rOutDev.ImplLogicHeightToDevicePixel(rSrcSize.Height()), - ImplLogicXToDevicePixel(rDestPt.X()), - ImplLogicYToDevicePixel(rDestPt.Y()), - ImplLogicWidthToDevicePixel(rDestSize.Width()), - ImplLogicHeightToDevicePixel(rDestSize.Height())); + SalTwoRect aPosAry(rOutDev.ImplLogicXToDevicePixel(rSrcPt.X()), + rOutDev.ImplLogicYToDevicePixel(rSrcPt.Y()), + rOutDev.ImplLogicWidthToDevicePixel(rSrcSize.Width()), + rOutDev.ImplLogicHeightToDevicePixel(rSrcSize.Height()), + ImplLogicXToDevicePixel(rDestPt.X()), + ImplLogicYToDevicePixel(rDestPt.Y()), + ImplLogicWidthToDevicePixel(rDestSize.Width()), + ImplLogicHeightToDevicePixel(rDestSize.Height())); - drawOutDevDirect(rOutDev, aPosAry); - - // #i32109#: make destination rectangle opaque - source has no alpha - if (mpAlphaVDev) - mpAlphaVDev->ImplFillOpaqueRectangle(tools::Rectangle(rDestPt, rDestSize)); - } + // if we have alpha, this will blend source over destination + drawOutDevDirect(rOutDev, aPosAry); } void OutputDevice::CopyArea( const Point& rDestPt, @@ -576,9 +531,6 @@ void OutputDevice::CopyArea( const Point& rDestPt, } SetRasterOp( eOldRop ); - - if( mpAlphaVDev ) - mpAlphaVDev->CopyArea( rDestPt, rSrcPt, rSrcSize, bWindowInvalidate ); } // Direct OutputDevice drawing protected function @@ -654,9 +606,6 @@ tools::Rectangle OutputDevice::GetBackgroundComponentBounds() const void OutputDevice::EnableRTL( bool bEnable ) { mbEnableRTL = bEnable; - - if( mpAlphaVDev ) - mpAlphaVDev->EnableRTL( bEnable ); } bool OutputDevice::ImplIsAntiparallel() const diff --git a/vcl/source/outdev/pixel.cxx b/vcl/source/outdev/pixel.cxx index 8c97aeb43237..fa38a78005e2 100644 --- a/vcl/source/outdev/pixel.cxx +++ b/vcl/source/outdev/pixel.cxx @@ -40,12 +40,6 @@ Color OutputDevice::GetPixel(const Point& rPoint) const const tools::Long nX = ImplLogicXToDevicePixel(rPoint.X()); const tools::Long nY = ImplLogicYToDevicePixel(rPoint.Y()); aColor = mpGraphics->GetPixel(nX, nY, *this); - - if (mpAlphaVDev) - { - Color aAlphaColor = mpAlphaVDev->GetPixel(rPoint); - aColor.SetAlpha(aAlphaColor.GetBlue()); - } } } return aColor; @@ -77,9 +71,6 @@ void OutputDevice::DrawPixel( const Point& rPt ) InitLineColor(); mpGraphics->DrawPixel( aPt.X(), aPt.Y(), *this ); - - if( mpAlphaVDev ) - mpAlphaVDev->DrawPixel( rPt ); } void OutputDevice::DrawPixel( const Point& rPt, const Color& rColor ) @@ -107,12 +98,6 @@ void OutputDevice::DrawPixel( const Point& rPt, const Color& rColor ) return; mpGraphics->DrawPixel( aPt.X(), aPt.Y(), aColor, *this ); - - if (mpAlphaVDev) - { - Color aAlphaColor(rColor.GetAlpha(), rColor.GetAlpha(), rColor.GetAlpha()); - mpAlphaVDev->DrawPixel(rPt, aAlphaColor); - } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/outdev/polygon.cxx b/vcl/source/outdev/polygon.cxx index e764e6b66dbe..6aa164037dd6 100644 --- a/vcl/source/outdev/polygon.cxx +++ b/vcl/source/outdev/polygon.cxx @@ -105,11 +105,7 @@ void OutputDevice::DrawPolyPolygon( const tools::PolyPolygon& rPolyPoly ) } if(bSuccess) - { - if( mpAlphaVDev ) - mpAlphaVDev->DrawPolyPolygon( rPolyPoly ); return; - } } if ( nPoly == 1 ) @@ -133,8 +129,6 @@ void OutputDevice::DrawPolyPolygon( const tools::PolyPolygon& rPolyPoly ) // ImplLogicToDevicePixel calls ImplDrawPolyPolygon( nPoly, ImplLogicToDevicePixel( rPolyPoly ) ); } - if( mpAlphaVDev ) - mpAlphaVDev->DrawPolyPolygon( rPolyPoly ); } void OutputDevice::DrawPolygon( const basegfx::B2DPolygon& rB2DPolygon) @@ -218,11 +212,7 @@ void OutputDevice::DrawPolygon( const tools::Polygon& rPoly ) } if(bSuccess) - { - if( mpAlphaVDev ) - mpAlphaVDev->DrawPolygon( rPoly ); return; - } } tools::Polygon aPoly = ImplLogicToDevicePixel( rPoly ); @@ -243,8 +233,6 @@ void OutputDevice::DrawPolygon( const tools::Polygon& rPoly ) { mpGraphics->DrawPolygon( nPoints, pPtAry, *this ); } - if( mpAlphaVDev ) - mpAlphaVDev->DrawPolygon( rPoly ); } // Caution: This method is nearly the same as @@ -338,9 +326,6 @@ void OutputDevice::ImplDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyP const tools::PolyPolygon aPixelPolyPolygon = ImplLogicToDevicePixel(aToolsPolyPolygon); ImplDrawPolyPolygon(aPixelPolyPolygon.Count(), aPixelPolyPolygon); } - - if (mpAlphaVDev) - mpAlphaVDev->ImplDrawPolyPolygonWithB2DPolyPolygon(rB2DPolyPoly); } // #100127# Extracted from OutputDevice::DrawPolyPolygon() diff --git a/vcl/source/outdev/polyline.cxx b/vcl/source/outdev/polyline.cxx index 75e8252f4ae2..63dafcbb4308 100644 --- a/vcl/source/outdev/polyline.cxx +++ b/vcl/source/outdev/polyline.cxx @@ -99,9 +99,6 @@ void OutputDevice::DrawPolyLine( const tools::Polygon& rPoly ) mpGraphics->DrawPolyLine( nPoints, pPtAry, *this ); } } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawPolyLine( rPoly ); } void OutputDevice::DrawPolyLine( const tools::Polygon& rPoly, const LineInfo& rLineInfo ) @@ -298,9 +295,6 @@ void OutputDevice::drawPolyLine(const tools::Polygon& rPoly, const LineInfo& rLi mpGraphics->DrawPolyLine(nPoints, aPoly.GetPointAry(), *this); } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawPolyLine( rPoly, rLineInfo ); } bool OutputDevice::DrawPolyLineDirect( @@ -374,12 +368,11 @@ bool OutputDevice::DrawPolyLineDirectInternal( const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation() * rObjectTransform); const bool bPixelSnapHairline((mnAntialiasing & AntialiasingFlags::PixelSnapHairline) && rB2DPolygon.count() < 1000); - const double fAdjustedTransparency = mpAlphaVDev ? 0 : fTransparency; // draw the polyline - bool bDrawSuccess = mpGraphics->DrawPolyLine( + return mpGraphics->DrawPolyLine( aTransform, rB2DPolygon, - fAdjustedTransparency, + fTransparency, fLineWidth, // tdf#124848 use LineWidth direct, do not try to solve for zero-case (aka hairline) pStroke, // MM01 eLineJoin, @@ -387,16 +380,6 @@ bool OutputDevice::DrawPolyLineDirectInternal( fMiterMinimumAngle, bPixelSnapHairline, *this); - - if( bDrawSuccess ) - { - if (mpAlphaVDev) - mpAlphaVDev->DrawPolyLineDirect(rObjectTransform, rB2DPolygon, fLineWidth, - fTransparency, pStroke, eLineJoin, eLineCap, - fMiterMinimumAngle); - - return true; - } } return false; } diff --git a/vcl/source/outdev/rect.cxx b/vcl/source/outdev/rect.cxx index 227263f23fdf..efd693e13c82 100644 --- a/vcl/source/outdev/rect.cxx +++ b/vcl/source/outdev/rect.cxx @@ -81,9 +81,6 @@ void OutputDevice::DrawRect( const tools::Rectangle& rRect ) InitFillColor(); mpGraphics->DrawRect( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), *this ); - - if( mpAlphaVDev ) - mpAlphaVDev->DrawRect( rRect ); } void OutputDevice::DrawRect( const tools::Rectangle& rRect, @@ -140,9 +137,6 @@ void OutputDevice::DrawRect( const tools::Rectangle& rRect, mpGraphics->DrawPolygon( aRoundRectPoly.GetSize(), pPtAry, *this ); } } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawRect( rRect, nHorzRound, nVertRound ); } void OutputDevice::Invert( const tools::Rectangle& rRect, InvertFlags nFlags ) @@ -332,9 +326,6 @@ void OutputDevice::DrawGrid( const tools::Rectangle& rRect, const Size& rDist, D } EnableMapMode( bOldMap ); - - if( mpAlphaVDev ) - mpAlphaVDev->DrawGrid( rRect, rDist, nFlags ); } BmpMirrorFlags AdjustTwoRect( SalTwoRect& rTwoRect, const Size& rSizePix ) diff --git a/vcl/source/outdev/stack.cxx b/vcl/source/outdev/stack.cxx index 72ef63af551d..9b32d4c5b7c8 100644 --- a/vcl/source/outdev/stack.cxx +++ b/vcl/source/outdev/stack.cxx @@ -83,9 +83,6 @@ void OutputDevice::Push(vcl::PushFlags nFlags) if (nFlags & vcl::PushFlags::REFPOINT && mbRefPoint) rState.mpRefPoint = maRefPoint; - - if (mpAlphaVDev) - mpAlphaVDev->Push(); } void OutputDevice::Pop() @@ -103,9 +100,6 @@ void OutputDevice::Pop() } const vcl::State& rState = maOutDevStateStack.back(); - if( mpAlphaVDev ) - mpAlphaVDev->Pop(); - if ( rState.mnFlags & vcl::PushFlags::LINECOLOR ) { if ( rState.mpLineColor ) diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx index 7941d4a1399d..4bef5eef1ce2 100644 --- a/vcl/source/outdev/text.cxx +++ b/vcl/source/outdev/text.cxx @@ -56,9 +56,6 @@ void OutputDevice::SetLayoutMode( vcl::text::ComplexTextLayoutFlags nTextLayoutM mpMetaFile->AddAction( new MetaLayoutModeAction( nTextLayoutMode ) ); mnTextLayoutMode = nTextLayoutMode; - - if( mpAlphaVDev ) - mpAlphaVDev->SetLayoutMode( nTextLayoutMode ); } void OutputDevice::SetDigitLanguage( LanguageType eTextLanguage ) @@ -67,9 +64,6 @@ void OutputDevice::SetDigitLanguage( LanguageType eTextLanguage ) mpMetaFile->AddAction( new MetaTextLanguageAction( eTextLanguage ) ); meTextLanguage = eTextLanguage; - - if( mpAlphaVDev ) - mpAlphaVDev->SetDigitLanguage( eTextLanguage ); } void OutputDevice::ImplInitTextColor() @@ -483,14 +477,10 @@ void OutputDevice::SetTextColor( const Color& rColor ) maTextColor = aColor; mbInitTextColor = true; } - - if( mpAlphaVDev ) - mpAlphaVDev->SetTextColor( COL_ALPHA_OPAQUE ); } void OutputDevice::SetTextFillColor() { - if ( mpMetaFile ) mpMetaFile->AddAction( new MetaTextFillColorAction( Color(), false ) ); @@ -499,9 +489,6 @@ void OutputDevice::SetTextFillColor() } if ( !maFont.IsTransparent() ) maFont.SetTransparent( true ); - - if( mpAlphaVDev ) - mpAlphaVDev->SetTextFillColor(); } void OutputDevice::SetTextFillColor( const Color& rColor ) @@ -515,9 +502,6 @@ void OutputDevice::SetTextFillColor( const Color& rColor ) maFont.SetFillColor( aColor ); if ( maFont.IsTransparent() != rColor.IsTransparent() ) maFont.SetTransparent( rColor.IsTransparent() ); - - if( mpAlphaVDev ) - mpAlphaVDev->SetTextFillColor( COL_ALPHA_OPAQUE ); } Color OutputDevice::GetTextFillColor() const @@ -530,7 +514,6 @@ Color OutputDevice::GetTextFillColor() const void OutputDevice::SetTextAlign( TextAlign eAlign ) { - if ( mpMetaFile ) mpMetaFile->AddAction( new MetaTextAlignAction( eAlign ) ); @@ -539,9 +522,6 @@ void OutputDevice::SetTextAlign( TextAlign eAlign ) maFont.SetAlignment( eAlign ); mbNewFont = true; } - - if( mpAlphaVDev ) - mpAlphaVDev->SetTextAlign( eAlign ); } vcl::Region OutputDevice::GetOutputBoundsClipRegion() const @@ -635,9 +615,6 @@ void OutputDevice::DrawText( const Point& rStartPt, const OUString& rStr, { ImplDrawText( *pSalLayout ); } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawText( rStartPt, rStr, nIndex, nLen, pVector, pDisplayText ); } tools::Long OutputDevice::GetTextWidth( const OUString& rStr, sal_Int32 nIndex, sal_Int32 nLen, @@ -740,12 +717,6 @@ void OutputDevice::DrawPartialTextArray(const Point& rStartPt, const OUString& r { ImplDrawText(*pSalLayout); } - - if (mpAlphaVDev) - { - mpAlphaVDev->DrawPartialTextArray(rStartPt, rStr, pDXArray, pKashidaArray, nIndex, nLen, - nPartIndex, nPartLen, flags, pLayoutCache); - } } void OutputDevice::DrawTextArray( const Point& rStartPt, const OUString& rStr, @@ -778,9 +749,6 @@ void OutputDevice::DrawTextArray( const Point& rStartPt, const OUString& rStr, { ImplDrawText( *pSalLayout ); } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawTextArray( rStartPt, rStr, pDXAry, pKashidaAry, nIndex, nLen, flags ); } double @@ -992,9 +960,6 @@ void OutputDevice::DrawStretchText( const Point& rStartPt, sal_Int32 nWidth, { ImplDrawText( *pSalLayout ); } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawStretchText( rStartPt, nWidth, rStr, nIndex, nLen ); } vcl::text::ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( OUString& rStr, @@ -1790,9 +1755,6 @@ void OutputDevice::DrawText( const tools::Rectangle& rRect, const OUString& rOri // and enable again mpMetaFile = pMtf; - - if( mpAlphaVDev ) - mpAlphaVDev->DrawText( rRect, rOrigStr, nStyle, pVector, pDisplayText ); } tools::Rectangle OutputDevice::GetTextRect( const tools::Rectangle& rRect, @@ -2041,9 +2003,6 @@ void OutputDevice::DrawCtrlText( const Point& rPos, const OUString& rStr, SetTextColor( *oOldTextColor ); if (oOldTextFillColor) SetTextFillColor(*oOldTextFillColor); - - if( mpAlphaVDev ) - mpAlphaVDev->DrawCtrlText( rPos, rStr, nIndex, nLen, nStyle, pVector, pDisplayText ); } tools::Long OutputDevice::GetCtrlTextWidth( const OUString& rStr, const SalLayoutGlyphs* pGlyphs ) const diff --git a/vcl/source/outdev/textline.cxx b/vcl/source/outdev/textline.cxx index bde74b2a494c..837870f7cd06 100644 --- a/vcl/source/outdev/textline.cxx +++ b/vcl/source/outdev/textline.cxx @@ -919,14 +919,10 @@ void OutputDevice::ImplDrawMnemonicLine( tools::Long nX, tools::Long nY, tools:: void OutputDevice::SetTextLineColor() { - if ( mpMetaFile ) mpMetaFile->AddAction( new MetaTextLineColorAction( Color(), false ) ); maTextLineColor = COL_TRANSPARENT; - - if( mpAlphaVDev ) - mpAlphaVDev->SetTextLineColor(); } void OutputDevice::SetTextLineColor( const Color& rColor ) @@ -937,21 +933,14 @@ void OutputDevice::SetTextLineColor( const Color& rColor ) mpMetaFile->AddAction( new MetaTextLineColorAction( aColor, true ) ); maTextLineColor = aColor; - - if( mpAlphaVDev ) - mpAlphaVDev->SetTextLineColor( COL_ALPHA_OPAQUE ); } void OutputDevice::SetOverlineColor() { - if ( mpMetaFile ) mpMetaFile->AddAction( new MetaOverlineColorAction( Color(), false ) ); maOverlineColor = COL_TRANSPARENT; - - if( mpAlphaVDev ) - mpAlphaVDev->SetOverlineColor(); } void OutputDevice::SetOverlineColor( const Color& rColor ) @@ -962,9 +951,6 @@ void OutputDevice::SetOverlineColor( const Color& rColor ) mpMetaFile->AddAction( new MetaOverlineColorAction( aColor, true ) ); maOverlineColor = aColor; - - if( mpAlphaVDev ) - mpAlphaVDev->SetOverlineColor( COL_ALPHA_OPAQUE ); } void OutputDevice::DrawTextLine( const Point& rPos, tools::Long nWidth, @@ -1002,9 +988,6 @@ void OutputDevice::DrawTextLine( const Point& rPos, tools::Long nWidth, double fWidth = ImplLogicWidthToDeviceSubPixel(nWidth); aPos += Point( mnTextOffX, mnTextOffY ); ImplDrawTextLine( aPos.X(), aPos.X(), 0, fWidth, fWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove ); - - if( mpAlphaVDev ) - mpAlphaVDev->DrawTextLine( rPos, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove ); } void OutputDevice::DrawWaveLine(const Point& rStartPos, const Point& rEndPos, tools::Long nLineWidth, tools::Long nWaveHeight) @@ -1149,9 +1132,6 @@ void OutputDevice::ImplDrawWaveLineBezier(tools::Long nStartX, tools::Long nStar basegfx::deg2rad(15.0), bPixelSnapHairline, *this); - - if( mpAlphaVDev ) - mpAlphaVDev->ImplDrawWaveLineBezier(nStartX, nStartY, nEndX, nEndY, nWaveHeight, fOrientation, nLineWidth); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/outdev/transparent.cxx b/vcl/source/outdev/transparent.cxx index 8c4051087c3e..2d8dd407fc0e 100644 --- a/vcl/source/outdev/transparent.cxx +++ b/vcl/source/outdev/transparent.cxx @@ -128,14 +128,13 @@ void OutputDevice::DrawTransparent( const basegfx::B2DHomMatrix aFullTransform(ImplGetDeviceTransformation() * rObjectTransform); // TODO: this must not drop transparency for mpAlphaVDev case, but instead use premultiplied // alpha... but that requires using premultiplied alpha also for already drawn data - const double fAdjustedTransparency = mpAlphaVDev ? 0 : fTransparency; if (IsFillColor()) { mpGraphics->DrawPolyPolygon( aFullTransform, aB2DPolyPolygon, - fAdjustedTransparency, + fTransparency, *this); } @@ -148,7 +147,7 @@ void OutputDevice::DrawTransparent( mpGraphics->DrawPolyLine( aFullTransform, rPolygon, - fAdjustedTransparency, + fTransparency, 0.0, // tdf#124848 hairline nullptr, // MM01 basegfx::B2DLineJoin::NONE, @@ -170,9 +169,6 @@ void OutputDevice::DrawTransparent( static_cast< sal_uInt16 >(fTransparency * 100.0))); } - if (mpAlphaVDev) - mpAlphaVDev->DrawTransparent(rObjectTransform, rB2DPolyPoly, fTransparency); - return; } @@ -273,13 +269,6 @@ bool OutputDevice::DrawTransparentNatively ( const tools::PolyPolygon& rPolyPoly void OutputDevice::EmulateDrawTransparent ( const tools::PolyPolygon& rPolyPoly, sal_uInt16 nTransparencePercent ) { - // #110958# Disable alpha VDev, we perform the necessary - VirtualDevice* pOldAlphaVDev = mpAlphaVDev; - - // operation explicitly further below. - if( mpAlphaVDev ) - mpAlphaVDev = nullptr; - GDIMetaFile* pOldMetaFile = mpMetaFile; mpMetaFile = nullptr; @@ -297,9 +286,7 @@ void OutputDevice::EmulateDrawTransparent ( const tools::PolyPolygon& rPolyPoly, // #i66849# Added fast path for exactly rectangular // polygons - // #i83087# Naturally, system alpha blending cannot - // work with separate alpha VDev - if( !mpAlphaVDev && aPolyPoly.IsRect() ) + if( aPolyPoly.IsRect() ) { // setup Graphics only here (other cases delegate // to basic OutDev methods) @@ -500,9 +487,6 @@ void OutputDevice::EmulateDrawTransparent ( const tools::PolyPolygon& rPolyPoly, } mpMetaFile = pOldMetaFile; - - // #110958# Restore disabled alpha VDev - mpAlphaVDev = pOldAlphaVDev; } void OutputDevice::DrawTransparent( const tools::PolyPolygon& rPolyPoly, @@ -539,18 +523,6 @@ void OutputDevice::DrawTransparent( const tools::PolyPolygon& rPolyPoly, if (!bDrawn) EmulateDrawTransparent( rPolyPoly, nTransparencePercent ); - - // #110958# Apply alpha value also to VDev alpha channel - if( mpAlphaVDev ) - { - const Color aFillCol( mpAlphaVDev->GetFillColor() ); - sal_uInt8 nAlpha = 255 - sal::static_int_cast(255*nTransparencePercent/100); - mpAlphaVDev->SetFillColor( Color(nAlpha, nAlpha, nAlpha) ); - - mpAlphaVDev->DrawTransparent( rPolyPoly, nTransparencePercent ); - - mpAlphaVDev->SetFillColor( aFillCol ); - } } void OutputDevice::DrawTransparent( const GDIMetaFile& rMtf, const Point& rPos, diff --git a/vcl/source/outdev/wallpaper.cxx b/vcl/source/outdev/wallpaper.cxx index b1eeb4dc2874..8d75d31ebecf 100644 --- a/vcl/source/outdev/wallpaper.cxx +++ b/vcl/source/outdev/wallpaper.cxx @@ -54,9 +54,6 @@ void OutputDevice::DrawWallpaper( const tools::Rectangle& rRect, rWallpaper ); } } - - if( mpAlphaVDev ) - mpAlphaVDev->DrawWallpaper( rRect, rWallpaper ); } void OutputDevice::DrawWallpaper( tools::Long nX, tools::Long nY, @@ -117,9 +114,6 @@ void OutputDevice::Erase() if ( eRasterOp != RasterOp::OverPaint ) SetRasterOp( eRasterOp ); } - // If we went into the "if ( mbBackground )" section, then we have already erased the mpAlphaDev. - else if( mpAlphaVDev ) - mpAlphaVDev->Erase(); } void OutputDevice::Erase(const tools::Rectangle& rRect) @@ -130,9 +124,6 @@ void OutputDevice::Erase(const tools::Rectangle& rRect) DrawWallpaper(rRect, GetBackground()); if ( eRasterOp != RasterOp::OverPaint ) SetRasterOp( eRasterOp ); - - if (mpAlphaVDev) - mpAlphaVDev->Erase(rRect); } void OutputDevice::DrawBitmapWallpaper( tools::Long nX, tools::Long nY, diff --git a/vcl/source/window/paint.cxx b/vcl/source/window/paint.cxx index 0770a2526190..a26713ee8330 100644 --- a/vcl/source/window/paint.cxx +++ b/vcl/source/window/paint.cxx @@ -1639,9 +1639,6 @@ void Window::Erase(vcl::RenderContext& rRenderContext) if (eRasterOp != RasterOp::OverPaint) rRenderContext.SetRasterOp(eRasterOp); } - - if (GetOutDev()->mpAlphaVDev) - GetOutDev()->mpAlphaVDev->Erase(); } void Window::ImplScroll( const tools::Rectangle& rRect, diff --git a/vcl/unx/generic/app/salinst.cxx b/vcl/unx/generic/app/salinst.cxx index 445dc8b89b59..ebb3c2d1f364 100644 --- a/vcl/unx/generic/app/salinst.cxx +++ b/vcl/unx/generic/app/salinst.cxx @@ -78,10 +78,6 @@ X11SalInstance::X11SalInstance(std::unique_ptr pMutex) m_bSupportsOpenGL = true; #if HAVE_FEATURE_SKIA X11SkiaSalGraphicsImpl::prepareSkia(); -#if SKIA_USE_BITMAP32 - if (SkiaHelper::isVCLSkiaEnabled()) - m_bSupportsBitmap32 = true; -#endif #endif } diff --git a/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx b/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx index 9e822047f14e..aea90a9b87f4 100644 --- a/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx +++ b/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx @@ -186,9 +186,10 @@ void X11CairoSalGraphicsImpl::drawMask(const SalTwoRect& rTR, const SalBitmap& r std::shared_ptr X11CairoSalGraphicsImpl::getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight) + tools::Long nHeight, + bool bWithoutAlpha) { - return mrCairoCommon.getBitmap(nX, nY, nWidth, nHeight); + return mrCairoCommon.getBitmap(nX, nY, nWidth, nHeight, bWithoutAlpha); } bool X11CairoSalGraphicsImpl::drawPolyLineBezier(sal_uInt32, const Point*, const PolyFlags*) diff --git a/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx b/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx index 3a8948eedafe..d53f7994056a 100644 --- a/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx +++ b/vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.hxx @@ -149,7 +149,7 @@ public: Color nMaskColor) override; std::shared_ptr getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth, - tools::Long nHeight) override; + tools::Long nHeight, bool bWithoutAlpha) override; bool drawPolyLineBezier(sal_uInt32 nPoints, const Point* pPtAry, const PolyFlags* pFlgAry) override; diff --git a/vcl/unx/generic/gdi/salvd.cxx b/vcl/unx/generic/gdi/salvd.cxx index 52b87875d2e6..3581a43a8ab8 100644 --- a/vcl/unx/generic/gdi/salvd.cxx +++ b/vcl/unx/generic/gdi/salvd.cxx @@ -36,8 +36,9 @@ std::unique_ptr X11SalInstance::CreateX11VirtualDevice(const SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, DeviceFormat eFormat, - std::unique_ptr pNewGraphics) + std::unique_ptr pNewGraphics, bool bAlphaMaskTransparent) { + assert(!bAlphaMaskTransparent && "TODO"); (void)bAlphaMaskTransparent; assert(pNewGraphics); #if HAVE_FEATURE_SKIA if (SkiaHelper::isVCLSkiaEnabled()) @@ -61,9 +62,9 @@ std::unique_ptr X11SalInstance::CreateX11VirtualDevice(const S } std::unique_ptr X11SalInstance::CreateVirtualDevice(SalGraphics& rGraphics, - tools::Long nDX, tools::Long nDY, DeviceFormat eFormat) + tools::Long nDX, tools::Long nDY, DeviceFormat eFormat, bool bAlphaMaskTransparent) { - return CreateX11VirtualDevice(rGraphics, nDX, nDY, eFormat, std::make_unique()); + return CreateX11VirtualDevice(rGraphics, nDX, nDY, eFormat, std::make_unique(), bAlphaMaskTransparent); } std::unique_ptr X11SalInstance::CreateVirtualDevice(SalGraphics& rGraphics, @@ -229,8 +230,9 @@ SalGraphics* X11SalVirtualDevice::AcquireGraphics() void X11SalVirtualDevice::ReleaseGraphics( SalGraphics* ) { bGraphics_ = false; } -bool X11SalVirtualDevice::SetSize( tools::Long nDX, tools::Long nDY ) +bool X11SalVirtualDevice::SetSize( tools::Long nDX, tools::Long nDY, bool bAlphaMaskTransparent ) { + assert(!bAlphaMaskTransparent && "TODO"); (void)bAlphaMaskTransparent; if( bExternPixmap_ ) return false; diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index 447b3e5fad6c..6a8914523854 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -370,14 +370,15 @@ void GtkYieldMutex::ThreadsLeave() std::unique_ptr GtkInstance::CreateVirtualDevice( SalGraphics &rG, tools::Long nDX, tools::Long nDY, - DeviceFormat /*eFormat*/ ) + DeviceFormat /*eFormat*/, + bool bAlphaMaskTransparent ) { EnsureInit(); SvpSalGraphics *pSvpSalGraphics = dynamic_cast(&rG); assert(pSvpSalGraphics); // tdf#127529 see SvpSalInstance::CreateVirtualDevice for the rare case of a non-null pPreExistingTarget std::unique_ptr xNew(new SvpSalVirtualDevice(pSvpSalGraphics->getSurface(), /*pPreExistingTarget*/nullptr)); - if (!xNew->SetSize(nDX, nDY)) + if (!xNew->SetSize(nDX, nDY, bAlphaMaskTransparent)) xNew.reset(); return xNew; } @@ -393,7 +394,7 @@ std::unique_ptr GtkInstance::CreateVirtualDevice( SalGraphics // tdf#127529 see SvpSalInstance::CreateVirtualDevice for the rare case of a non-null pPreExistingTarget cairo_surface_t* pPreExistingTarget = static_cast(rGd.pSurface); std::unique_ptr xNew(new SvpSalVirtualDevice(pSvpSalGraphics->getSurface(), pPreExistingTarget)); - if (!xNew->SetSize(nDX, nDY)) + if (!xNew->SetSize(nDX, nDY, /*bAlphaMaskTransparent*/false)) xNew.reset(); return xNew; } diff --git a/vcl/win/app/salinst.cxx b/vcl/win/app/salinst.cxx index 8f374dbe39d2..f0b7c0f510b6 100644 --- a/vcl/win/app/salinst.cxx +++ b/vcl/win/app/salinst.cxx @@ -406,10 +406,6 @@ WinSalInstance::WinSalInstance() pSVData->maAppData.mxToolkitName = OUString("win"); m_bSupportsOpenGL = true; WinSkiaSalGraphicsImpl::prepareSkia(); -#if SKIA_USE_BITMAP32 - if (SkiaHelper::isVCLSkiaEnabled()) - m_bSupportsBitmap32 = true; -#endif } WinSalInstance::~WinSalInstance() diff --git a/vcl/win/gdi/gdiimpl.cxx b/vcl/win/gdi/gdiimpl.cxx index eb4ab2c18972..afa19be6941a 100644 --- a/vcl/win/gdi/gdiimpl.cxx +++ b/vcl/win/gdi/gdiimpl.cxx @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,7 @@ #include #include #include +#include #include @@ -717,7 +719,7 @@ void WinSalGraphicsImpl::drawMask(const SalTwoRect& rPosAry, ImplDrawBitmap( hDC, aPosAry, rSalBitmap, false, 0x00B8074AUL );// raster operation PSDPxax } -std::shared_ptr WinSalGraphicsImpl::getBitmap( tools::Long nX, tools::Long nY, tools::Long nDX, tools::Long nDY ) +std::shared_ptr WinSalGraphicsImpl::getBitmap( tools::Long nX, tools::Long nY, tools::Long nDX, tools::Long nDY, bool bWithoutAlpha ) { SAL_WARN_IF( mrParent.isPrinter(), "vcl", "No ::GetBitmap() from printer possible!" ); @@ -727,12 +729,34 @@ std::shared_ptr WinSalGraphicsImpl::getBitmap( tools::Long nX, tools: nDY = std::abs( nDY ); HDC hDC = mrParent.getHDC(); - HBITMAP hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY ); - bool bRet; + HBITMAP hBmpBitmap; + if (bWithoutAlpha && GetBitCount() == 32) + { + BITMAPINFO aBitmapInfo; + aBitmapInfo.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); + aBitmapInfo.bmiHeader.biWidth = nDX; + aBitmapInfo.bmiHeader.biHeight = -nDY; // negative for top down + aBitmapInfo.bmiHeader.biPlanes = 1; + aBitmapInfo.bmiHeader.biBitCount = 24; + aBitmapInfo.bmiHeader.biCompression = BI_RGB; + aBitmapInfo.bmiHeader.biSizeImage = 0; + aBitmapInfo.bmiHeader.biXPelsPerMeter = 0; + aBitmapInfo.bmiHeader.biYPelsPerMeter = 0; + aBitmapInfo.bmiHeader.biClrUsed = 0; + aBitmapInfo.bmiHeader.biClrImportant = 0; + void* pData; + hBmpBitmap = CreateDIBSection( hDC, &aBitmapInfo, + DIB_RGB_COLORS, &pData, nullptr, + 0 ); + SAL_WARN_IF( !hBmpBitmap, "vcl", "CreateDIBSection failed: " << comphelper::WindowsErrorString( GetLastError() ) ); + } + else + hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY ); + + bool bRet; { ScopedCachedHDC hBmpDC(hBmpBitmap); - bRet = BitBlt(hBmpDC.get(), 0, 0, static_cast(nDX), static_cast(nDY), hDC, static_cast(nX), static_cast(nY), SRCCOPY) ? TRUE : FALSE; @@ -758,14 +782,38 @@ std::shared_ptr WinSalGraphicsImpl::getBitmap( tools::Long nX, tools: Color WinSalGraphicsImpl::getPixel( tools::Long nX, tools::Long nY ) { - COLORREF aWinCol = ::GetPixel( mrParent.getHDC(), static_cast(nX), static_cast(nY) ); + // The only way to read a pixel color with alpha is via GDI+ + // This is all hideously inefficient, but we only really use it for unit tests. + Gdiplus::Bitmap screenPixel(1, 1, PixelFormat32bppARGB); + Gdiplus::Graphics gdest(&screenPixel); + auto hDestDC = gdest.GetHDC(); + BOOL retval = BitBlt(hDestDC, 0, 0, 1, 1, + mrParent.getHDC(), static_cast(nX), static_cast(nY), + SRCCOPY); + gdest.ReleaseHDC(hDestDC); - if ( CLR_INVALID == aWinCol ) - return Color( 0, 0, 0 ); + if (!retval) + { + SAL_WARN("vcl", "GetPixel failed1"); + return Color(0, 0, 0); + } + Gdiplus::Color nGdiColor; + if (screenPixel.GetPixel(0, 0, &nGdiColor) != Gdiplus::Ok) + { + SAL_WARN("vcl", "GetPixel failed2"); + return Color(0, 0, 0); + } + // seems to be returning premultiplied color, despite the pixel format that I pass in the constructor + if (nGdiColor.GetAlpha() == 0) + return Color(ColorAlpha, nGdiColor.GetAlpha(), + nGdiColor.GetRed(), + nGdiColor.GetGreen(), + nGdiColor.GetBlue()); else - return Color( GetRValue( aWinCol ), - GetGValue( aWinCol ), - GetBValue( aWinCol ) ); + return Color(ColorAlpha, nGdiColor.GetAlpha(), + nGdiColor.GetRed() * 255 / nGdiColor.GetAlpha(), + nGdiColor.GetGreen() * 255 / nGdiColor.GetAlpha(), + nGdiColor.GetBlue() * 255 / nGdiColor.GetAlpha()); } namespace @@ -1379,11 +1427,42 @@ void WinSalGraphicsImpl::drawPixel( tools::Long nX, tools::Long nY ) void WinSalGraphicsImpl::drawPixel( tools::Long nX, tools::Long nY, Color nColor ) { - COLORREF nCol = RGB( nColor.GetRed(), + COLORREF nColorRef = RGB( nColor.GetRed(), nColor.GetGreen(), nColor.GetBlue() ); - DrawPixelImpl( nX, nY, nCol ); + if (nColor.GetAlpha() != 255) + { + const HDC hDC = mrParent.getHDC(); + + if (!mbXORMode) + { + // the only way to draw a pixel with alpha is via GDI+ + Gdiplus::Graphics g (hDC); + g.SetCompositingMode(Gdiplus::CompositingModeSourceCopy); + Gdiplus::SolidBrush brush(Gdiplus::Color(nColor.GetAlpha(), nColor.GetRed(), nColor.GetGreen(), nColor.GetBlue())); + g.FillRectangle(&brush, static_cast(nX), static_cast(nY), 1, 1); + } + else + { + assert(false && "I am not even sure what it would mean to use alpha in this mode"); + ScopedSelectedHBRUSH hBrush(hDC, CreateSolidBrush(nColorRef)); + PatBlt(hDC, static_cast(nX), static_cast(nY), int(1), int(1), PATINVERT); + } + } + else + { + const HDC hDC = mrParent.getHDC(); + + if (!mbXORMode) + { + SetPixel(hDC, static_cast(nX), static_cast(nY), nColorRef); + return; + } + + ScopedSelectedHBRUSH hBrush(hDC, CreateSolidBrush(nColorRef)); + PatBlt(hDC, static_cast(nX), static_cast(nY), int(1), int(1), PATINVERT); + } } void WinSalGraphicsImpl::drawLine( tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2 ) @@ -1403,8 +1482,24 @@ void WinSalGraphicsImpl::drawRect( tools::Long nX, tools::Long nY, tools::Long n { if ( !mrParent.isPrinter() ) { - PatBlt( mrParent.getHDC(), static_cast(nX), static_cast(nY), static_cast(nWidth), static_cast(nHeight), - mbXORMode ? PATINVERT : PATCOPY ); + if (maFillColor.GetAlpha() == 255) + { + PatBlt( mrParent.getHDC(), static_cast(nX), static_cast(nY), static_cast(nWidth), static_cast(nHeight), + mbXORMode ? PATINVERT : PATCOPY ); + } + else if (mbXORMode) + assert(false && "don't even know what this would mean"); + else + { + // the only way to draw with alpha is via GDI+ + Gdiplus::Graphics g(mrParent.getHDC()); + if (g.SetCompositingMode(Gdiplus::CompositingModeSourceCopy) != Gdiplus::Ok) + SAL_WARN("vcl", "SetCompositingMode failed"); + Gdiplus::SolidBrush brush( + Gdiplus::Color(maFillColor.GetAlpha(), maFillColor.GetRed(), + maFillColor.GetGreen(), maFillColor.GetBlue())); + g.FillRectangle(&brush, static_cast(nX), static_cast(nY), nWidth, nHeight); + } } else { @@ -1417,7 +1512,25 @@ void WinSalGraphicsImpl::drawRect( tools::Long nX, tools::Long nY, tools::Long n } } else - Rectangle( mrParent.getHDC(), static_cast(nX), static_cast(nY), static_cast(nX+nWidth), static_cast(nY+nHeight) ); + { + if (maFillColor.GetAlpha() == 255) + Rectangle(mrParent.getHDC(), static_cast(nX), static_cast(nY), + static_cast(nX + nWidth), static_cast(nY + nHeight)); + else if (mbXORMode) + assert(false && "don't even know what this would mean"); + else + { + // the only way to draw with alpha is via GDI+ + Gdiplus::Graphics g(mrParent.getHDC()); + if (g.SetCompositingMode(Gdiplus::CompositingModeSourceCopy) != Gdiplus::Ok) + SAL_WARN("vcl", "SetCompositingMode failed"); + Gdiplus::SolidBrush brush( + Gdiplus::Color(maFillColor.GetAlpha(), maFillColor.GetRed(), + maFillColor.GetGreen(), maFillColor.GetBlue())); + g.FillRectangle(&brush, static_cast(nX), static_cast(nY), nWidth, + nHeight); + } + } } void WinSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const Point* pPtAry ) @@ -2266,30 +2379,15 @@ static void paintToGdiPlus( const SalTwoRect& rTR, Gdiplus::Bitmap& rBitmap) { - // only parts of source are used - Gdiplus::PointF aDestPoints[3]; - Gdiplus::ImageAttributes aAttributes; - - // define target region as parallelogram - aDestPoints[0].X = Gdiplus::REAL(rTR.mnDestX); - aDestPoints[0].Y = Gdiplus::REAL(rTR.mnDestY); - aDestPoints[1].X = Gdiplus::REAL(rTR.mnDestX + rTR.mnDestWidth); - aDestPoints[1].Y = Gdiplus::REAL(rTR.mnDestY); - aDestPoints[2].X = Gdiplus::REAL(rTR.mnDestX); - aDestPoints[2].Y = Gdiplus::REAL(rTR.mnDestY + rTR.mnDestHeight); - - aAttributes.SetWrapMode(Gdiplus::WrapModeTileFlipXY); + Gdiplus::Rect aDestRect{ INT(rTR.mnDestX), INT(rTR.mnDestY), + INT(rTR.mnDestWidth), INT(rTR.mnDestHeight) }; rGraphics.DrawImage( &rBitmap, - aDestPoints, - 3, - Gdiplus::REAL(rTR.mnSrcX), - Gdiplus::REAL(rTR.mnSrcY), - Gdiplus::REAL(rTR.mnSrcWidth), - Gdiplus::REAL(rTR.mnSrcHeight), + aDestRect, + rTR.mnSrcX, rTR.mnSrcY, rTR.mnSrcWidth, rTR.mnSrcHeight, Gdiplus::UnitPixel, - &aAttributes); + nullptr); } static void setInterpolationMode( @@ -2374,6 +2472,10 @@ bool WinSalGraphicsImpl::drawAlphaBitmap( if(!rTR.mnSrcWidth || !rTR.mnSrcHeight || !rTR.mnDestWidth || !rTR.mnDestHeight) return false; + // neither GDI nor GDI+ can properly blend to a surface that has alpha + if (GetBitCount() == 32) + return false; + assert(dynamic_cast(&rSrcBitmap)); assert(dynamic_cast(&rAlphaBmp)); diff --git a/vcl/win/gdi/gdiimpl.hxx b/vcl/win/gdi/gdiimpl.hxx index da0aa7672b73..7959620d5243 100644 --- a/vcl/win/gdi/gdiimpl.hxx +++ b/vcl/win/gdi/gdiimpl.hxx @@ -170,7 +170,7 @@ public: const SalBitmap& rSalBitmap, Color nMaskColor ) override; - virtual std::shared_ptr getBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight ) override; + virtual std::shared_ptr getBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, bool bWithoutAlpha ) override; virtual Color getPixel( tools::Long nX, tools::Long nY ) override; diff --git a/vcl/win/gdi/salbmp.cxx b/vcl/win/gdi/salbmp.cxx index f65cd869e277..dd3fb6119377 100644 --- a/vcl/win/gdi/salbmp.cxx +++ b/vcl/win/gdi/salbmp.cxx @@ -748,7 +748,7 @@ BitmapBuffer* WinSalBitmap::AcquireBuffer( BitmapAccessMode /*nMode*/ ) pBuffer->meFormat = pBIH->biBitCount == 8 ? ScanlineFormat::N8BitPal : pBIH->biBitCount == 24 ? ScanlineFormat::N24BitTcBgr : - pBIH->biBitCount == 32 ? ScanlineFormat::N32BitTcBgrx : + pBIH->biBitCount == 32 ? ScanlineFormat::N32BitTcBgra : ScanlineFormat::NONE; assert (pBuffer->meFormat != ScanlineFormat::NONE); diff --git a/vcl/win/gdi/salgdi2.cxx b/vcl/win/gdi/salgdi2.cxx index 4dca93550041..2d1cfb2c89b5 100644 --- a/vcl/win/gdi/salgdi2.cxx +++ b/vcl/win/gdi/salgdi2.cxx @@ -212,9 +212,9 @@ void WinSalGraphics::drawMask( const SalTwoRect& rPosAry, mpImpl->drawMask( rPosAry, rSSalBitmap, nMaskColor ); } -std::shared_ptr WinSalGraphics::getBitmap( tools::Long nX, tools::Long nY, tools::Long nDX, tools::Long nDY ) +std::shared_ptr WinSalGraphics::getBitmap( tools::Long nX, tools::Long nY, tools::Long nDX, tools::Long nDY, bool bWithoutAlpha ) { - return mpImpl->getBitmap( nX, nY, nDX, nDY ); + return mpImpl->getBitmap( nX, nY, nDX, nDY, bWithoutAlpha ); } Color WinSalGraphics::getPixel( tools::Long nX, tools::Long nY ) diff --git a/vcl/win/gdi/salvd.cxx b/vcl/win/gdi/salvd.cxx index 22dca8b03337..547cae8976f7 100644 --- a/vcl/win/gdi/salvd.cxx +++ b/vcl/win/gdi/salvd.cxx @@ -31,12 +31,13 @@ #include #include -HBITMAP WinSalVirtualDevice::ImplCreateVirDevBitmap(HDC hDC, tools::Long nDX, tools::Long nDY, sal_uInt16 nBitCount, void **ppData) +HBITMAP WinSalVirtualDevice::ImplCreateVirDevBitmap(HDC hDC, tools::Long nDX, tools::Long nDY, sal_uInt16 nBitCount, void **ppData, bool bAlphaMaskTransparent) { HBITMAP hBitmap; if ( nBitCount == 1 ) { + assert(!bAlphaMaskTransparent && "does not make sense here"); hBitmap = CreateBitmap( static_cast(nDX), static_cast(nDY), 1, 1, nullptr ); SAL_WARN_IF( !hBitmap, "vcl", "CreateBitmap failed: " << comphelper::WindowsErrorString( GetLastError() ) ); ppData = nullptr; @@ -52,7 +53,7 @@ HBITMAP WinSalVirtualDevice::ImplCreateVirDevBitmap(HDC hDC, tools::Long nDX, to BITMAPINFO aBitmapInfo; aBitmapInfo.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); aBitmapInfo.bmiHeader.biWidth = nDX; - aBitmapInfo.bmiHeader.biHeight = nDY; + aBitmapInfo.bmiHeader.biHeight = -nDY; // negative for top-down bitmap aBitmapInfo.bmiHeader.biPlanes = 1; aBitmapInfo.bmiHeader.biBitCount = nBitCount; aBitmapInfo.bmiHeader.biCompression = BI_RGB; @@ -62,10 +63,23 @@ HBITMAP WinSalVirtualDevice::ImplCreateVirDevBitmap(HDC hDC, tools::Long nDX, to aBitmapInfo.bmiHeader.biClrUsed = 0; aBitmapInfo.bmiHeader.biClrImportant = 0; + void* pData = nullptr; hBitmap = CreateDIBSection( hDC, &aBitmapInfo, - DIB_RGB_COLORS, ppData, nullptr, + DIB_RGB_COLORS, &pData, nullptr, 0 ); SAL_WARN_IF( !hBitmap, "vcl", "CreateDIBSection failed: " << comphelper::WindowsErrorString( GetLastError() ) ); + + if (hBitmap) + { + if (bAlphaMaskTransparent) + { + assert(nBitCount == 32); + memset(pData, nDX * nDY * 4, 0); + } + + if (ppData) + *ppData = pData; + } } return hBitmap; @@ -73,7 +87,8 @@ HBITMAP WinSalVirtualDevice::ImplCreateVirDevBitmap(HDC hDC, tools::Long nDX, to std::unique_ptr WinSalInstance::CreateVirtualDevice( SalGraphics& rSGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat /*eFormat*/ ) + DeviceFormat eFormat, + bool bAlphaMaskTransparent ) { WinSalGraphics& rGraphics = static_cast(rSGraphics); @@ -83,13 +98,14 @@ std::unique_ptr WinSalInstance::CreateVirtualDevice( SalGraphi if (!hDC) return nullptr; - const sal_uInt16 nBitCount = 0; + const sal_uInt16 nBitCount = eFormat == DeviceFormat::WITHOUT_ALPHA ? 0 : 32; // #124826# continue even if hBmp could not be created // if we would return a failure in this case, the process // would terminate which is not required HBITMAP hBmp = WinSalVirtualDevice::ImplCreateVirDevBitmap(rGraphics.getHDC(), nDX, nDY, nBitCount, - &o3tl::temporary(nullptr)); + &o3tl::temporary(nullptr), + bAlphaMaskTransparent); auto pVDev = std::make_unique(hDC, hBmp, nBitCount, /*bForeignDC*/false, nDX, nDY, rGraphics.isScreen()); @@ -195,13 +211,13 @@ void WinSalVirtualDevice::ReleaseGraphics( SalGraphics* ) mbGraphicsAcquired = false; } -bool WinSalVirtualDevice::SetSize( tools::Long nDX, tools::Long nDY ) +bool WinSalVirtualDevice::SetSize( tools::Long nDX, tools::Long nDY, bool bAlphaMaskTransparent ) { if( mbForeignDC || !mhBmp ) return true; // ??? HBITMAP hNewBmp = ImplCreateVirDevBitmap(getHDC(), nDX, nDY, mnBitCount, - &o3tl::temporary(nullptr)); + &o3tl::temporary(nullptr), bAlphaMaskTransparent); if (!hNewBmp) { mnWidth = 0;