drawinglayer/source/processor2d/cairopixelprocessor2d.cxx  |  592 ++++++++++---
 include/drawinglayer/processor2d/cairopixelprocessor2d.hxx |   15 
 svx/source/sdr/overlay/overlaymanager.cxx                  |   21 
 3 files changed, 485 insertions(+), 143 deletions(-)

New commits:
commit d569a6b335d27ac13487e5e66cd9880439beb03b
Author:     Armin Le Grand (collabora) <armin.legr...@collabora.com>
AuthorDate: Tue Jul 29 13:58:33 2025 +0200
Commit:     Armin Le Grand <armin.le.gr...@me.com>
CommitDate: Thu Jul 31 16:51:35 2025 +0200

    tdf#167511 Added use of DrawModeFlags to CairoSDPR
    
    Did the necessary now, despite it would be better to apply
    that where the geometry gets created (primitives) or painted
    (older direct-apints to OutputDevice).
    Instead it's in Outputevice where care is taken to apply
    changes based on DrawModeFlags. Remember that this is then
    done in the renderer.
    This will need to be done in every renderer in the future
    then. It is traditionally done in OutputDevice, completely
    missing in PresentationMode and added now to CairoSDPR.
    
    Problem is that it is not defined how to apply that, e.g.
    (even in OutDev) painting text may lead to decompose and
    fill the resulting polygons, so the ::*Fill flags are
    applied while I think the ::*Text ones should be used.
    
    I looked a lot at OutDev and what it does and tried to
    mimic it as good as possible, but cannot give guarantees,
    as mentioned in the example above.
    
    If we assume that (as usual) the definition of what should
    happen is the existing stuff when using OutDev this might
    cause some further errors/regressions in HighContrast
    and Black/White/Gray/Settings stuff. Luckily most of that
    seems to be used in UI/Button rendering when using
    OutDev, so should not lead to big problems. OTOH if
    we want to use SDPRs for that in the future we would need
    that anyways...
    
    One more note: the fixes already applied may be removed
    again after this is applied.
    
    Change-Id: Ie6eb1cd4ee51c62beb950030a0a5d00d3705be61
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188527
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>
    Tested-by: Jenkins
    Reviewed-by: Armin Le Grand <armin.le.gr...@me.com>

diff --git a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx 
b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
index 944eb6000af6..7e5d6eb286fa 100644
--- a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
@@ -964,11 +964,12 @@ void CairoPixelProcessor2D::updateViewInformation(
                                                                           : 
CAIRO_ANTIALIAS_NONE);
 }
 
-CairoPixelProcessor2D::CairoPixelProcessor2D(const 
geometry::ViewInformation2D& rViewInformation,
-                                             cairo_surface_t* pTarget)
+CairoPixelProcessor2D::CairoPixelProcessor2D(
+    const basegfx::BColorModifierStack& rBColorModifierStack, const 
DrawModeFlags& rDrawModeFlags,
+    const geometry::ViewInformation2D& rViewInformation, cairo_surface_t* 
pTarget)
     : BaseProcessor2D(rViewInformation)
     , mpTargetOutputDevice(nullptr)
