summaryrefslogtreecommitdiff
path: root/vcl/source
diff options
context:
space:
mode:
authorXisco Fauli <xiscofauli@libreoffice.org>2024-04-05 10:08:36 +0200
committerXisco Fauli <xiscofauli@libreoffice.org>2024-04-16 09:36:37 +0200
commitcb4698626f17e005c820a7138c63a03c21120ecd (patch)
treead153f60368e60065226d8d72b8d17aeb7e95772 /vcl/source
parentded4d570fde21e55091c9c8c364114e67aa0cdcf (diff)
tdf#48062: Add support for arithmetic in feComposite
Took https://github.com/w3c/csswg-drafts/issues/3831 as a reference Change-Id: I42039c481ec114c3faeae51526a5f29b86960146 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165828 Tested-by: Jenkins Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Diffstat (limited to 'vcl/source')
-rw-r--r--vcl/source/bitmap/BitmapArithmeticBlendFilter.cxx105
1 files changed, 105 insertions, 0 deletions
diff --git a/vcl/source/bitmap/BitmapArithmeticBlendFilter.cxx b/vcl/source/bitmap/BitmapArithmeticBlendFilter.cxx
new file mode 100644
index 000000000000..da52a436b6f6
--- /dev/null
+++ b/vcl/source/bitmap/BitmapArithmeticBlendFilter.cxx
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <comphelper/diagnose_ex.hxx>
+#include <vcl/BitmapArithmeticBlendFilter.hxx>
+#include <vcl/BitmapWriteAccess.hxx>
+#include <vcl/BitmapTools.hxx>
+
+BitmapArithmeticBlendFilter::BitmapArithmeticBlendFilter(BitmapEx const& rBitmapEx,
+ BitmapEx const& rBitmapEx2)
+ : maBitmapEx(rBitmapEx)
+ , maBitmapEx2(rBitmapEx2)
+{
+}
+
+BitmapArithmeticBlendFilter::~BitmapArithmeticBlendFilter() {}
+
+static sal_uInt8 lcl_calculate(sal_uInt8 aColor, sal_uInt8 aColor2, double aK1, double aK2,
+ double aK3, double aK4)
+{
+ const double i1 = aColor / 255.0;
+ const double i2 = aColor2 / 255.0;
+ const double result = aK1 * i1 * i2 + aK2 * i1 + aK3 * i2 + aK4;
+
+ return std::clamp(result, 0.0, 1.0) * 255.0;
+}
+
+static BitmapColor premultiply(const BitmapColor c)
+{
+ return BitmapColor(ColorAlpha, vcl::bitmap::premultiply(c.GetRed(), c.GetAlpha()),
+ vcl::bitmap::premultiply(c.GetGreen(), c.GetAlpha()),
+ vcl::bitmap::premultiply(c.GetBlue(), c.GetAlpha()), c.GetAlpha());
+}
+
+static BitmapColor unpremultiply(const BitmapColor c)
+{
+ return BitmapColor(ColorAlpha, vcl::bitmap::unpremultiply(c.GetRed(), c.GetAlpha()),
+ vcl::bitmap::unpremultiply(c.GetGreen(), c.GetAlpha()),
+ vcl::bitmap::unpremultiply(c.GetBlue(), c.GetAlpha()), c.GetAlpha());
+}
+
+BitmapEx BitmapArithmeticBlendFilter::execute(double aK1, double aK2, double aK3, double aK4)
+{
+ if (maBitmapEx.IsEmpty() || maBitmapEx2.IsEmpty())
+ return BitmapEx();
+
+ Size aSize = maBitmapEx.GetBitmap().GetSizePixel();
+ Size aSize2 = maBitmapEx2.GetBitmap().GetSizePixel();
+ sal_Int32 nHeight = std::min(aSize.getHeight(), aSize2.getHeight());
+ sal_Int32 nWidth = std::min(aSize.getWidth(), aSize2.getWidth());
+
+ BitmapScopedReadAccess pReadAccess(maBitmapEx.GetBitmap());
+ Bitmap aDstBitmap(Size(nWidth, nHeight), maBitmapEx.GetBitmap().getPixelFormat(),
+ &pReadAccess->GetPalette());
+ Bitmap aDstAlpha(AlphaMask(Size(nWidth, nHeight)).GetBitmap());
+
+ {
+ // just to be on the safe side: let the
+ // ScopedAccessors get destructed before
+ // copy-constructing the resulting bitmap. This will
+ // rule out the possibility that cached accessor data
+ // is not yet written back.
+
+ BitmapScopedWriteAccess pWriteAccess(aDstBitmap);
+ BitmapScopedWriteAccess pAlphaWriteAccess(aDstAlpha);
+
+ if (pWriteAccess.get() != nullptr && pAlphaWriteAccess.get() != nullptr)
+ {
+ for (tools::Long y(0); y < nHeight; ++y)
+ {
+ Scanline pScanline = pWriteAccess->GetScanline(y);
+ Scanline pScanAlpha = pAlphaWriteAccess->GetScanline(y);
+ for (tools::Long x(0); x < nWidth; ++x)
+ {
+ BitmapColor i1 = premultiply(maBitmapEx.GetPixelColor(x, y));
+ BitmapColor i2 = premultiply(maBitmapEx2.GetPixelColor(x, y));
+ sal_uInt8 r(lcl_calculate(i1.GetRed(), i2.GetRed(), aK1, aK2, aK3, aK4));
+ sal_uInt8 g(lcl_calculate(i1.GetGreen(), i2.GetGreen(), aK1, aK2, aK3, aK4));
+ sal_uInt8 b(lcl_calculate(i1.GetBlue(), i2.GetBlue(), aK1, aK2, aK3, aK4));
+ sal_uInt8 a(lcl_calculate(i1.GetAlpha(), i2.GetAlpha(), aK1, aK2, aK3, aK4));
+
+ pWriteAccess->SetPixelOnData(
+ pScanline, x, unpremultiply(BitmapColor(ColorAlpha, r, g, b, a)));
+ pAlphaWriteAccess->SetPixelOnData(pScanAlpha, x, BitmapColor(a));
+ }
+ }
+ }
+ else
+ {
+ // TODO(E2): Error handling!
+ ENSURE_OR_THROW(false, "BitmapScreenBlendFilter: could not access bitmap");
+ }
+ }
+
+ return BitmapEx(aDstBitmap, AlphaMask(aDstAlpha));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */