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 vcl/qa/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 | 77 ----- 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 vcl/unx/generic/gdi/X11CairoSalGraphicsImpl.cxx | 5 vcl/unx/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 | 174 +++++++++-- 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, 637 insertions(+), 1278 deletions(-)
New commits: commit 088a7c7c451321a800ca8d3523a18b6bb93239b7 Author: Noel Grandin <noelgran...@gmail.com> AuthorDate: Tue Sep 24 16:18:11 2024 +0200 Commit: Noel Grandin <noelgran...@gmail.com> CommitDate: Mon Jul 21 10:49:25 2025 +0200 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 <noel.gran...@collabora.co.uk> 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<sal_uInt8, nCanvasWidth * nCanvasHeight * 4> 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 <vcl/BitmapColor.hxx> #include <vcl/BitmapAccessMode.hxx> -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<Bitmap, AlphaMask> 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<VirtualDevice> 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<unsigned char> aPixmap(nCanvasSize * nCanvasSize * 4, 0); ScopedVclPtrInstance<VirtualDevice> 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<Color> 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<Color>& 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<SalBitmap> 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<SvpSalBitmap> pBitmap = std::make_shared<SvpSalBitmap>(); 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<BitmapBuffer> 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<BitmapBuffer> 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<BitmapBuffer> 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<SalBitmap> 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<BitmapBuffer> 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<BitmapBuffer> 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<BitmapBuffer>& 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<SalVirtualDevice> SvpSalInstance::CreateVirtualDevice(SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat /*eFormat*/) + DeviceFormat /*eFormat*/, + bool bAlphaMaskTransparent) { SvpSalGraphics *pSvpSalGraphics = dynamic_cast<SvpSalGraphics*>(&rGraphics); assert(pSvpSalGraphics); std::unique_ptr<SalVirtualDevice> 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<SalVirtualDevice> SvpSalInstance::CreateVirtualDevice(SalGraphic cairo_surface_t* pPreExistingTarget = nullptr; #endif std::unique_ptr<SalVirtualDevice> 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<SalBitmap> 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<SalBitmap> 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<SalVirtualDevice> 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<SalVirtualDevice> CreateVirtualDevice( SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat ) override; + DeviceFormat eFormat, + bool bAlphaMaskTransparent = false ) override; virtual std::unique_ptr<SalVirtualDevice> 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<SalBitmap> 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<SalVirtualDevice> CreateVirtualDevice(SalGraphics& rGraphics, - tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat) override; + virtual std::unique_ptr<SalVirtualDevice> + CreateVirtualDevice(SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, + DeviceFormat eFormat, bool bAlphaMaskTransparent = false) override; virtual std::unique_ptr<SalVirtualDevice> 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<SalBitmap> 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<SalBitmap> 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<SalBitmap> getBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight ) = 0; + virtual std::shared_ptr<SalBitmap> 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<SalBitmap> getBitmap(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight) override + std::shared_ptr<SalBitmap> 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<SalBitmap> getBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight ) = 0; + virtual std::shared_ptr<SalBitmap> 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<css::datatransfer::clipboard::XClipboard> m_clipboard; protected: - bool m_bSupportsBitmap32 = false; bool m_bSupportsOpenGL = false; public: SalInstance(std::unique_ptr<comphelper::SolarMutex> 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<SalVirtualDevice> 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<SalBitmap> 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<SkImage>& image); + SkiaSalBitmap(const sk_sp<SkImage>& 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<SalVirtualDevice> CreateVirtualDevice( SalGraphics&, tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat ) override; + DeviceFormat eFormat, + bool bAlphaMaskTransparent = false ) override; virtual std::unique_ptr<SalVirtualDevice> 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<SalVirtualDevice> CreateX11VirtualDevice(const SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat, std::unique_ptr<X11SalGraphics> pNewGraphics); + DeviceFormat eFormat, std::unique_ptr<X11SalGraphics> pNewGraphics, + bool bAlphaMaskTransparent); static std::unique_ptr<SalVirtualDevice> CreateX11VirtualDevice(const SalGraphics& rGraphics, tools::Long &nDX, tools::Long &nDY, DeviceFormat eFormat, const SystemGraphicsData& rData, std::unique_ptr<X11SalGraphics> pNewGraphics); virtual std::unique_ptr<SalVirtualDevice> CreateVirtualDevice( SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat ) override; + DeviceFormat eFormat, + bool bAlphaMaskTransparent = false ) override; virtual std::unique_ptr<SalVirtualDevice> 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<SalBitmap> getBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight ) override; + virtual std::shared_ptr<SalBitmap> 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<SalVirtualDevice> CreateVirtualDevice( SalGraphics& rGraphics, tools::Long nDX, tools::Long nDY, - DeviceFormat eFormat ) override; + DeviceFormat eFormat, + bool bAlphaMaskTransparent = false ) override; virtual std::unique_ptr<SalVirtualDevice> 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<css::rendering::XCanvas> 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<SalBitmap> 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<SalBitmap> 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<QtBitmap>(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<SalVirtualDevice> 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<SalVirtualDevice> QtInstance::CreateVirtualDevice(SalGraphics& r // tdf#127529 see SvpSalInstance::CreateVirtualDevice for the rare case of a non-null pPreExistingTarget std::unique_ptr<SalVirtualDevice> pVD( new QtSvpVirtualDevice(pSvpSalGraphics->getSurface(), /*pPreExistingTarget*/ nullptr)); - pVD->SetSize(nDX, nDY); + pVD->SetSize(nDX, nDY, bAlphaMaskTransparent); return pVD; } else { std::unique_ptr<SalVirtualDevice> 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<cairo_surface_t*>(rGd.pSurface); std::unique_ptr<SalVirtualDevice> pVD( new QtSvpVirtualDevice(pSvpSalGraphics->getSurface(), pPreExistingTarget)); - pVD->SetSize(nDX, nDY); + pVD->SetSize(nDX, nDY, /*bAlphaMaskTransparent*/ false); return pVD; } else { std::unique_ptr<SalVirtualDevice> 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<SalBitmap> 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<SalVirtualDevice> 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<SalVirtualDevice> pNew(new AquaSalVirtualDevice( nullptr, nDX, nDY, eFormat )); + std::unique_ptr<SalVirtualDevice> pNew(new AquaSalVirtualDevice( nullptr, nDX, nDY, eFormat, bAlphaMaskTransparent )); pNew->SetSize( nDX, nDY ); return pNew; #else return std::unique_ptr<SalVirtualDevice>(new AquaSalVirtualDevice( static_cast< AquaSalGraphics* >(&rGraphics), - nDX, nDY, eFormat )); + nDX, nDY, eFormat, bAlphaMaskTransparent )); #endif } @@ -69,7 +70,7 @@ std::unique_ptr<SalVirtualDevice> 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<SalBitmap> 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<SalBitmap> SkiaSalGraphicsImpl::getBitmap(tools::Long nX, tools: // in blendAlphaBitmap(), where we could simply use the proper rect of the image. sk_sp<SkImage> image = makeCheckedImageSnapshot( mSurface, scaleRect(SkIRect::MakeXYWH(nX, nY, nWidth, nHeight), mScaling)); - std::shared_ptr<SkiaSalBitmap> bitmap = std::make_shared<SkiaSalBitmap>(image); + std::shared_ptr<SkiaSalBitmap> bitmap = std::make_shared<SkiaSalBitmap>(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<SkImage>& image) +SkiaSalBitmap::SkiaSalBitmap(const sk_sp<SkImage>& 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<Bitmap, AlphaMask> 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, AlphaMask> 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<bool>(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<png_byte> 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); - 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); + 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); - 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<std::vector<png_byte>> 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<png_byte> 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<std::vector<png_byte>> 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)); - } -e ... etc. - the rest is truncated