-    , maBColorModifierStack()
+    , maBColorModifierStack(rBColorModifierStack)
     , mpOwnedSurface(nullptr)
     , mpRT(nullptr)
     , mbRenderSimpleTextDirect(
@@ -976,6 +977,7 @@ CairoPixelProcessor2D::CairoPixelProcessor2D(const 
geometry::ViewInformation2D&
     , mbRenderDecoratedTextDirect(
           
officecfg::Office::Common::Drawinglayer::RenderDecoratedTextDirect::get())
     , mnClipRecursionCount(0)
+    , maDrawModeFlags(rDrawModeFlags)
     , mbCairoCoordinateLimitWorkaroundActive(false)
 {
     // no target, nothing to initialize
@@ -1012,6 +1014,7 @@ CairoPixelProcessor2D::CairoPixelProcessor2D(const 
geometry::ViewInformation2D&
     , mbRenderDecoratedTextDirect(
           
officecfg::Office::Common::Drawinglayer::RenderDecoratedTextDirect::get())
     , mnClipRecursionCount(0)
+    , maDrawModeFlags(DrawModeFlags::Default)
     , mbCairoCoordinateLimitWorkaroundActive(false)
 {
     if (nWidthPixel <= 0 || nHeightPixel <= 0)
@@ -1054,6 +1057,7 @@ 
CairoPixelProcessor2D::CairoPixelProcessor2D(OutputDevice& rOutputDevice,
     , mbRenderDecoratedTextDirect(
           
officecfg::Office::Common::Drawinglayer::RenderDecoratedTextDirect::get())
     , mnClipRecursionCount(0)
+    , maDrawModeFlags(rOutputDevice.GetDrawMode())
     , mbCairoCoordinateLimitWorkaroundActive(false)
 {
     SystemGraphicsData aData(mpTargetOutputDevice->GetSystemGfxData());
@@ -1278,7 +1282,38 @@ BitmapEx CairoPixelProcessor2D::extractBitmapEx() const
 void CairoPixelProcessor2D::processBitmapPrimitive2D(
     const primitive2d::BitmapPrimitive2D& rBitmapCandidate)
 {
+    constexpr DrawModeFlags BITMAP(DrawModeFlags::BlackBitmap | 
DrawModeFlags::WhiteBitmap
+                                   | DrawModeFlags::GrayBitmap);
+    const bool bDrawModeFlagsUsed(maDrawModeFlags & BITMAP);
+
+    if (bDrawModeFlagsUsed)
+    {
+        // if DrawModeFlags for Bitmap are used, encapsulate with
+        // corresponding BColorModifier
+        if (maDrawModeFlags & DrawModeFlags::BlackBitmap)
+        {
+            const basegfx::BColorModifierSharedPtr aBColorModifier(
+                
std::make_shared<basegfx::BColorModifier_replace>(basegfx::BColor(0, 0, 0)));
+            maBColorModifierStack.push(aBColorModifier);
+        }
+        else if (maDrawModeFlags & DrawModeFlags::WhiteBitmap)
+        {
+            const basegfx::BColorModifierSharedPtr aBColorModifier(
+                
std::make_shared<basegfx::BColorModifier_replace>(basegfx::BColor(1, 1, 1)));
+            maBColorModifierStack.push(aBColorModifier);
+        }
+        else // DrawModeFlags::GrayBitmap
+        {
+            const basegfx::BColorModifierSharedPtr aBColorModifier(
+                std::make_shared<basegfx::BColorModifier_gray>());
+            maBColorModifierStack.push(aBColorModifier);
+        }
+    }
+
     paintBitmapAlpha(rBitmapCandidate.getBitmap(), 
rBitmapCandidate.getTransform());
+
+    if (bDrawModeFlagsUsed)
+        maBColorModifierStack.pop();
 }
 
 void CairoPixelProcessor2D::paintBitmapAlpha(const BitmapEx& rBitmapEx,
@@ -1464,8 +1499,8 @@ void CairoPixelProcessor2D::processPointArrayPrimitive2D(
     cairo_save(mpRT);
 
     // determine & set color
-    const basegfx::BColor aPointColor(
-        
maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor()));
+    basegfx::BColor 
aPointColor(getLineColor(rPointArrayCandidate.getRGBColor()));
+    aPointColor = maBColorModifierStack.getModifiedColor(aPointColor);
     cairo_set_source_rgb(mpRT, aPointColor.getRed(), aPointColor.getGreen(), 
aPointColor.getBlue());
 
     // To really paint a single pixel I found nothing better than
@@ -1502,8 +1537,8 @@ void 
CairoPixelProcessor2D::processPolygonHairlinePrimitive2D(
     cairo_save(mpRT);
 
     // determine & set color
-    const basegfx::BColor aHairlineColor(
-        
maBColorModifierStack.getModifiedColor(rPolygonHairlinePrimitive2D.getBColor()));
+    basegfx::BColor 
aHairlineColor(getLineColor(rPolygonHairlinePrimitive2D.getBColor()));
+    aHairlineColor = maBColorModifierStack.getModifiedColor(aHairlineColor);
     cairo_set_source_rgb(mpRT, aHairlineColor.getRed(), 
aHairlineColor.getGreen(),
                          aHairlineColor.getBlue());
 
@@ -1551,8 +1586,12 @@ void 
CairoPixelProcessor2D::processPolygonHairlinePrimitive2D(
 void CairoPixelProcessor2D::processPolyPolygonColorPrimitive2D(
     const primitive2d::PolyPolygonColorPrimitive2D& 
rPolyPolygonColorPrimitive2D)
 {
-    paintPolyPolygonRGBA(rPolyPolygonColorPrimitive2D.getB2DPolyPolygon(),
-                         rPolyPolygonColorPrimitive2D.getBColor());
+    if (maDrawModeFlags & DrawModeFlags::NoFill)
+        // NoFill wanted, done
+        return;
+
+    const basegfx::BColor 
aFillColor(getFillColor(rPolyPolygonColorPrimitive2D.getBColor()));
+    paintPolyPolygonRGBA(rPolyPolygonColorPrimitive2D.getB2DPolyPolygon(), 
aFillColor);
 }
 
 void CairoPixelProcessor2D::paintPolyPolygonRGBA(const 
basegfx::B2DPolyPolygon& rPolyPolygon,
@@ -1669,7 +1708,8 @@ void 
CairoPixelProcessor2D::processTransparencePrimitive2D(
     const double fContainedHeight(aVisibleRange.getHeight());
     cairo_surface_t* pMask(cairo_surface_create_similar_image(pTarget, 
CAIRO_FORMAT_ARGB32,
                                                               fContainedWidth, 
fContainedHeight));
-    CairoPixelProcessor2D aMaskRenderer(aViewInformation2D, pMask);
+    CairoPixelProcessor2D aMaskRenderer(getBColorModifierStack(), 
maDrawModeFlags,
+                                        aViewInformation2D, pMask);
     aMaskRenderer.process(rTransCandidate.getTransparence());
 
     // convert mask to something cairo can use
@@ -1678,11 +1718,8 @@ void 
CairoPixelProcessor2D::processTransparencePrimitive2D(
     // draw content to temporary surface
     cairo_surface_t* pContent(cairo_surface_create_similar(
         pTarget, cairo_surface_get_content(pTarget), fContainedWidth, 
fContainedHeight));
-    CairoPixelProcessor2D aContent(aViewInformation2D, pContent);
-
-    // important for content rendering: need to take over the 
ColorModifierStack
-    aContent.setBColorModifierStack(getBColorModifierStack());
-
+    CairoPixelProcessor2D aContent(getBColorModifierStack(), maDrawModeFlags, 
aViewInformation2D,
+                                   pContent);
     aContent.process(rTransCandidate.getChildren());
 
     // munge the temporary surfaces to our target surface
@@ -1740,11 +1777,8 @@ void CairoPixelProcessor2D::processInvertPrimitive2D(
     const double fContainedHeight(aVisibleRange.getHeight());
     cairo_surface_t* pContent(cairo_surface_create_similar_image(
         pTarget, CAIRO_FORMAT_ARGB32, fContainedWidth, fContainedHeight));
-    CairoPixelProcessor2D aContent(aViewInformation2D, pContent);
-
-    // take over evtl. used ColorModifierStack for content
-    aContent.setBColorModifierStack(getBColorModifierStack());
-
+    CairoPixelProcessor2D aContent(getBColorModifierStack(), maDrawModeFlags, 
aViewInformation2D,
+                                   pContent);
     aContent.process(rInvertCandidate.getChildren());
     cairo_surface_flush(pContent);
 
@@ -2058,11 +2092,8 @@ void 
CairoPixelProcessor2D::processUnifiedTransparencePrimitive2D(
     const double fContainedHeight(aVisibleRange.getHeight());
     cairo_surface_t* pContent(cairo_surface_create_similar(
         pTarget, cairo_surface_get_content(pTarget), fContainedWidth, 
fContainedHeight));
-    CairoPixelProcessor2D aContent(aViewInformation2D, pContent);
-
-    // take over evtl. used ColorModifierStack for content
-    aContent.setBColorModifierStack(getBColorModifierStack());
-
+    CairoPixelProcessor2D aContent(getBColorModifierStack(), maDrawModeFlags, 
aViewInformation2D,
+                                   pContent);
     aContent.process(rTransCandidate.getChildren());
 
     // paint temporary surface to target with fixed transparence
@@ -2094,10 +2125,55 @@ void 
CairoPixelProcessor2D::processMarkerArrayPrimitive2D(
         return;
     }
 
+    // prepare Marker's Bitmap
+    BitmapEx aBitmapEx(rMarkerArrayCandidate.getMarker());
+
+    constexpr DrawModeFlags BITMAP(DrawModeFlags::BlackBitmap | 
DrawModeFlags::WhiteBitmap
+                                   | DrawModeFlags::GrayBitmap);
+    if (maDrawModeFlags & BITMAP)
+    {
+        if (maDrawModeFlags & DrawModeFlags::BlackBitmap)
+        {
+            const basegfx::BColorModifierSharedPtr aBColorModifier(
+                
std::make_shared<basegfx::BColorModifier_replace>(basegfx::BColor(0, 0, 0)));
+            maBColorModifierStack.push(aBColorModifier);
+        }
+        else if (maDrawModeFlags & DrawModeFlags::WhiteBitmap)
+        {
+            const basegfx::BColorModifierSharedPtr aBColorModifier(
+                
std::make_shared<basegfx::BColorModifier_replace>(basegfx::BColor(1, 1, 1)));
+            maBColorModifierStack.push(aBColorModifier);
+        }
+        else // DrawModeFlags::GrayBitmap
+        {
+            const basegfx::BColorModifierSharedPtr aBColorModifier(
+                std::make_shared<basegfx::BColorModifier_gray>());
+            maBColorModifierStack.push(aBColorModifier);
+        }
+
+        // need to apply ColorModifier to Bitmap data
+        aBitmapEx = aBitmapEx.ModifyBitmapEx(maBColorModifierStack);
+
+        if (aBitmapEx.IsEmpty())
+        {
+            // color gets completely replaced, get it
+            const basegfx::BColor aReplacementColor(
+                maBColorModifierStack.getModifiedColor(basegfx::BColor()));
+            Bitmap aBitmap(rMarker.GetSizePixel(), vcl::PixelFormat::N24_BPP);
+            aBitmap.Erase(Color(aReplacementColor));
+
+            if (rMarker.IsAlpha())
+                aBitmapEx = BitmapEx(aBitmap, rMarker.GetAlphaMask());
+            else
+                aBitmapEx = BitmapEx(aBitmap);
+        }
+
+        maBColorModifierStack.pop();
+    }
+
     // access or create cairo bitmap data
-    const BitmapEx& rBitmapEx(rMarkerArrayCandidate.getMarker());
     std::shared_ptr<CairoSurfaceHelper> aCairoSurfaceHelper(
-        getOrCreateCairoSurfaceHelper(rBitmapEx));
+        getOrCreateCairoSurfaceHelper(aBitmapEx));
     if (!aCairoSurfaceHelper)
     {
         SAL_WARN("drawinglayer", "SDPRCairo: No SurfaceHelper from BitmapEx 
(!)");
@@ -2145,6 +2221,10 @@ void 
CairoPixelProcessor2D::processBackgroundColorPrimitive2D(
         || rBackgroundColorCandidate.getTransparency() >= 1.0)
         return;
 
+    if (maDrawModeFlags & DrawModeFlags::NoFill)
+        // NoFill wanted, done
+        return;
+
     if (!getViewInformation2D().getViewport().isEmpty())
     {
         // we have a Viewport set with limitations, render as needed/defined
@@ -2156,8 +2236,8 @@ void 
CairoPixelProcessor2D::processBackgroundColorPrimitive2D(
 
     // no Viewport set, render surface completely
     cairo_save(mpRT);
-    const basegfx::BColor aFillColor(
-        
maBColorModifierStack.getModifiedColor(rBackgroundColorCandidate.getBColor()));
+    basegfx::BColor 
aFillColor(getFillColor(rBackgroundColorCandidate.getBColor()));
+    aFillColor = maBColorModifierStack.getModifiedColor(aFillColor);
     cairo_set_source_rgba(mpRT, aFillColor.getRed(), aFillColor.getGreen(), 
aFillColor.getBlue(),
                           1.0 - rBackgroundColorCandidate.getTransparency());
     // to also copy alpha part of color, see cairo docu. Will be reset by 
restore below
@@ -2268,7 +2348,8 @@ void 
CairoPixelProcessor2D::processPolygonStrokePrimitive2D(
     cairo_set_line_cap(mpRT, eCairoLineCap);
 
     // determine & set color
-    basegfx::BColor 
aLineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor()));
+    basegfx::BColor aLineColor(getLineColor(rLineAttribute.getColor()));
+    aLineColor = maBColorModifierStack.getModifiedColor(aLineColor);
     if (bRenderDecomposeForCompareInRed)
         aLineColor.setRed(0.5);
     cairo_set_source_rgb(mpRT, aLineColor.getRed(), aLineColor.getGreen(), 
aLineColor.getBlue());
@@ -2365,8 +2446,8 @@ void 
CairoPixelProcessor2D::processLineRectanglePrimitive2D(
     aRange.transform(getViewInformation2D().getObjectToViewTransformation());
     cairo_identity_matrix(mpRT);
 
-    const basegfx::BColor aHairlineColor(
-        
maBColorModifierStack.getModifiedColor(rLineRectanglePrimitive2D.getBColor()));
+    basegfx::BColor 
aHairlineColor(getLineColor(rLineRectanglePrimitive2D.getBColor()));
+    aHairlineColor = maBColorModifierStack.getModifiedColor(aHairlineColor);
     cairo_set_source_rgb(mpRT, aHairlineColor.getRed(), 
aHairlineColor.getGreen(),
                          aHairlineColor.getBlue());
 
@@ -2391,6 +2472,10 @@ void 
CairoPixelProcessor2D::processFilledRectanglePrimitive2D(
         return;
     }
 
+    if (maDrawModeFlags & DrawModeFlags::NoFill)
+        // NoFill wanted, done
+        return;
+
     cairo_save(mpRT);
 
     // work in view coordinates
@@ -2398,8 +2483,8 @@ void 
CairoPixelProcessor2D::processFilledRectanglePrimitive2D(
     aRange.transform(getViewInformation2D().getObjectToViewTransformation());
     cairo_identity_matrix(mpRT);
 
-    const basegfx::BColor aFillColor(
-        
maBColorModifierStack.getModifiedColor(rFilledRectanglePrimitive2D.getBColor()));
+    basegfx::BColor 
aFillColor(getFillColor(rFilledRectanglePrimitive2D.getBColor()));
+    aFillColor = maBColorModifierStack.getModifiedColor(aFillColor);
     cairo_set_source_rgb(mpRT, aFillColor.getRed(), aFillColor.getGreen(), 
aFillColor.getBlue());
 
     cairo_rectangle(mpRT, aRange.getMinX(), aRange.getMinY(), 
aRange.getWidth(),
@@ -2414,8 +2499,8 @@ void CairoPixelProcessor2D::processSingleLinePrimitive2D(
 {
     cairo_save(mpRT);
 
-    const basegfx::BColor aLineColor(
-        
maBColorModifierStack.getModifiedColor(rSingleLinePrimitive2D.getBColor()));
+    basegfx::BColor 
aLineColor(getLineColor(rSingleLinePrimitive2D.getBColor()));
+    aLineColor = maBColorModifierStack.getModifiedColor(aLineColor);
     cairo_set_source_rgb(mpRT, aLineColor.getRed(), aLineColor.getGreen(), 
aLineColor.getBlue());
 
     const double fAAOffset(getViewInformation2D().getUseAntiAliasing() ? 0.5 : 
0.0);
@@ -2460,38 +2545,70 @@ void 
CairoPixelProcessor2D::processFillGraphicPrimitive2D(
     if (aPreparedBitmap.IsEmpty())
     {
         // output needed and Bitmap data empty, so no bitmap data based
-        // tiled rendering is suggested. Use fallback for paint (decomposition)
+        // tiled rendering is suggested. Use fallback for paint
+        // and decomposition
         process(rFillGraphicPrimitive2D);
         return;
     }
 
-    // render tiled using the prepared Bitmap data
-    if (maBColorModifierStack.count())
+    constexpr DrawModeFlags BITMAP(DrawModeFlags::BlackBitmap | 
DrawModeFlags::WhiteBitmap
+                                   | DrawModeFlags::GrayBitmap);
+    basegfx::BColor aReplacementColor(0, 0, 0);
+    bool bTemporaryGrayColorModifier(false);
+    if (maDrawModeFlags & BITMAP)
     {
-        // need to apply ColorModifier to Bitmap data
+        if (maDrawModeFlags & DrawModeFlags::BlackBitmap)
+        {
+            // aReplacementColor already set
+            aPreparedBitmap.SetEmpty();
+        }
+        else if (maDrawModeFlags & DrawModeFlags::WhiteBitmap)
+        {
+            aReplacementColor = basegfx::BColor(1, 1, 1);
+            aPreparedBitmap.SetEmpty();
+        }
+        else // DrawModeFlags::GrayBitmap
+        {
+            bTemporaryGrayColorModifier = true;
+            const basegfx::BColorModifierSharedPtr aBColorModifier(
+                std::make_shared<basegfx::BColorModifier_gray>());
+            maBColorModifierStack.push(aBColorModifier);
+        }
+    }
+
+    if (!aPreparedBitmap.IsEmpty() && maBColorModifierStack.count())
+    {
+        // apply ColorModifier to Bitmap data
         aPreparedBitmap = 
aPreparedBitmap.ModifyBitmapEx(maBColorModifierStack);
 
         if (aPreparedBitmap.IsEmpty())
         {
-            // color gets completely replaced, get it (any input works)
-            const basegfx::BColor aModifiedColor(
-                maBColorModifierStack.getModifiedColor(basegfx::BColor()));
+            // color gets completely replaced, get it
+            aReplacementColor = 
maBColorModifierStack.getModifiedColor(basegfx::BColor());
+        }
 
-            // 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());
+        if (bTemporaryGrayColorModifier)
+            // cleanup temporary BColorModifier
+            maBColorModifierStack.pop();
+    }
 
-            // 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());
+    // if PreparedBitmap is empty, draw geometry in single color using
+    // prepared ReplacementColor
+    if (aPreparedBitmap.IsEmpty())
+    {
+        // 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());
 
-            // draw directly
-            paintPolyPolygonRGBA(basegfx::B2DPolyPolygon(aPolygon), 
aModifiedColor,
-                                 rFillGraphicPrimitive2D.getTransparency());
+        // 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());
 
-            return;
-        }
+        // draw directly, done
+        paintPolyPolygonRGBA(basegfx::B2DPolyPolygon(aPolygon), 
aReplacementColor,
+                             rFillGraphicPrimitive2D.getTransparency());
+        return;
     }
 
     // access or create cairo bitmap data
@@ -2584,12 +2701,13 @@ void 
CairoPixelProcessor2D::processFillGraphicPrimitive2D(
 void CairoPixelProcessor2D::processFillGradientPrimitive2D_drawOutputRange(
     const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
 {
+    // prepare outer color
+    basegfx::BColor 
aOuterColor(getGradientColor(rFillGradientPrimitive2D.getOuterColor()));
+    aOuterColor = maBColorModifierStack.getModifiedColor(aOuterColor);
+
     cairo_save(mpRT);
 
     // fill simple rect with outer color
-    const basegfx::BColor aColor(
-        
maBColorModifierStack.getModifiedColor(rFillGradientPrimitive2D.getOuterColor()));
-
     if (rFillGradientPrimitive2D.hasAlphaGradient())
     {
         const attribute::FillGradientAttribute& rAlphaGradient(
@@ -2604,12 +2722,13 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D_drawOutputRange(
                 fLuminance = 
rAlphaGradient.getColorStops().front().getStopColor().luminance();
         }
 
-        cairo_set_source_rgba(mpRT, aColor.getRed(), aColor.getGreen(), 
aColor.getBlue(),
-                              1.0 - fLuminance);
+        cairo_set_source_rgba(mpRT, aOuterColor.getRed(), 
aOuterColor.getGreen(),
+                              aOuterColor.getBlue(), 1.0 - fLuminance);
     }
     else
     {
-        cairo_set_source_rgb(mpRT, aColor.getRed(), aColor.getGreen(), 
aColor.getBlue());
+        cairo_set_source_rgb(mpRT, aOuterColor.getRed(), 
aOuterColor.getGreen(),
+                             aOuterColor.getBlue());
     }
 
     const basegfx::B2DHomMatrix 
aTrans(getViewInformation2D().getObjectToViewTransformation());
@@ -3291,6 +3410,24 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D(
         return;
     }
 
+    constexpr DrawModeFlags SIMPLE_GRADIENT(DrawModeFlags::BlackGradient
+                                            | DrawModeFlags::WhiteGradient
+                                            | DrawModeFlags::SettingsGradient);
+    if (maDrawModeFlags & SIMPLE_GRADIENT)
+    {
+        // use simple, single-color OutputRange draw
+        
processFillGradientPrimitive2D_drawOutputRange(rFillGradientPrimitive2D);
+        return;
+    }
+
+    const bool bTemporaryGrayColorModifier(maDrawModeFlags & 
DrawModeFlags::GrayGradient);
+    if (bTemporaryGrayColorModifier)
+    {
+        const basegfx::BColorModifierSharedPtr aBColorModifier(
+            std::make_shared<basegfx::BColorModifier_gray>());
+        maBColorModifierStack.push(aBColorModifier);
+    }
+
     // evtl. prefer fallback: cairo does *not* render hard color transitions
     // in gradients anti-aliased which is most visible in 'step'ed gradients,
     // but may also happen in normal ones -> may need to be checked in
@@ -3306,79 +3443,92 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D(
     if (bPreferAntiAliasedHardColorTransitions && rFillGradient.getSteps())
     {
         
processFillGradientPrimitive2D_fallback_decompose(rFillGradientPrimitive2D);
-        return;
     }
-
-    switch (rFillGradient.getStyle())
+    else
     {
-        case css::awt::GradientStyle_LINEAR:
-        case css::awt::GradientStyle_AXIAL:
-        {
-            // use specialized renderer for this cases - linear, axial
-            
processFillGradientPrimitive2D_linear_axial(rFillGradientPrimitive2D);
-            return;
-        }
-        case css::awt::GradientStyle_RADIAL:
-        case css::awt::GradientStyle_ELLIPTICAL:
-        {
-            // use specialized renderer for this cases - radial, elliptical
-
-            //  NOTE for css::awt::GradientStyle_ELLIPTICAL:
-            // The first time ever I will accept slight deviations for the
-            // elliptical case here due to it's old chaotic move-two-pixels 
inside
-            // rendering method that cannot be patched into a 
lineartransformation
-            // and is hard/difficult to support in more modern systems. 
Differences
-            // are small and mostly would be visible *if* in steps-mode what is
-            // also rare. IF that should make problems reactivation of that 
case
-            // for the default case below is possible. main reason is that 
speed
-            // for direct rendering in cairo is much better.
-            
processFillGradientPrimitive2D_radial_elliptical(rFillGradientPrimitive2D);
-            return;
-        }
-        case css::awt::GradientStyle_SQUARE:
-        case css::awt::GradientStyle_RECT:
-        {
-            // use specialized renderer for this cases - square, rect
-            // NOTE: *NO* support for FillGradientAlpha here. it is anyways
-            // hard to map these to direct rendering, but to do so the four
-            // trapezoids/sides are 'stitched' together, so painting RGBA
-            // directly will make the overlaps look bad and like errors.
-            // Anyways, these gradient types are only our internal heritage
-            // and rendering them directly is already much faster, will be 
okay.
-            
processFillGradientPrimitive2D_square_rect(rFillGradientPrimitive2D);
-            return;
-        }
-        default:
+        switch (rFillGradient.getStyle())
         {
-            // NOTE: All cases are covered above, but keep this as fallback,
-            // so it is possible anytime to exclude one of the cases above 
again
-            // and go back to decomposed version - just in case...
-            
processFillGradientPrimitive2D_fallback_decompose(rFillGradientPrimitive2D);
-            break;
+            case css::awt::GradientStyle_LINEAR:
+            case css::awt::GradientStyle_AXIAL:
+            {
+                // use specialized renderer for this cases - linear, axial
+                
processFillGradientPrimitive2D_linear_axial(rFillGradientPrimitive2D);
+                break;
+            }
+            case css::awt::GradientStyle_RADIAL:
+            case css::awt::GradientStyle_ELLIPTICAL:
+            {
+                // use specialized renderer for this cases - radial, elliptical
+
+                //  NOTE for css::awt::GradientStyle_ELLIPTICAL:
+                // The first time ever I will accept slight deviations for the
+                // elliptical case here due to it's old chaotic 
move-two-pixels inside
+                // rendering method that cannot be patched into a 
lineartransformation
+                // and is hard/difficult to support in more modern systems. 
Differences
+                // are small and mostly would be visible *if* in steps-mode 
what is
+                // also rare. IF that should make problems reactivation of 
that case
+                // for the default case below is possible. main reason is that 
speed
+                // for direct rendering in cairo is much better.
+                
processFillGradientPrimitive2D_radial_elliptical(rFillGradientPrimitive2D);
+                break;
+            }
+            case css::awt::GradientStyle_SQUARE:
+            case css::awt::GradientStyle_RECT:
+            {
+                // use specialized renderer for this cases - square, rect
+                // NOTE: *NO* support for FillGradientAlpha here. it is anyways
+                // hard to map these to direct rendering, but to do so the four
+                // trapezoids/sides are 'stitched' together, so painting RGBA
+                // directly will make the overlaps look bad and like errors.
+                // Anyways, these gradient types are only our internal heritage
+                // and rendering them directly is already much faster, will be 
okay.
+                
processFillGradientPrimitive2D_square_rect(rFillGradientPrimitive2D);
+                break;
+            }
+            default:
+            {
+                // NOTE: All cases are covered above, but keep this as 
fallback,
+                // so it is possible anytime to exclude one of the cases above 
again
+                // and go back to decomposed version - just in case...
+                
processFillGradientPrimitive2D_fallback_decompose(rFillGradientPrimitive2D);
+                break;
+            }
         }
     }
+
+    if (bTemporaryGrayColorModifier)
+        // cleanup temporary BColorModifier
+        maBColorModifierStack.pop();
 }
 
 void CairoPixelProcessor2D::processPolyPolygonRGBAPrimitive2D(
     const primitive2d::PolyPolygonRGBAPrimitive2D& rPolyPolygonRGBAPrimitive2D)
 {
+    if (maDrawModeFlags & DrawModeFlags::NoFill)
+        // NoFill wanted, done
+        return;
+
+    const basegfx::BColor 
aFillColor(getFillColor(rPolyPolygonRGBAPrimitive2D.getBColor()));
+
     if (!rPolyPolygonRGBAPrimitive2D.hasTransparency())
     {
         // do what CairoPixelProcessor2D::processPolyPolygonColorPrimitive2D 
does
-        paintPolyPolygonRGBA(rPolyPolygonRGBAPrimitive2D.getB2DPolyPolygon(),
-                             rPolyPolygonRGBAPrimitive2D.getBColor());
+        paintPolyPolygonRGBA(rPolyPolygonRGBAPrimitive2D.getB2DPolyPolygon(), 
aFillColor);
         return;
     }
 
     // draw with alpha directly
-    paintPolyPolygonRGBA(rPolyPolygonRGBAPrimitive2D.getB2DPolyPolygon(),
-                         rPolyPolygonRGBAPrimitive2D.getBColor(),
+    paintPolyPolygonRGBA(rPolyPolygonRGBAPrimitive2D.getB2DPolyPolygon(), 
aFillColor,
                          rPolyPolygonRGBAPrimitive2D.getTransparency());
 }
 
 void CairoPixelProcessor2D::processPolyPolygonAlphaGradientPrimitive2D(
     const primitive2d::PolyPolygonAlphaGradientPrimitive2D& 
rPolyPolygonAlphaGradientPrimitive2D)
 {
+    if (maDrawModeFlags & DrawModeFlags::NoFill)
+        // NoFill wanted, done
+        return;
+
     const basegfx::B2DPolyPolygon& rPolyPolygon(
         rPolyPolygonAlphaGradientPrimitive2D.getB2DPolyPolygon());
     if (0 == rPolyPolygon.count())
@@ -3387,14 +3537,16 @@ void 
CairoPixelProcessor2D::processPolyPolygonAlphaGradientPrimitive2D(
         return;
     }
 
-    const basegfx::BColor& 
rColor(rPolyPolygonAlphaGradientPrimitive2D.getBColor());
+    basegfx::BColor 
aFillColor(getFillColor(rPolyPolygonAlphaGradientPrimitive2D.getBColor()));
+    aFillColor = maBColorModifierStack.getModifiedColor(aFillColor);
+
     const attribute::FillGradientAttribute& rAlphaGradient(
         rPolyPolygonAlphaGradientPrimitive2D.getAlphaGradient());
     if (rAlphaGradient.isDefault())
     {
         // default is a single ColorStop at 0.0 with black (0, 0, 0). The
         // luminance is then 0.0, too -> not transparent at all
-        paintPolyPolygonRGBA(rPolyPolygon, rColor);
+        paintPolyPolygonRGBA(rPolyPolygon, aFillColor);
         return;
     }
 
@@ -3403,7 +3555,7 @@ void 
CairoPixelProcessor2D::processPolyPolygonAlphaGradientPrimitive2D(
     if (rAlphaStops.isSingleColor(aSingleColor))
     {
         // draw with alpha directly
-        paintPolyPolygonRGBA(rPolyPolygon, rColor, aSingleColor.luminance());
+        paintPolyPolygonRGBA(rPolyPolygon, aFillColor, 
aSingleColor.luminance());
         return;
     }
 
@@ -3426,7 +3578,7 @@ void 
CairoPixelProcessor2D::processPolyPolygonAlphaGradientPrimitive2D(
     // create ColorStops at same stops but single color
     aColorStops.reserve(rAlphaStops.size());
     for (const auto& entry : rAlphaStops)
-        aColorStops.emplace_back(entry.getStopOffset(), rColor);
+        aColorStops.emplace_back(entry.getStopOffset(), aFillColor);
 
     // create FillGradient using that single-color ColorStops
     const attribute::FillGradientAttribute aFillGradient(
@@ -3453,17 +3605,48 @@ void 
CairoPixelProcessor2D::processPolyPolygonAlphaGradientPrimitive2D(
 void CairoPixelProcessor2D::processBitmapAlphaPrimitive2D(
     const primitive2d::BitmapAlphaPrimitive2D& rBitmapAlphaPrimitive2D)
 {
+    constexpr DrawModeFlags BITMAP(DrawModeFlags::BlackBitmap | 
DrawModeFlags::WhiteBitmap
+                                   | DrawModeFlags::GrayBitmap);
+    const bool bDrawModeFlagsUsed(maDrawModeFlags & BITMAP);
+
+    if (bDrawModeFlagsUsed)
+    {
+        if (maDrawModeFlags & DrawModeFlags::BlackBitmap)
+        {
+            const basegfx::BColorModifierSharedPtr aBColorModifier(
+                
std::make_shared<basegfx::BColorModifier_replace>(basegfx::BColor(0, 0, 0)));
+            maBColorModifierStack.push(aBColorModifier);
+        }
+        else if (maDrawModeFlags & DrawModeFlags::WhiteBitmap)
+        {
+            const basegfx::BColorModifierSharedPtr aBColorModifier(
+                
std::make_shared<basegfx::BColorModifier_replace>(basegfx::BColor(1, 1, 1)));
+            maBColorModifierStack.push(aBColorModifier);
+        }
+        else // DrawModeFlags::GrayBitmap
+        {
+            const basegfx::BColorModifierSharedPtr aBColorModifier(
+                std::make_shared<basegfx::BColorModifier_gray>());
+            maBColorModifierStack.push(aBColorModifier);
+        }
+    }
+
     if (!rBitmapAlphaPrimitive2D.hasTransparency())
     {
         // do what CairoPixelProcessor2D::processPolyPolygonColorPrimitive2D 
does
         paintBitmapAlpha(rBitmapAlphaPrimitive2D.getBitmap(),
                          rBitmapAlphaPrimitive2D.getTransform());
-        return;
+    }
+    else
+    {
+        // draw with alpha directly
+        paintBitmapAlpha(rBitmapAlphaPrimitive2D.getBitmap(),
+                         rBitmapAlphaPrimitive2D.getTransform(),
+                         rBitmapAlphaPrimitive2D.getTransparency());
     }
 
-    // draw with alpha directly
-    paintBitmapAlpha(rBitmapAlphaPrimitive2D.getBitmap(), 
rBitmapAlphaPrimitive2D.getTransform(),
-                     rBitmapAlphaPrimitive2D.getTransparency());
+    if (bDrawModeFlagsUsed)
+        maBColorModifierStack.pop();
 }
 
 void CairoPixelProcessor2D::processTextSimplePortionPrimitive2D(
@@ -3509,8 +3692,8 @@ void CairoPixelProcessor2D::renderTextBackground(
     cairo_matrix_init(&aMatrix, rTransform.a(), rTransform.b(), 
rTransform.c(), rTransform.d(),
                       rTransform.e(), rTransform.f());
     cairo_set_matrix(mpRT, &aMatrix);
-    const basegfx::BColor aFillColor(
-        
maBColorModifierStack.getModifiedColor(rTextCandidate.getTextFillColor().getBColor()));
+    basegfx::BColor 
aFillColor(getFillColor(rTextCandidate.getTextFillColor().getBColor()));
+    aFillColor = maBColorModifierStack.getModifiedColor(aFillColor);
     cairo_set_source_rgb(mpRT, aFillColor.getRed(), aFillColor.getGreen(), 
aFillColor.getBlue());
     cairo_rectangle(mpRT, 0.0, -fAscent, fTextWidth, fAscent + fDescent);
     cairo_fill(mpRT);
@@ -3618,6 +3801,9 @@ void 
CairoPixelProcessor2D::renderTextSimpleOrDecoratedPortionPrimitive2D(
                              pSalLayout->GetTextWidth());
     }
 
+    // get TextColor early, may have to be modified
+    basegfx::BColor aTextColor(getTextColor(rTextCandidate.getFontColor()));
+
     if (rTextCandidate.hasShadow())
     {
         // Text shadow is constant, relative to font size, *not* rotated with
@@ -3628,8 +3814,7 @@ void 
CairoPixelProcessor2D::renderTextSimpleOrDecoratedPortionPrimitive2D(
         // see ::ImplDrawSpecialText -> no longer simple fixed color
         const basegfx::BColor aBlack(0.0, 0.0, 0.0);
         basegfx::BColor aShadowColor(aBlack);
-        if (aBlack == rTextCandidate.getFontColor()
-            || rTextCandidate.getFontColor().luminance() < (8.0 / 255.0))
+        if (aBlack == aTextColor || aTextColor.luminance() < (8.0 / 255.0))
             aShadowColor = COL_LIGHTGRAY.getBColor();
         aShadowColor = maBColorModifierStack.getModifiedColor(aShadowColor);
 
@@ -3656,9 +3841,6 @@ void 
CairoPixelProcessor2D::renderTextSimpleOrDecoratedPortionPrimitive2D(
                                                               &aTransform, 
&aShadowColor);
         }
     }
-    // get TextColor early, may have to be modified
-    basegfx::BColor aTextColor(rTextCandidate.getFontColor());
-
     if (rTextCandidate.hasOutline())
     {
         // render as outline
@@ -3700,7 +3882,7 @@ void 
CairoPixelProcessor2D::renderTextSimpleOrDecoratedPortionPrimitive2D(
                             getViewInformation2D().getUseAntiAliasing());
             if (rTextCandidate.hasTextDecoration())
             {
-                const basegfx::B2DHomMatrix aTransform(
+                basegfx::B2DHomMatrix aTransform(
                     aInvViewTransform * aDiscreteOffset
                     * getViewInformation2D().getObjectToViewTransformation());
                 
renderTextDecorationWithOptionalTransformAndColor(*pDecoratedCandidate, 
aDecTrans,
@@ -3799,14 +3981,30 @@ bool CairoPixelProcessor2D::handleSvgGradientHelper(
         return true;
     }
 
-    if (rCandidate.getSingleEntry())
+    basegfx::BColor aSimpleColor;
+    bool bDrawSimple(false);
+    primitive2d::SvgGradientEntryVector::const_reference aEntry(
+        rCandidate.getGradientEntries().back());
+
+    constexpr DrawModeFlags SIMPLE_GRADIENT(DrawModeFlags::BlackGradient
+                                            | DrawModeFlags::WhiteGradient
+                                            | DrawModeFlags::SettingsGradient);
+    if (maDrawModeFlags & SIMPLE_GRADIENT)
+    {
+        aSimpleColor = getGradientColor(aSimpleColor);
+        bDrawSimple = true;
+    }
+
+    if (!bDrawSimple && rCandidate.getSingleEntry())
     {
         // only one color entry, fill with last existing color, done
-        primitive2d::SvgGradientEntryVector::const_reference aEntry(
-            rCandidate.getGradientEntries().back());
-        paintPolyPolygonRGBA(rCandidate.getPolyPolygon(), aEntry.getColor(),
-                             1.0 - aEntry.getOpacity());
+        aSimpleColor = aEntry.getColor();
+        bDrawSimple = true;
+    }
 
+    if (bDrawSimple)
+    {
+        paintPolyPolygonRGBA(rCandidate.getPolyPolygon(), aSimpleColor, 1.0 - 
aEntry.getOpacity());
         return true;
     }
 
@@ -3825,6 +4023,14 @@ void 
CairoPixelProcessor2D::processSvgLinearGradientPrimitive2D(
 
     cairo_save(mpRT);
 
+    const bool bTemporaryGrayColorModifier(maDrawModeFlags & 
DrawModeFlags::GrayGradient);
+    if (bTemporaryGrayColorModifier)
+    {
+        const basegfx::BColorModifierSharedPtr aBColorModifier(
+            std::make_shared<basegfx::BColorModifier_gray>());
+        maBColorModifierStack.push(aBColorModifier);
+    }
+
     // set ObjectToView as regular transformation at CairoContext
     const basegfx::B2DHomMatrix 
aTrans(getViewInformation2D().getObjectToViewTransformation());
     cairo_matrix_t aMatrix;
@@ -3885,6 +4091,10 @@ void 
CairoPixelProcessor2D::processSvgLinearGradientPrimitive2D(
     // cleanup
     cairo_pattern_destroy(pPattern);
     cairo_restore(mpRT);
+
+    if (bTemporaryGrayColorModifier)
+        // cleanup temporary BColorModifier
+        maBColorModifierStack.pop();
 }
 
 void CairoPixelProcessor2D::processSvgRadialGradientPrimitive2D(
@@ -3899,6 +4109,15 @@ void 
CairoPixelProcessor2D::processSvgRadialGradientPrimitive2D(
 
     cairo_save(mpRT);
 
+    bool bTemporaryGrayColorModifier(false);
+    if (maDrawModeFlags & DrawModeFlags::GrayGradient)
+    {
+        bTemporaryGrayColorModifier = true;
+        const basegfx::BColorModifierSharedPtr aBColorModifier(
+            std::make_shared<basegfx::BColorModifier_gray>());
+        maBColorModifierStack.push(aBColorModifier);
+    }
+
     // set ObjectToView as regular transformation at CairoContext
     const basegfx::B2DHomMatrix 
aTrans(getViewInformation2D().getObjectToViewTransformation());
     cairo_matrix_t aMatrix;
@@ -3980,6 +4199,10 @@ void 
CairoPixelProcessor2D::processSvgRadialGradientPrimitive2D(
     // cleanup
     cairo_pattern_destroy(pPattern);
     cairo_restore(mpRT);
+
+    if (bTemporaryGrayColorModifier)
+        // cleanup temporary BColorModifier
+        maBColorModifierStack.pop();
 }
 
 void CairoPixelProcessor2D::processControlPrimitive2D(
@@ -4089,6 +4312,111 @@ void 
CairoPixelProcessor2D::evaluateCairoCoordinateLimitWorkaround()
     }
 }
 
+basegfx::BColor CairoPixelProcessor2D::getLineColor(const basegfx::BColor& 
rColor) const
+{
+    constexpr DrawModeFlags LINE(DrawModeFlags::BlackLine | 
DrawModeFlags::WhiteLine
+                                 | DrawModeFlags::GrayLine | 
DrawModeFlags::SettingsLine);
+    if (!(maDrawModeFlags & LINE))
+        return rColor;
+
+    if (maDrawModeFlags & DrawModeFlags::BlackLine)
+        return basegfx::BColor(0, 0, 0);
+
+    if (maDrawModeFlags & DrawModeFlags::WhiteLine)
+        return basegfx::BColor(1, 1, 1);
+
+    if (maDrawModeFlags & DrawModeFlags::GrayLine)
+    {
+        const double fLuminance(rColor.luminance());
+        return basegfx::BColor(fLuminance, fLuminance, fLuminance);
+    }
+
+    // DrawModeFlags::SettingsLine
+    if (maDrawModeFlags & DrawModeFlags::SettingsForSelection)
+        return 
Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
+
+    return 
Application::GetSettings().GetStyleSettings().GetWindowTextColor().getBColor();
+}
+
+basegfx::BColor CairoPixelProcessor2D::getFillColor(const basegfx::BColor& 
rColor) const
+{
+    constexpr DrawModeFlags FILL(DrawModeFlags::BlackFill | 
DrawModeFlags::WhiteFill
+                                 | DrawModeFlags::GrayFill | 
DrawModeFlags::SettingsFill);
+    if (!(maDrawModeFlags & FILL))
+        return rColor;
+
+    if (maDrawModeFlags & DrawModeFlags::BlackFill)
+        return basegfx::BColor(0, 0, 0);
+
+    if (maDrawModeFlags & DrawModeFlags::WhiteFill)
+        return basegfx::BColor(1, 1, 1);
+
+    if (maDrawModeFlags & DrawModeFlags::GrayFill)
+    {
+        const double fLuminance(rColor.luminance());
+        return basegfx::BColor(fLuminance, fLuminance, fLuminance);
+    }
+
+    // DrawModeFlags::SettingsFill
+    if (maDrawModeFlags & DrawModeFlags::SettingsForSelection)
+        return 
Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
+
+    return 
Application::GetSettings().GetStyleSettings().GetWindowColor().getBColor();
+}
+
+basegfx::BColor CairoPixelProcessor2D::getTextColor(const basegfx::BColor& 
rColor) const
+{
+    constexpr DrawModeFlags TEXT(DrawModeFlags::BlackText | 
DrawModeFlags::WhiteText
+                                 | DrawModeFlags::GrayText | 
DrawModeFlags::SettingsText);
+    if (!(maDrawModeFlags & TEXT))
+        return rColor;
+
+    if (maDrawModeFlags & DrawModeFlags::BlackText)
+        return basegfx::BColor(0, 0, 0);
+
+    if (maDrawModeFlags & DrawModeFlags::WhiteText)
+        return basegfx::BColor(1, 1, 1);
+
+    if (maDrawModeFlags & DrawModeFlags::GrayText)
+    {
+        const double fLuminance(rColor.luminance());
+        return basegfx::BColor(fLuminance, fLuminance, fLuminance);
+    }
+
+    // DrawModeFlags::SettingsText
+    if (maDrawModeFlags & DrawModeFlags::SettingsForSelection)
+        return 
Application::GetSettings().GetStyleSettings().GetHighlightTextColor().getBColor();
+
+    return 
Application::GetSettings().GetStyleSettings().GetWindowTextColor().getBColor();
+}
+
+basegfx::BColor CairoPixelProcessor2D::getGradientColor(const basegfx::BColor& 
rColor) const
+{
+    constexpr DrawModeFlags GRADIENT(DrawModeFlags::BlackGradient | 
DrawModeFlags::GrayGradient
+                                     | DrawModeFlags::WhiteGradient
+                                     | DrawModeFlags::SettingsGradient);
+    if (!(maDrawModeFlags & GRADIENT))
+        return rColor;
+
+    if (maDrawModeFlags & DrawModeFlags::BlackGradient)
+        return basegfx::BColor(0, 0, 0);
+
+    if (maDrawModeFlags & DrawModeFlags::WhiteGradient)
+        return basegfx::BColor(1, 1, 1);
+
+    if (maDrawModeFlags & DrawModeFlags::GrayGradient)
+    {
+        const double fLuminance(rColor.luminance());
+        return basegfx::BColor(fLuminance, fLuminance, fLuminance);
+    }
+
+    // DrawModeFlags::SettingsGradient
+    if (maDrawModeFlags & DrawModeFlags::SettingsForSelection)
+        return 
Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
+
+    return 
Application::GetSettings().GetStyleSettings().GetWindowColor().getBColor();
+}
+
 void CairoPixelProcessor2D::processBasePrimitive2D(const 
primitive2d::BasePrimitive2D& rCandidate)
 {
     const cairo_status_t aStart(cairo_status(mpRT));
diff --git a/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx 
b/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx
index e97b1042a8d0..325cbe8f7fcd 100644
--- a/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx
+++ b/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx
@@ -14,6 +14,7 @@
 #include <tools/long.hxx>
 #include <sal/config.h>
 #include <vcl/vclptr.hxx>
+#include <vcl/rendercontext/DrawModeFlags.hxx>
 
 // cairo-specific
 #include <cairo.h>
@@ -91,6 +92,10 @@ class UNLESS_MERGELIBS(DRAWINGLAYER_DLLPUBLIC) 
CairoPixelProcessor2D final : pub
     // see comment there
     sal_uInt16 mnClipRecursionCount;
 
+    // DrawModeFlags from OutputDevice: These do modify how stuff
+    // needs to be colored/painted, context-dependent
+    DrawModeFlags maDrawModeFlags;
+
     // calculated result of if we are in outsideCairoCoordinateLimits mode
     bool mbCairoCoordinateLimitWorkaroundActive;
 
@@ -190,6 +195,11 @@ class UNLESS_MERGELIBS(DRAWINGLAYER_DLLPUBLIC) 
CairoPixelProcessor2D final : pub
     // check if CairoCoordinateLimitWorkaround is needed
     void evaluateCairoCoordinateLimitWorkaround();
 
+    basegfx::BColor getLineColor(const basegfx::BColor& rColor) const;
+    basegfx::BColor getFillColor(const basegfx::BColor& rColor) const;
+    basegfx::BColor getTextColor(const basegfx::BColor& rColor) const;
+    basegfx::BColor getGradientColor(const basegfx::BColor& rColor) const;
+
 protected:
     bool hasError() const { return cairo_status(mpRT) != CAIRO_STATUS_SUCCESS; 
}
     bool hasRenderTarget() const { return nullptr != mpRT; }
@@ -203,6 +213,11 @@ protected:
     // be owned and not destroyed, but be used as render
     // target. You should check the result using valid()
     CairoPixelProcessor2D(
+        // take over current BColorModifierStack
+        const basegfx::BColorModifierStack& rBColorModifierStack,
+
+        // take over current DrawModeFlags
+        const DrawModeFlags& rDrawModeFlags,
 
         // the ViewInformation
         const geometry::ViewInformation2D& rViewInformation,
diff --git a/svx/source/sdr/overlay/overlaymanager.cxx 
b/svx/source/sdr/overlay/overlaymanager.cxx
index de70e8e138eb..8b6d40006416 100644
--- a/svx/source/sdr/overlay/overlaymanager.cxx
+++ b/svx/source/sdr/overlay/overlaymanager.cxx
@@ -49,10 +49,8 @@ namespace sdr::overlay
             // taken from the system High Contrast settings
             const DrawModeFlags 
nOriginalDrawMode(rDestinationDevice.GetDrawMode());
 
-            // create processor
-            std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> 
pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
-                rDestinationDevice,
-                getCurrentViewInformation2D()));
+            // prepare ViewInformation2D
+            drawinglayer::geometry::ViewInformation2D 
aViewInformation2D(getCurrentViewInformation2D());
 
             for(const auto& rpOverlayObject : maOverlayObjects)
             {
@@ -67,24 +65,28 @@ namespace sdr::overlay
                     {
                         if(rRange.overlaps(rCandidate.getBaseRange()))
                         {
-                            const bool 
bCurrentAA(pProcessor->getViewInformation2D().getUseAntiAliasing());
+                            const bool 
bCurrentAA(aViewInformation2D.getUseAntiAliasing());
                             const bool 
bWantedAA(rCandidate.allowsAntiAliase());
 
                             if (bCurrentAA != bWantedAA)
                             {
                                 // set AntiAliasing at Processor2D
-                                drawinglayer::geometry::ViewInformation2D 
aViewInformation2D(pProcessor->getViewInformation2D());
                                 
aViewInformation2D.setUseAntiAliasing(bWantedAA);
-                                
pProcessor->setViewInformation2D(aViewInformation2D);
                             }
 
-                            const bool bIsHighContrastSelection = 
rCandidate.isHighContrastSelection();
+                            const bool 
bIsHighContrastSelection(rCandidate.isHighContrastSelection());
                             if (bIsHighContrastSelection)
                             {
                                 // overrule DrawMode settings
                                 
rDestinationDevice.SetDrawMode(nOriginalDrawMode | 
DrawModeFlags::SettingsForSelection);
                             }
 
+                            // create processor
+                            
std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> 
pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice(
+                                rDestinationDevice,
+                                aViewInformation2D));
+
+                            // render primitive
                             pProcessor->process(aSequence);
 
                             if (bIsHighContrastSelection)
@@ -96,9 +98,6 @@ namespace sdr::overlay
                     }
                 }
             }
-
-            // destroy Processor2D and restore AA settings
-            pProcessor.reset();
         }
 
         void OverlayManager::ImpStripeDefinitionChanged()

Reply via email to