drawinglayer/source/processor2d/cairopixelprocessor2d.cxx |   38 +++++++++++++-
 include/vcl/bitmap.hxx                                    |    5 +
 vcl/source/bitmap/bitmap.cxx                              |   34 ++++++++++++
 3 files changed, 76 insertions(+), 1 deletion(-)

New commits:
commit e565a0d634c80a258340f73dc6f4a45cc3e180cc
Author:     Noel Grandin <noel.gran...@collabora.co.uk>
AuthorDate: Mon Sep 15 17:55:14 2025 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Fri Sep 19 16:56:24 2025 +0200

    tdf#168392 Disappearing image fill at lower zoom
    
    regression from
      commit cd93f83bbcba0379bf39f3a4e76b955b7fa368b5
      Author: Armin Le Grand (collabora) <armin.legr...@collabora.com>
      Date:   Thu Aug 7 21:02:41 2025 +0200
      tdf#167831 avoid painting bitmap data with zero dimensions
    
    we cannot skip these fills if the fill bitmap is too small,
    we need to fill with something or the resulting picture
    is very wrong
    
    Change-Id: I194b59414db8f675df2415c3ee4fb9a0305611b3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190981
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx 
b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
index ae0931833d6f..9f6b5a2e6ec5 100644
--- a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
@@ -2482,7 +2482,43 @@ void 
CairoPixelProcessor2D::processFillGraphicPrimitive2D(
     // tdf#167831 check for output size, may have zero discrete dimension in X 
and/or Y
     if (0 == nDestWidth || 0 == nDestHeight)
     {
-        // it has and is thus invisible
+        // In which case, maybe we are zoomed out far enough to make the fill 
bitmap less than one pixel by one pixel,
+        // and so we need to fill with a color that is an average of the 
bitmap's color.
+        basegfx::BColor aFillColor = 
aPreparedBitmap.GetAverageColor().getBColor();
+        bool bTemporaryGrayColorModifier(false);
+        const DrawModeFlags 
aDrawModeFlags(getViewInformation2D().getDrawModeFlags());
+        if (aDrawModeFlags & DrawModeFlags::GrayBitmap)
+        {
+            bTemporaryGrayColorModifier = true;
+            const basegfx::BColorModifierSharedPtr aBColorModifier(
+                std::make_shared<basegfx::BColorModifier_gray>());
+            maBColorModifierStack.push(aBColorModifier);
+        }
+
+        if (maBColorModifierStack.count())
+        {
+            // apply ColorModifier to Bitmap data
+            aFillColor = maBColorModifierStack.getModifiedColor(aFillColor);
+
+            if (bTemporaryGrayColorModifier)
+                // cleanup temporary BColorModifier
+                maBColorModifierStack.pop();
+        }
+
+        // draw geometry in single color using prepared ReplacementColor
+
+        // use unit geometry as fallback object geometry. Do *not*
+        // transform, the below used method will use the already
+        // correctly initialized local ViewInformation
+        basegfx::B2DPolygon aPolygon(basegfx::utils::createUnitPolygon());
+
+        // what we still need to apply is the object transform from the
+        // local primitive, that is not part of DisplayInfo yet
+        aPolygon.transform(rFillGraphicPrimitive2D.getTransformation());
+
+        // draw directly, done
+        paintPolyPolygonRGBA(basegfx::B2DPolyPolygon(aPolygon), aFillColor,
+                             rFillGraphicPrimitive2D.getTransparency());
         return;
     }
 
diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx
index de1f27a69f84..b8704fe60095 100644
--- a/include/vcl/bitmap.hxx
+++ b/include/vcl/bitmap.hxx
@@ -687,6 +687,11 @@ public:
     [[nodiscard]]
     Bitmap            Modify( const basegfx::BColorModifierStack& 
rBColorModifierStack) const;
 
+    /** Get the average color of the entire image.
+        i.e. like scaling it down to a 1x1 pixel image.
+    */
+    Color             GetAverageColor() const;
+
     [[nodiscard]]
     static Bitmap     AutoScaleBitmap( Bitmap const & rBitmap, const 
tools::Long aStandardSize );
 
diff --git a/vcl/source/bitmap/bitmap.cxx b/vcl/source/bitmap/bitmap.cxx
index 9e769b13cee1..069c9b4b56d3 100644
--- a/vcl/source/bitmap/bitmap.cxx
+++ b/vcl/source/bitmap/bitmap.cxx
@@ -2141,6 +2141,40 @@ Bitmap Bitmap::Modify(const 
basegfx::BColorModifierStack& rBColorModifierStack)
     return aChangedBitmap;
 }
 
+/** Get the average color of the entire image.
+    i.e. like scaling it down to a 1x1 pixel image.
+*/
+Color Bitmap::GetAverageColor() const
+{
+    BitmapScopedReadAccess xContent(*this);
+    assert(xContent);
+    if(!xContent)
+        return Color();
+
+    double fRed = 0;
+    double fGreen = 0;
+    double fBlue = 0;
+    double fAlpha = 0;
+    int nCnt = 0;
+    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 aCol(xContent->GetPixelFromData(pScanline, x));
+            fRed += aCol.GetRed();
+            fGreen += aCol.GetGreen();
+            fBlue += aCol.GetBlue();
+            fAlpha += aCol.GetAlpha();
+            nCnt++;
+        }
+    }
+    return Color(ColorAlpha, static_cast<sal_uInt8>(fAlpha / nCnt),
+                   static_cast<sal_uInt8>(fRed / nCnt),
+                   static_cast<sal_uInt8>(fGreen / nCnt),
+                   static_cast<sal_uInt8>(fBlue / nCnt));
+}
+
 void Bitmap::Draw( OutputDevice* pOutDev, const Point& rDestPt ) const
 {
     pOutDev->DrawBitmapEx( rDestPt, *this );

Reply via email to