drawinglayer/source/processor2d/SDPRProcessor2dTools.cxx    |   30 -
 drawinglayer/source/processor2d/cairopixelprocessor2d.cxx   |   80 +---
 drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx     |    6 
 include/basegfx/utils/systemdependentdata.hxx               |    1 
 include/drawinglayer/primitive2d/fillgraphicprimitive2d.hxx |   10 
 include/drawinglayer/processor2d/SDPRProcessor2dTools.hxx   |    5 
 include/drawinglayer/processor2d/cairopixelprocessor2d.hxx  |    3 
 include/vcl/bitmap.hxx                                      |    9 
 vcl/source/bitmap/bitmap.cxx                                |  204 ++++++++++++
 9 files changed, 271 insertions(+), 77 deletions(-)

New commits:
commit bacd1b5dc4d3d81c87803048892aa1d9c1ff0d9f
Author:     Noel Grandin <[email protected]>
AuthorDate: Thu Aug 7 12:30:54 2025 +0200
Commit:     Noel Grandin <[email protected]>
CommitDate: Thu Aug 7 22:04:36 2025 +0200

    BitmapEx->Bitmap in FillGraphicPrimitive2D
    
    now that Bitmap supports transparency
    
    Change-Id: I9762dadae840e8eaec37526f82068183474c7962
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189069
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <[email protected]>

diff --git a/drawinglayer/source/processor2d/SDPRProcessor2dTools.cxx 
b/drawinglayer/source/processor2d/SDPRProcessor2dTools.cxx
index 4116c09d6b85..12917206fa55 100644
--- a/drawinglayer/source/processor2d/SDPRProcessor2dTools.cxx
+++ b/drawinglayer/source/processor2d/SDPRProcessor2dTools.cxx
@@ -34,14 +34,14 @@ namespace drawinglayer::processor2d
 {
 void setOffsetXYCreatedBitmap(
     drawinglayer::primitive2d::FillGraphicPrimitive2D& rFillGraphicPrimitive2D,
-    const BitmapEx& rBitmap)
+    const Bitmap& rBitmap)
 {
     rFillGraphicPrimitive2D.impSetOffsetXYCreatedBitmap(rBitmap);
 }
 
 void takeCareOfOffsetXY(
     const drawinglayer::primitive2d::FillGraphicPrimitive2D& 
rFillGraphicPrimitive2D,
-    BitmapEx& rTarget, basegfx::B2DRange& rFillUnitRange)
+    Bitmap& rTarget, basegfx::B2DRange& rFillUnitRange)
 {
     const attribute::FillGraphicAttribute& rFillGraphicAttribute(
         rFillGraphicPrimitive2D.getFillGraphic());
@@ -54,20 +54,20 @@ void takeCareOfOffsetXY(
     {
         if (rFillGraphicPrimitive2D.getOffsetXYCreatedBitmap().IsEmpty())
         {
-            const Size& rSize(rTarget.GetSizePixel());
-            const tools::Long w(rSize.Width());
+            const Size aSize(rTarget.GetSizePixel());
+            const tools::Long w(aSize.Width());
             const tools::Long a(
                 basegfx::fround<tools::Long>(w * (1.0 - 
rFillGraphicAttribute.getOffsetX())));
 
             if (0 != a && w != a)
             {
-                const tools::Long h(rSize.Height());
+                const tools::Long h(aSize.Height());
                 const tools::Long b(w - a);
-                BitmapEx aTarget(Size(w, h * 2), rTarget.getPixelFormat());
+                Bitmap aTarget(Size(w, h * 2), rTarget.getPixelFormat());
 
                 aTarget.SetPrefSize(
                     Size(rTarget.GetPrefSize().Width(), 
rTarget.GetPrefSize().Height() * 2));
-                const tools::Rectangle aSrcDst(Point(), rSize);
+                const tools::Rectangle aSrcDst(Point(), aSize);
                 aTarget.CopyPixel(aSrcDst, // Dst
                                   aSrcDst, // Src
                                   rTarget);
@@ -98,20 +98,20 @@ void takeCareOfOffsetXY(
     {
         if (rFillGraphicPrimitive2D.getOffsetXYCreatedBitmap().IsEmpty())
         {
-            const Size& rSize(rTarget.GetSizePixel());
-            const tools::Long h(rSize.Height());
+            const Size aSize(rTarget.GetSizePixel());
+            const tools::Long h(aSize.Height());
             const tools::Long a(
                 basegfx::fround<tools::Long>(h * (1.0 - 
rFillGraphicAttribute.getOffsetY())));
 
             if (0 != a && h != a)
             {
-                const tools::Long w(rSize.Width());
+                const tools::Long w(aSize.Width());
                 const tools::Long b(h - a);
-                BitmapEx aTarget(Size(w * 2, h), rTarget.getPixelFormat());
+                Bitmap aTarget(Size(w * 2, h), rTarget.getPixelFormat());
 
                 aTarget.SetPrefSize(
                     Size(rTarget.GetPrefSize().Width() * 2, 
rTarget.GetPrefSize().Height()));
-                const tools::Rectangle aSrcDst(Point(), rSize);
+                const tools::Rectangle aSrcDst(Point(), aSize);
                 aTarget.CopyPixel(aSrcDst, // Dst
                                   aSrcDst, // Src
                                   rTarget);
@@ -142,7 +142,7 @@ void takeCareOfOffsetXY(
 
 bool prepareBitmapForDirectRender(
     const drawinglayer::primitive2d::FillGraphicPrimitive2D& 
rFillGraphicPrimitive2D,
-    const drawinglayer::geometry::ViewInformation2D& rViewInformation2D, 
BitmapEx& rTarget,
+    const drawinglayer::geometry::ViewInformation2D& rViewInformation2D, 
Bitmap& rTarget,
     basegfx::B2DRange& rFillUnitRange, double fBigDiscreteArea)
 {
     const attribute::FillGraphicAttribute& rFillGraphicAttribute(
@@ -203,7 +203,7 @@ bool prepareBitmapForDirectRender(
     {
         // bitmap graphic, always handle locally, so get bitmap data 
independent
         // if it'sie or it's discrete display size
-        rTarget = rGraphic.GetBitmapEx();
+        rTarget = Bitmap(rGraphic.GetBitmapEx());
     }
     else
     {
@@ -243,7 +243,7 @@ bool prepareBitmapForDirectRender(
             // at BitmapEx is possible, just get the default fallback Bitmap 
from the
             // vector data to continue. Trust the existing converters for now 
to
             // do something with good quality.
-            rTarget = rGraphic.GetBitmapEx();
+            rTarget = Bitmap(rGraphic.GetBitmapEx());
         }
     }
 
diff --git a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx 
b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
index b3bbdd36536e..0eda4ca44e52 100644
--- a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
@@ -426,11 +426,9 @@ class CairoSurfaceHelper
     mutable std::unordered_map<sal_uInt64, cairo_surface_t*> maDownscaled;
 
     // create 32bit RGBA data for given BitmapEx
-    void createRGBA(const BitmapEx& rBitmapEx)
+    void createRGBA(const Bitmap& rBitmap)
     {
-        Bitmap aSrcAlpha(rBitmapEx.GetAlphaMask().GetBitmap());
-        BitmapScopedReadAccess pReadAccess(rBitmapEx.GetBitmap());
-        BitmapScopedReadAccess pAlphaReadAccess(aSrcAlpha);
+        BitmapScopedReadAccess pReadAccess(rBitmap);
         const tools::Long nHeight(pReadAccess->Height());
         const tools::Long nWidth(pReadAccess->Width());
         mpCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 
nWidth, nHeight);
@@ -450,8 +448,7 @@ class CairoSurfaceHelper
             for (tools::Long x(0); x < nWidth; ++x)
             {
                 const BitmapColor aColor(pReadAccess->GetColor(y, x));
-                const BitmapColor aAlpha(pAlphaReadAccess->GetColor(y, x));
-                const sal_uInt16 nAlpha(aAlpha.GetRed());
+                const sal_uInt16 nAlpha(aColor.GetAlpha());
 
                 pPixelData[SVP_CAIRO_RED] = 
vcl::bitmap::premultiply(aColor.GetRed(), nAlpha);
                 pPixelData[SVP_CAIRO_GREEN] = 
vcl::bitmap::premultiply(aColor.GetGreen(), nAlpha);
@@ -465,9 +462,9 @@ class CairoSurfaceHelper
     }
 
     // create 32bit RGB data for given BitmapEx
-    void createRGB(const BitmapEx& rBitmapEx)
+    void createRGB(const Bitmap& rBitmap)
     {
-        BitmapScopedReadAccess pReadAccess(rBitmapEx.GetBitmap());
+        BitmapScopedReadAccess pReadAccess(rBitmap);
         const tools::Long nHeight(pReadAccess->Height());
         const tools::Long nWidth(pReadAccess->Width());
         mpCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 
nWidth, nHeight);
@@ -502,9 +499,9 @@ class CairoSurfaceHelper
 // #define TEST_RGB16
 #ifdef TEST_RGB16
     // experimental: create 16bit RGB data for given BitmapEx
-    void createRGB16(const BitmapEx& rBitmapEx)
+    void createRGB16(const BitmapEx& rBitmap)
     {
-        BitmapScopedReadAccess pReadAccess(rBitmapEx.GetBitmap());
+        BitmapScopedReadAccess pReadAccess(rBitmap);
         const tools::Long nHeight(pReadAccess->Height());
         const tools::Long nWidth(pReadAccess->Width());
         mpCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB16_565, 
nWidth, nHeight);
@@ -542,17 +539,17 @@ class CairoSurfaceHelper
 #endif
 
 public:
-    CairoSurfaceHelper(const BitmapEx& rBitmapEx)
+    CairoSurfaceHelper(const Bitmap& rBitmap)
         : mpCairoSurface(nullptr)
         , maDownscaled()
     {
-        if (rBitmapEx.IsAlpha())
-            createRGBA(rBitmapEx);
+        if (rBitmap.HasAlpha())
+            createRGBA(rBitmap);
         else
 #ifdef TEST_RGB16
-            createRGB16(rBitmapEx);
+            createRGB16(rBitmap);
 #else
-            createRGB(rBitmapEx);
+            createRGB(rBitmap);
 #endif
     }
 
@@ -665,19 +662,12 @@ class SystemDependentData_CairoSurface : public 
basegfx::SystemDependentData
     // the CairoSurface holder
     std::shared_ptr<CairoSurfaceHelper> mpCairoSurfaceHelper;
 
-    // need to remember alpha source for combined BitmapEx to detect/
-    // react on that changing
-    std::shared_ptr<SalBitmap> maAssociatedAlpha;
-
 public:
-    SystemDependentData_CairoSurface(const BitmapEx& rBitmapEx)
+    SystemDependentData_CairoSurface(const Bitmap& rBitmap)
         : 
basegfx::SystemDependentData(Application::GetSystemDependentDataManager(),
                                        basegfx::SDD_Type::SDDType_CairoSurface)
-        , mpCairoSurfaceHelper(std::make_shared<CairoSurfaceHelper>(rBitmapEx))
-        , maAssociatedAlpha()
+        , mpCairoSurfaceHelper(std::make_shared<CairoSurfaceHelper>(rBitmap))
     {
-        if (rBitmapEx.IsAlpha())
-            maAssociatedAlpha = 
rBitmapEx.GetAlphaMask().GetBitmap().ImplGetSalBitmap();
     }
 
     // read access
@@ -685,7 +675,6 @@ public:
     {
         return mpCairoSurfaceHelper;
     }
-    const std::shared_ptr<SalBitmap>& getAssociatedAlpha() const { return 
maAssociatedAlpha; }
 
     virtual sal_Int64 estimateUsageInBytes() const override;
 };
@@ -714,10 +703,9 @@ sal_Int64 
SystemDependentData_CairoSurface::estimateUsageInBytes() const
     return nRetval;
 }
 
-std::shared_ptr<CairoSurfaceHelper> getOrCreateCairoSurfaceHelper(const 
BitmapEx& rBitmapEx)
+std::shared_ptr<CairoSurfaceHelper> getOrCreateCairoSurfaceHelper(const 
Bitmap& rBitmap)
 {
-    const basegfx::SystemDependentDataHolder* pHolder(
-        rBitmapEx.GetBitmap().accessSystemDependentDataHolder());
+    const basegfx::SystemDependentDataHolder* 
pHolder(rBitmap.accessSystemDependentDataHolder());
     std::shared_ptr<SystemDependentData_CairoSurface> 
pSystemDependentData_CairoSurface;
 
     if (nullptr != pHolder)
@@ -726,22 +714,13 @@ std::shared_ptr<CairoSurfaceHelper> 
getOrCreateCairoSurfaceHelper(const BitmapEx
         pSystemDependentData_CairoSurface
             = std::static_pointer_cast<SystemDependentData_CairoSurface>(
                 
pHolder->getSystemDependentData(basegfx::SDD_Type::SDDType_CairoSurface));
-
-        // check data validity for associated Alpha
-        if (pSystemDependentData_CairoSurface && rBitmapEx.IsAlpha()
-            && pSystemDependentData_CairoSurface->getAssociatedAlpha()
-                   != rBitmapEx.GetAlphaMask().GetBitmap().ImplGetSalBitmap())
-        {
-            // AssociatedAlpha did change, data invalid
-            pSystemDependentData_CairoSurface.reset();
-        }
     }
 
     if (!pSystemDependentData_CairoSurface)
     {
         // create new SystemDependentData_CairoSurface
         pSystemDependentData_CairoSurface
-            = std::make_shared<SystemDependentData_CairoSurface>(rBitmapEx);
+            = std::make_shared<SystemDependentData_CairoSurface>(rBitmap);
 
         // only add if feasible
         if (nullptr != pHolder
@@ -1301,13 +1280,13 @@ void CairoPixelProcessor2D::processBitmapPrimitive2D(
         }
     }
 
-    paintBitmapAlpha(rBitmapCandidate.getBitmap(), 
rBitmapCandidate.getTransform());
+    paintBitmapAlpha(Bitmap(rBitmapCandidate.getBitmap()), 
rBitmapCandidate.getTransform());
 
     if (bDrawModeFlagsUsed)
         maBColorModifierStack.pop();
 }
 
-void CairoPixelProcessor2D::paintBitmapAlpha(const BitmapEx& rBitmapEx,
+void CairoPixelProcessor2D::paintBitmapAlpha(const Bitmap& rBitmap,
                                              const basegfx::B2DHomMatrix& 
rTransform,
                                              double fTransparency)
 {
@@ -1335,9 +1314,9 @@ void CairoPixelProcessor2D::paintBitmapAlpha(const 
BitmapEx& rBitmapEx,
         }
     }
 
-    BitmapEx aBitmapEx(rBitmapEx);
+    Bitmap aBitmap(rBitmap);
 
-    if (aBitmapEx.IsEmpty() || aBitmapEx.GetSizePixel().IsEmpty())
+    if (aBitmap.IsEmpty() || aBitmap.GetSizePixel().IsEmpty())
     {
         // no pixel data, done
         return;
@@ -1346,9 +1325,9 @@ void CairoPixelProcessor2D::paintBitmapAlpha(const 
BitmapEx& rBitmapEx,
     if (maBColorModifierStack.count())
     {
         // need to apply ColorModifier to Bitmap data
-        aBitmapEx = aBitmapEx.ModifyBitmapEx(maBColorModifierStack);
+        aBitmap = aBitmap.Modify(maBColorModifierStack);
 
-        if (aBitmapEx.IsEmpty())
+        if (aBitmap.IsEmpty())
         {
             // color gets completely replaced, get it
             const basegfx::BColor aModifiedColor(
@@ -1367,8 +1346,7 @@ void CairoPixelProcessor2D::paintBitmapAlpha(const 
BitmapEx& rBitmapEx,
     }
 
     // access or create cairo bitmap data
-    std::shared_ptr<CairoSurfaceHelper> aCairoSurfaceHelper(
-        getOrCreateCairoSurfaceHelper(aBitmapEx));
+    std::shared_ptr<CairoSurfaceHelper> 
aCairoSurfaceHelper(getOrCreateCairoSurfaceHelper(aBitmap));
     if (!aCairoSurfaceHelper)
     {
         SAL_WARN("drawinglayer", "SDPRCairo: No SurfaceHelper from BitmapEx 
(!)");
@@ -2161,7 +2139,7 @@ void CairoPixelProcessor2D::processMarkerArrayPrimitive2D(
 
     // access or create cairo bitmap data
     std::shared_ptr<CairoSurfaceHelper> aCairoSurfaceHelper(
-        getOrCreateCairoSurfaceHelper(aBitmapEx));
+        getOrCreateCairoSurfaceHelper(Bitmap(aBitmapEx)));
     if (!aCairoSurfaceHelper)
     {
         SAL_WARN("drawinglayer", "SDPRCairo: No SurfaceHelper from BitmapEx 
(!)");
@@ -2517,7 +2495,7 @@ void CairoPixelProcessor2D::processFillGraphicPrimitive2D(
         return;
     }
 
-    BitmapEx aPreparedBitmap;
+    Bitmap aPreparedBitmap;
     basegfx::B2DRange 
aFillUnitRange(rFillGraphicPrimitive2D.getFillGraphic().getGraphicRange());
     constexpr double fBigDiscreteArea(300.0 * 300.0);
 
@@ -2568,7 +2546,7 @@ void CairoPixelProcessor2D::processFillGraphicPrimitive2D(
     if (!aPreparedBitmap.IsEmpty() && maBColorModifierStack.count())
     {
         // apply ColorModifier to Bitmap data
-        aPreparedBitmap = 
aPreparedBitmap.ModifyBitmapEx(maBColorModifierStack);
+        aPreparedBitmap = aPreparedBitmap.Modify(maBColorModifierStack);
 
         if (aPreparedBitmap.IsEmpty())
         {
@@ -3625,13 +3603,13 @@ void 
CairoPixelProcessor2D::processBitmapAlphaPrimitive2D(
     if (!rBitmapAlphaPrimitive2D.hasTransparency())
     {
         // do what CairoPixelProcessor2D::processPolyPolygonColorPrimitive2D 
does
-        paintBitmapAlpha(rBitmapAlphaPrimitive2D.getBitmap(),
+        paintBitmapAlpha(Bitmap(rBitmapAlphaPrimitive2D.getBitmap()),
                          rBitmapAlphaPrimitive2D.getTransform());
     }
     else
     {
         // draw with alpha directly
-        paintBitmapAlpha(rBitmapAlphaPrimitive2D.getBitmap(),
+        paintBitmapAlpha(Bitmap(rBitmapAlphaPrimitive2D.getBitmap()),
                          rBitmapAlphaPrimitive2D.getTransform(),
                          rBitmapAlphaPrimitive2D.getTransparency());
     }
diff --git a/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx 
b/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx
index 412fbaa92a59..16e116b2bd37 100644
--- a/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx
@@ -1817,7 +1817,7 @@ void D2DPixelProcessor2D::processFillGraphicPrimitive2D(
         return;
     }
 
-    BitmapEx aPreparedBitmap;
+    Bitmap aPreparedBitmap;
     basegfx::B2DRange 
aFillUnitRange(rFillGraphicPrimitive2D.getFillGraphic().getGraphicRange());
     constexpr double fBigDiscreteArea(300.0 * 300.0);
 
@@ -1842,7 +1842,7 @@ void D2DPixelProcessor2D::processFillGraphicPrimitive2D(
     if (maBColorModifierStack.count())
     {
         // need to apply ColorModifier to Bitmap data
-        aPreparedBitmap = 
aPreparedBitmap.ModifyBitmapEx(maBColorModifierStack);
+        aPreparedBitmap = aPreparedBitmap.Modify(maBColorModifierStack);
 
         if (aPreparedBitmap.IsEmpty())
         {
@@ -1871,7 +1871,7 @@ void D2DPixelProcessor2D::processFillGraphicPrimitive2D(
 
     bool bDone(false);
     sal::systools::COMReference<ID2D1Bitmap> pD2DBitmap(
-        getOrCreateB2DBitmap(getRenderTarget(), aPreparedBitmap));
+        getOrCreateB2DBitmap(getRenderTarget(), BitmapEx(aPreparedBitmap)));
 
     if (pD2DBitmap)
     {
diff --git a/include/basegfx/utils/systemdependentdata.hxx 
b/include/basegfx/utils/systemdependentdata.hxx
index b07ae267e662..2d174f21f548 100644
--- a/include/basegfx/utils/systemdependentdata.hxx
+++ b/include/basegfx/utils/systemdependentdata.hxx
@@ -51,6 +51,7 @@ namespace basegfx
         SDDType_MaskHelper,
         SDDType_CairoPath,
         SDDType_ModifiedBitmapEx,
+        SDDType_ModifiedBitmap,
         SDDType_GraphicsPath,
         SDDType_GdiPlusBitmap
     };
diff --git a/include/drawinglayer/primitive2d/fillgraphicprimitive2d.hxx 
b/include/drawinglayer/primitive2d/fillgraphicprimitive2d.hxx
index 4688d3dacdf8..2f8e660b4397 100644
--- a/include/drawinglayer/primitive2d/fillgraphicprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/fillgraphicprimitive2d.hxx
@@ -38,7 +38,7 @@ namespace drawinglayer::processor2d
 // from there
 void setOffsetXYCreatedBitmap(
     drawinglayer::primitive2d::FillGraphicPrimitive2D&,
-    const BitmapEx&);
+    const Bitmap&);
 }
 
 // FillbitmapPrimitive2D class
@@ -73,7 +73,7 @@ namespace drawinglayer::primitive2d
             attribute::FillGraphicAttribute             maFillGraphic;
 
             /// the evtl. buffered OffsetXYCreatedBitmap
-            BitmapEx                                    
maOffsetXYCreatedBitmap;
+            Bitmap                                      
maOffsetXYCreatedBitmap;
 
             /// the transparency in range [0.0 .. 1.0]
             double mfTransparency;
@@ -84,10 +84,10 @@ namespace drawinglayer::primitive2d
             // allow this single accessor to change it to set buggered data
             friend void drawinglayer::processor2d::setOffsetXYCreatedBitmap(
                 drawinglayer::primitive2d::FillGraphicPrimitive2D&,
-                const BitmapEx&);
+                const Bitmap&);
 
             // private tooling method to be called by setOffsetXYCreatedBitmap
-            void impSetOffsetXYCreatedBitmap(const BitmapEx& rBitmap)
+            void impSetOffsetXYCreatedBitmap(const Bitmap& rBitmap)
             {
                 maOffsetXYCreatedBitmap = rBitmap;
             }
@@ -102,7 +102,7 @@ namespace drawinglayer::primitive2d
             /// data read access
             const basegfx::B2DHomMatrix& getTransformation() const { return 
maTransformation; }
             const attribute::FillGraphicAttribute& getFillGraphic() const { 
return maFillGraphic; }
-            const BitmapEx& getOffsetXYCreatedBitmap() const { return 
maOffsetXYCreatedBitmap; }
+            const Bitmap& getOffsetXYCreatedBitmap() const { return 
maOffsetXYCreatedBitmap; }
             double getTransparency() const { return mfTransparency; }
             bool hasTransparency() const { return 
!basegfx::fTools::equalZero(mfTransparency); }
 
diff --git a/include/drawinglayer/processor2d/SDPRProcessor2dTools.hxx 
b/include/drawinglayer/processor2d/SDPRProcessor2dTools.hxx
index 0dd81f594fa5..c26dc296cffe 100644
--- a/include/drawinglayer/processor2d/SDPRProcessor2dTools.hxx
+++ b/include/drawinglayer/processor2d/SDPRProcessor2dTools.hxx
@@ -36,6 +36,7 @@ namespace basegfx
 class B2DRange;
 }
 
+class Bitmap;
 class BitmapEx;
 
 namespace drawinglayer::processor2d
@@ -82,7 +83,7 @@ namespace drawinglayer::processor2d
     */
 bool prepareBitmapForDirectRender(
     const drawinglayer::primitive2d::FillGraphicPrimitive2D& 
rFillGraphicPrimitive2D,
-    const drawinglayer::geometry::ViewInformation2D& rViewInformation2D, 
BitmapEx& rTarget,
+    const drawinglayer::geometry::ViewInformation2D& rViewInformation2D, 
Bitmap& rTarget,
     basegfx::B2DRange& rFillUnitRange, double fBigDiscreteArea = 300.0 * 
300.0);
 
 /** helper to react/process if OffsetX/OffsetY of the FillGraphicAttribute is 
used.
@@ -98,7 +99,7 @@ bool prepareBitmapForDirectRender(
     */
 void takeCareOfOffsetXY(
     const drawinglayer::primitive2d::FillGraphicPrimitive2D& 
rFillGraphicPrimitive2D,
-    BitmapEx& rTarget, basegfx::B2DRange& rFillUnitRange);
+    Bitmap& rTarget, basegfx::B2DRange& rFillUnitRange);
 
 /** helper to calculate a discrete visible range based on a given logic range
     and a current ViewInformation2D. This is used for pixel renderers.
diff --git a/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx 
b/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx
index 3e5ecff28965..af3a1d63a710 100644
--- a/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx
+++ b/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx
@@ -61,6 +61,7 @@ namespace basegfx::utils
 class B2DHomMatrixBufferedOnDemandDecompose;
 }
 
+class Bitmap;
 class BitmapEx;
 class OutputDevice;
 class SalLayout;
@@ -134,7 +135,7 @@ class UNLESS_MERGELIBS(DRAWINGLAYER_DLLPUBLIC) 
CairoPixelProcessor2D final : pub
     void processPolyPolygonAlphaGradientPrimitive2D(
         const primitive2d::PolyPolygonAlphaGradientPrimitive2D&
             rPolyPolygonAlphaGradientPrimitive2D);
-    void paintBitmapAlpha(const BitmapEx& rBitmapEx, const 
basegfx::B2DHomMatrix& rTransform,
+    void paintBitmapAlpha(const Bitmap& rBitmap, const basegfx::B2DHomMatrix& 
rTransform,
                           double fTransparency = 0.0);
     void processBitmapAlphaPrimitive2D(
         const primitive2d::BitmapAlphaPrimitive2D& rBitmapAlphaPrimitive2D);
diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx
index 32d529d393fb..c0f2851b6889 100644
--- a/include/vcl/bitmap.hxx
+++ b/include/vcl/bitmap.hxx
@@ -37,6 +37,7 @@
 #include <memory>
 
 class BitmapEx;
+namespace basegfx { class BColorModifierStack; }
 
 inline sal_uInt8 GAMMA(double _def_cVal, double _def_InvGamma)
 {
@@ -598,6 +599,14 @@ public:
     */
     std::pair<Bitmap, AlphaMask> SplitIntoColorAndAlpha() const;
 
+   /** Create ColorStack-modified version of this BitmapEx
+
+        @param rBColorModifierStack
+        A ColrModifierStack which defines how each pixel has to be modified
+    */
+    [[nodiscard]]
+    Bitmap            Modify( const basegfx::BColorModifierStack& 
rBColorModifierStack) const;
+
 public:
     /** ReassignWithSize and recalculate bitmap.
 
diff --git a/vcl/source/bitmap/bitmap.cxx b/vcl/source/bitmap/bitmap.cxx
index 7471778967f7..72a84373d14f 100644
--- a/vcl/source/bitmap/bitmap.cxx
+++ b/vcl/source/bitmap/bitmap.cxx
@@ -37,6 +37,8 @@
 #include <vcl/bitmap/BitmapMonochromeFilter.hxx>
 #include <vcl/ImageTree.hxx>
 
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/color/bcolormodifier.hxx>
 #include <bitmap/BitmapScaleSuperFilter.hxx>
 #include <bitmap/BitmapScaleConvolutionFilter.hxx>
 #include <bitmap/BitmapFastScaleFilter.hxx>
@@ -1863,5 +1865,207 @@ void Bitmap::Expand(sal_Int32 nDX, sal_Int32 nDY, bool 
bExpandTransparent)
     operator=(Bitmap(aTmpEx));
 }
 
+namespace
+{
+class BufferedData_ModifiedBitmap : public basegfx::SystemDependentData
+{
+    Bitmap maChangedBitmap;
+    basegfx::BColorModifierStack maBColorModifierStack;
+
+public:
+    BufferedData_ModifiedBitmap(
+        const Bitmap& rChangedBitmap,
+        const basegfx::BColorModifierStack& rBColorModifierStack)
+    : basegfx::SystemDependentData(
+        Application::GetSystemDependentDataManager(),
+        basegfx::SDD_Type::SDDType_ModifiedBitmap)
+    , maChangedBitmap(rChangedBitmap)
+    , maBColorModifierStack(rBColorModifierStack)
+    {
+    }
+
+    const Bitmap& getChangedBitmap() const { return maChangedBitmap; }
+    const basegfx::BColorModifierStack& getBColorModifierStack() const { 
return maBColorModifierStack; }
+
+    virtual sal_Int64 estimateUsageInBytes() const override;
+};
+
+sal_Int64 BufferedData_ModifiedBitmap::estimateUsageInBytes() const
+{
+    return maChangedBitmap.GetSizeBytes();
+}
+}
+
+Bitmap Bitmap::Modify(const basegfx::BColorModifierStack& 
rBColorModifierStack) const
+{
+    if (0 == rBColorModifierStack.count())
+    {
+        // no modifiers, done
+        return *this;
+    }
+
+    // check for BColorModifier_replace at the top of the stack
+    const basegfx::BColorModifierSharedPtr& 
rLastModifier(rBColorModifierStack.getBColorModifier(rBColorModifierStack.count()
 - 1));
+    const basegfx::BColorModifier_replace* 
pLastModifierReplace(dynamic_cast<const 
basegfx::BColorModifier_replace*>(rLastModifier.get()));
+
+    if (nullptr != pLastModifierReplace && !HasAlpha())
+    {
+        // at the top of the stack we have a BColorModifier_replace -> no 
Bitmap needed,
+        // representation can be replaced by filled colored polygon. signal 
the caller
+        // about that by returning empty BitmapEx
+        return Bitmap();
+    }
+
+    const basegfx::SystemDependentDataHolder* 
pHolder(accessSystemDependentDataHolder());
+    std::shared_ptr<BufferedData_ModifiedBitmap> pBufferedData_ModifiedBitmap;
+
+    if (nullptr != pHolder)
+    {
+        // try to access SystemDependentDataHolder and buffered data
+        pBufferedData_ModifiedBitmap = 
std::static_pointer_cast<BufferedData_ModifiedBitmap>(
+            
pHolder->getSystemDependentData(basegfx::SDD_Type::SDDType_ModifiedBitmap));
+
+        if (nullptr != pBufferedData_ModifiedBitmap
+            && !(pBufferedData_ModifiedBitmap->getBColorModifierStack() == 
rBColorModifierStack))
+        {
+            // BColorModifierStack is different -> data invalid
+            pBufferedData_ModifiedBitmap = nullptr;
+        }
+
+        if (nullptr != pBufferedData_ModifiedBitmap)
+        {
+            // found existing instance of modified Bitmap, return 
reused/buffered result
+            return pBufferedData_ModifiedBitmap->getChangedBitmap();
+        }
+    }
+
+    // have to create modified Bitmap
+    Bitmap aChangedBitmap(*this);
+
+    if (nullptr != pLastModifierReplace)
+    {
+        // special case -> we have BColorModifier_replace but Alpha channel
+        if (vcl::isPalettePixelFormat(aChangedBitmap.getPixelFormat()))
+        {
+            // For e.g. 8bit Bitmaps, the nearest color to the given erase 
color is
+            // determined and used -> this may be different from what is 
wanted here.
+            // Better create a new bitmap with the needed color explicitly.
+            BitmapScopedReadAccess xReadAccess(aChangedBitmap);
+            SAL_WARN_IF(!xReadAccess, "vcl", "Got no Bitmap ReadAccess ?!?");
+
+            if(xReadAccess)
+            {
+                BitmapPalette aNewPalette(xReadAccess->GetPalette());
+                aNewPalette[0] = 
BitmapColor(Color(pLastModifierReplace->getBColor()));
+                aChangedBitmap = Bitmap(
+                    aChangedBitmap.GetSizePixel(),
+                    aChangedBitmap.getPixelFormat(),
+                    &aNewPalette);
+            }
+        }
+        else
+        {
+            // clear bitmap with dest color
+            aChangedBitmap.Erase(Color(pLastModifierReplace->getBColor()));
+        }
+    }
+    else
+    {
+        BitmapScopedWriteAccess xContent(aChangedBitmap);
+
+        if(xContent)
+        {
+            const double fConvertColor(1.0 / 255.0);
+
+            if(xContent->HasPalette())
+            {
+                const sal_uInt16 nCount(xContent->GetPaletteEntryCount());
+
+                for(sal_uInt16 b(0); b < nCount; b++)
+                {
+                    const BitmapColor& rCol = xContent->GetPaletteColor(b);
+                    const basegfx::BColor aBSource(
+                        rCol.GetRed() * fConvertColor,
+                        rCol.GetGreen() * fConvertColor,
+                        rCol.GetBlue() * fConvertColor);
+                    const basegfx::BColor 
aBDest(rBColorModifierStack.getModifiedColor(aBSource));
+                    xContent->SetPaletteColor(b, BitmapColor(Color(aBDest)));
+                }
+            }
+            else if(ScanlineFormat::N24BitTcBgr == 
xContent->GetScanlineFormat())
+            {
+                for(tools::Long y(0), nHeight(xContent->Height()); y < 
nHeight; y++)
+                {
+                    Scanline pScan = xContent->GetScanline(y);
+
+                    for(tools::Long x(0), nWidth(xContent->Width()); x < 
nWidth; x++)
+                    {
+                        const basegfx::BColor aBSource(
+                            *(pScan + 2)* fConvertColor,
+                            *(pScan + 1) * fConvertColor,
+                            *pScan * fConvertColor);
+                        const basegfx::BColor 
aBDest(rBColorModifierStack.getModifiedColor(aBSource));
+                        *pScan++ = static_cast< sal_uInt8 >(aBDest.getBlue() * 
255.0);
+                        *pScan++ = static_cast< sal_uInt8 >(aBDest.getGreen() 
* 255.0);
+                        *pScan++ = static_cast< sal_uInt8 >(aBDest.getRed() * 
255.0);
+                    }
+                }
+            }
+            else if(ScanlineFormat::N24BitTcRgb == 
xContent->GetScanlineFormat())
+            {
+                for(tools::Long y(0), nHeight(xContent->Height()); y < 
nHeight; y++)
+                {
+                    Scanline pScan = xContent->GetScanline(y);
+
+                    for(tools::Long x(0), nWidth(xContent->Width()); x < 
nWidth; x++)
+                    {
+                        const basegfx::BColor aBSource(
+                            *pScan * fConvertColor,
+                            *(pScan + 1) * fConvertColor,
+                            *(pScan + 2) * fConvertColor);
+                        const basegfx::BColor 
aBDest(rBColorModifierStack.getModifiedColor(aBSource));
+                        *pScan++ = static_cast< sal_uInt8 >(aBDest.getRed() * 
255.0);
+                        *pScan++ = static_cast< sal_uInt8 >(aBDest.getGreen() 
* 255.0);
+                        *pScan++ = static_cast< sal_uInt8 >(aBDest.getBlue() * 
255.0);
+                    }
+                }
+            }
+            else
+            {
+                for(tools::Long y(0), nHeight(xContent->Height()); y < 
nHeight; y++)
+                {
+                    Scanline pScanline = xContent->GetScanline( y );
+                    for(tools::Long x(0), nWidth(xContent->Width()); x < 
nWidth; x++)
+                    {
+                        const BitmapColor aBMCol(xContent->GetColor(y, x));
+                        const basegfx::BColor aBSource(
+                            static_cast<double>(aBMCol.GetRed()) * 
fConvertColor,
+                            static_cast<double>(aBMCol.GetGreen()) * 
fConvertColor,
+                            static_cast<double>(aBMCol.GetBlue()) * 
fConvertColor);
+                        const basegfx::BColor 
aBDest(rBColorModifierStack.getModifiedColor(aBSource));
+
+                        xContent->SetPixelOnData(pScanline, x, 
BitmapColor(Color(aBDest)));
+                    }
+                }
+            }
+        }
+    }
+
+    if (nullptr != pHolder)
+    {
+        // create new BufferedData_ModifiedBitmapEx (should be nullptr here)
+        if (nullptr == pBufferedData_ModifiedBitmap)
+        {
+            pBufferedData_ModifiedBitmap = 
std::make_shared<BufferedData_ModifiedBitmap>(aChangedBitmap, 
rBColorModifierStack);
+        }
+
+        // register it, evtl. it's a new one
+        basegfx::SystemDependentData_SharedPtr 
r2(pBufferedData_ModifiedBitmap);
+        
const_cast<basegfx::SystemDependentDataHolder*>(pHolder)->addOrReplaceSystemDependentData(r2);
+    }
+
+    // return result
+    return aChangedBitmap;
+}
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to