drawinglayer/source/primitive2d/PolyPolygonGradientPrimitive2D.cxx  |   87 +---
 drawinglayer/source/primitive2d/Tools.cxx                           |    2 
 drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx         |   70 ++-
 drawinglayer/source/processor2d/cairopixelprocessor2d.cxx           |  205 
++++------
 drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx             |    8 
 drawinglayer/source/processor2d/vclpixelprocessor2d.cxx             |    8 
 include/drawinglayer/primitive2d/PolyPolygonGradientPrimitive2D.hxx |   51 --
 include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx  |    3 
 include/drawinglayer/primitive2d/fillgradientprimitive2d.hxx        |   16 
 include/drawinglayer/processor2d/cairopixelprocessor2d.hxx          |   22 -
 svx/source/sdr/primitive2d/sdrdecompositiontools.cxx                |   40 -
 11 files changed, 226 insertions(+), 286 deletions(-)

New commits:
commit aac4974f2a50ebd34137d0384a5e21567c6ae646
Author:     Armin Le Grand (Collabora) <[email protected]>
AuthorDate: Thu Jul 18 14:08:48 2024 +0200
Commit:     Armin Le Grand <[email protected]>
CommitDate: Fri Jul 19 10:46:34 2024 +0200

    CairoSDPR: Direct support for RGBA Gradients (III)
    
    I thought about this functionality again and decided
    to change doing it in a way that will support more
    alpha more directly in existing primitives - that will
    be better for also supporting e.g. PolyPolys with alpha,
    etc. Will need checking of existing usages of e.g.
    FillGradientPrimitive2D, but it's worth it.
    Note that when your primitive processor (usually a
    renderer) does *not* support alpha in gradients
    directly it is now requuired to continue using the
    decomposition (what renderers do automatically when
    calling 'BaseProcessor2D::process' in the default
    case. Checked that for existing processors.
    
    Change-Id: I840c9feb8c98549b790ef16285a309b42c4b1b53
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170687
    Tested-by: Jenkins
    Reviewed-by: Armin Le Grand <[email protected]>

diff --git a/drawinglayer/source/primitive2d/PolyPolygonGradientPrimitive2D.cxx 
b/drawinglayer/source/primitive2d/PolyPolygonGradientPrimitive2D.cxx
index 2e6b83ab526f..de114e2fdf53 100644
--- a/drawinglayer/source/primitive2d/PolyPolygonGradientPrimitive2D.cxx
+++ b/drawinglayer/source/primitive2d/PolyPolygonGradientPrimitive2D.cxx
@@ -39,7 +39,8 @@ Primitive2DReference 
PolyPolygonGradientPrimitive2D::create2DDecomposition(
         // create SubSequence with FillGradientPrimitive2D
         const basegfx::B2DRange 
aPolyPolygonRange(getB2DPolyPolygon().getB2DRange());
         rtl::Reference<FillGradientPrimitive2D> pNewGradient = new 
FillGradientPrimitive2D(
-            aPolyPolygonRange, getDefinitionRange(), getFillGradient());
+            aPolyPolygonRange, getDefinitionRange(), getFillGradient(),
+            hasAlphaGradient() ? &getAlphaGradient() : nullptr);
         Primitive2DContainer aSubSequence{ pNewGradient };
 
         // create mask primitive
@@ -49,87 +50,57 @@ Primitive2DReference 
PolyPolygonGradientPrimitive2D::create2DDecomposition(
 }
 
 PolyPolygonGradientPrimitive2D::PolyPolygonGradientPrimitive2D(
-    const basegfx::B2DPolyPolygon& rPolyPolygon, 
attribute::FillGradientAttribute aFillGradient)
+    const basegfx::B2DPolyPolygon& rPolyPolygon,
+    const attribute::FillGradientAttribute& rFillGradient)
     : maPolyPolygon(rPolyPolygon)
     , maDefinitionRange(rPolyPolygon.getB2DRange())
-    , maFillGradient(std::move(aFillGradient))
+    , maFillGradient(rFillGradient)
+    , maAlphaGradient()
 {
 }
 
 PolyPolygonGradientPrimitive2D::PolyPolygonGradientPrimitive2D(
     basegfx::B2DPolyPolygon aPolyPolygon, const basegfx::B2DRange& 
rDefinitionRange,
-    attribute::FillGradientAttribute aFillGradient)
+    const attribute::FillGradientAttribute& rFillGradient,
+    const attribute::FillGradientAttribute* pAlphaGradient)
     : maPolyPolygon(std::move(aPolyPolygon))
     , maDefinitionRange(rDefinitionRange)
-    , maFillGradient(std::move(aFillGradient))
+    , maFillGradient(rFillGradient)
+    , maAlphaGradient()
 {
+    // copy alpha gradient if we got one
+    if (nullptr != pAlphaGradient)
+        maAlphaGradient = *pAlphaGradient;
 }
 
 bool PolyPolygonGradientPrimitive2D::operator==(const BasePrimitive2D& 
rPrimitive) const
 {
-    if (BufferedDecompositionPrimitive2D::operator==(rPrimitive))
-    {
-        const PolyPolygonGradientPrimitive2D& rCompare
-            = static_cast<const PolyPolygonGradientPrimitive2D&>(rPrimitive);
+    if (!(BufferedDecompositionPrimitive2D::operator==(rPrimitive)))
+        return false;
 
-        return (getB2DPolyPolygon() == rCompare.getB2DPolyPolygon()
-                && getDefinitionRange() == rCompare.getDefinitionRange()
-                && getFillGradient() == rCompare.getFillGradient());
-    }
+    const PolyPolygonGradientPrimitive2D& rCompare(
+        static_cast<const PolyPolygonGradientPrimitive2D&>(rPrimitive));
 
-    return false;
-}
+    if (getB2DPolyPolygon() != rCompare.getB2DPolyPolygon())
+        return false;
 
-// provide unique ID
-sal_uInt32 PolyPolygonGradientPrimitive2D::getPrimitive2DID() const
-{
-    return PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D;
-}
+    if (getDefinitionRange() != rCompare.getDefinitionRange())
+        return false;
 
-Primitive2DReference PolyPolygonRGBAGradientPrimitive2D::create2DDecomposition(
-    const geometry::ViewInformation2D& /*rViewInformation*/) const
-{
-    Primitive2DContainer aContent{ new PolyPolygonGradientPrimitive2D(
-        getB2DPolyPolygon(), getDefinitionRange(), getFillGradient()) };
+    if (getFillGradient() != rCompare.getFillGradient())
+        return false;
 
-    Primitive2DContainer aAlpha{ new FillGradientPrimitive2D(
-        basegfx::utils::getRange(getB2DPolyPolygon()), getDefinitionRange(),
-        getFillGradientAlpha()) };
+    if (maAlphaGradient != rCompare.maAlphaGradient)
+        return false;
 
-    return Primitive2DReference{ new 
TransparencePrimitive2D(std::move(aContent),
-                                                             
std::move(aAlpha)) };
+    return true;
 }
 
-PolyPolygonRGBAGradientPrimitive2D::PolyPolygonRGBAGradientPrimitive2D(
-    basegfx::B2DPolyPolygon aPolyPolygon, const basegfx::B2DRange& 
rDefinitionRange,
-    attribute::FillGradientAttribute aFillGradient,
-    attribute::FillGradientAttribute aFillGradientAlpha)
-    : PolyPolygonGradientPrimitive2D(aPolyPolygon, rDefinitionRange, 
aFillGradient)
-    , maFillGradientAlpha(aFillGradientAlpha)
-{
-    // assert when the definition is not allowed, it HAS to fulfil the
-    // requested preconditions
-    assert(aFillGradient.sameDefinitionThanAlpha(aFillGradientAlpha));
-}
-
-bool PolyPolygonRGBAGradientPrimitive2D::operator==(const BasePrimitive2D& 
rPrimitive) const
-{
-    if (PolyPolygonGradientPrimitive2D::operator==(rPrimitive))
-    {
-        const PolyPolygonRGBAGradientPrimitive2D& rCompare
-            = static_cast<const 
PolyPolygonRGBAGradientPrimitive2D&>(rPrimitive);
-
-        return getFillGradientAlpha() == rCompare.getFillGradientAlpha();
-    }
-
-    return false;
-}
-
-sal_uInt32 PolyPolygonRGBAGradientPrimitive2D::getPrimitive2DID() const
+// provide unique ID
+sal_uInt32 PolyPolygonGradientPrimitive2D::getPrimitive2DID() const
 {
-    return PRIMITIVE2D_ID_POLYPOLYGONRGBAGRADIENTPRIMITIVE2D;
+    return PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D;
 }
-
 } // end drawinglayer::primitive2d namespace
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/Tools.cxx 
b/drawinglayer/source/primitive2d/Tools.cxx
index 631ec63e52c1..cef1829e1567 100644
--- a/drawinglayer/source/primitive2d/Tools.cxx
+++ b/drawinglayer/source/primitive2d/Tools.cxx
@@ -233,8 +233,6 @@ OUString idToString(sal_uInt32 nId)
             return u"SINGLELINEPRIMITIVE"_ustr;
         case PRIMITIVE2D_ID_EXCLUSIVEEDITVIEWPRIMITIVE2D:
             return u"EXCLUSIVEEDITVIEWPRIMITIVE2D"_ustr;
-        case PRIMITIVE2D_ID_POLYPOLYGONRGBAGRADIENTPRIMITIVE2D:
-            return u"POLYPOLYGONRGBAGRADIENTPRIMITIVE2D"_ustr;
         case PRIMITIVE2D_ID_ANIMATEDGRAPHICPRIMITIVE2D:
             return u"ANIMATEDGRAPHICPRIMITIVE2D"_ustr;
         default:
diff --git a/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx 
b/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx
index 255d4fb96a3d..19dfe8482430 100644
--- a/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx
@@ -24,6 +24,7 @@
 #include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
 #include <drawinglayer/primitive2d/groupprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
 #include <utility>
 #include <algorithm>
 
@@ -260,51 +261,86 @@ namespace drawinglayer::primitive2d
 
         Primitive2DReference 
FillGradientPrimitive2D::create2DDecomposition(const 
geometry::ViewInformation2D& /*rViewInformation*/) const
         {
+            // SDPR: support alpha directly now. If a primitive processor
+            // cannot deal with it, use it's decomposition. For that purpose
+            // this decomposition has two stages now: This 1st one will
+            // separate content and alpha into a TransparencePrimitive2D,
+            // so all processors can work as before
+            if (hasAlphaGradient())
+            {
+                Primitive2DContainer aContent{ new FillGradientPrimitive2D(
+                    getOutputRange(),
+                    getDefinitionRange(),
+                    getFillGradient()) };
+
+                Primitive2DContainer aAlpha{ new FillGradientPrimitive2D(
+                    getOutputRange(),
+                    getDefinitionRange(),
+                    getAlphaGradient()) };
+
+                return Primitive2DReference{ new 
TransparencePrimitive2D(std::move(aContent),
+                                                                        
std::move(aAlpha)) };
+            }
+
             // default creates overlapping fill which works with AntiAliasing 
and without.
             // The non-overlapping version does not create single filled 
polygons, but
             // PolyPolygons where each one describes a 'ring' for the gradient 
such
             // that the rings will not overlap. This is useful for the old 
XOR-paint
             // 'trick' of VCL which is recorded in Metafiles; so this version 
may be
             // used from the MetafilePrimitive2D in its decomposition.
-
             if(!getFillGradient().isDefault())
             {
                 return createFill(/*bOverlapping*/true);
             }
+
             return nullptr;
         }
 
         FillGradientPrimitive2D::FillGradientPrimitive2D(
             const basegfx::B2DRange& rOutputRange,
-            attribute::FillGradientAttribute aFillGradient)
-        :   maOutputRange(rOutputRange),
-            maDefinitionRange(rOutputRange),
-            maFillGradient(std::move(aFillGradient))
+            const attribute::FillGradientAttribute& rFillGradient)
+        : maOutputRange(rOutputRange)
+        , maDefinitionRange(rOutputRange)
+        , maFillGradient(rFillGradient)
+        , maAlphaGradient()
         {
         }
 
         FillGradientPrimitive2D::FillGradientPrimitive2D(
             const basegfx::B2DRange& rOutputRange,
             const basegfx::B2DRange& rDefinitionRange,
-            attribute::FillGradientAttribute aFillGradient)
-        :   maOutputRange(rOutputRange),
-            maDefinitionRange(rDefinitionRange),
-            maFillGradient(std::move(aFillGradient))
+            const attribute::FillGradientAttribute& rFillGradient,
+            const attribute::FillGradientAttribute* pAlphaGradient)
+        : maOutputRange(rOutputRange)
+        , maDefinitionRange(rDefinitionRange)
+        , maFillGradient(rFillGradient)
+        , maAlphaGradient()
         {
+            // copy alpha gradient if we got one
+            if (nullptr != pAlphaGradient)
+                maAlphaGradient = *pAlphaGradient;
         }
 
         bool FillGradientPrimitive2D::operator==(const BasePrimitive2D& 
rPrimitive) const
         {
-            if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
-            {
-                const FillGradientPrimitive2D& rCompare = static_cast<const 
FillGradientPrimitive2D&>(rPrimitive);
+            if(!BufferedDecompositionPrimitive2D::operator==(rPrimitive))
+                return false;
 
-                return (getOutputRange() == rCompare.getOutputRange()
-                    && getDefinitionRange() == rCompare.getDefinitionRange()
-                    && getFillGradient() == rCompare.getFillGradient());
-            }
+            const FillGradientPrimitive2D& rCompare(static_cast<const 
FillGradientPrimitive2D&>(rPrimitive));
+
+            if (getOutputRange() != rCompare.getOutputRange())
+                return false;
+
+            if (getDefinitionRange() != rCompare.getDefinitionRange())
+                return false;
+
+            if (getFillGradient() != rCompare.getFillGradient())
+                return false;
+
+            if (maAlphaGradient != rCompare.maAlphaGradient)
+                return false;
 
-            return false;
+            return true;
         }
 
         basegfx::B2DRange FillGradientPrimitive2D::getB2DRange(const 
geometry::ViewInformation2D& /*rViewInformation*/) const
diff --git a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx 
b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
index 034e59dceea4..e49ab17931ab 100644
--- a/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/cairopixelprocessor2d.cxx
@@ -763,7 +763,7 @@ void LuminanceToAlpha(cairo_surface_t* pMask)
         for (sal_uInt32 x(0); x < nWidth; ++x)
         {
             // do not forget that we have pre-multiplied alpha
-            const sal_uInt8 nAlpha(pMaskPixelData[SVP_CAIRO_ALPHA]);
+            sal_uInt8 nAlpha(pMaskPixelData[SVP_CAIRO_ALPHA]);
 
             if (0 != nAlpha)
             {
@@ -772,17 +772,30 @@ void LuminanceToAlpha(cairo_surface_t* pMask)
                                           + pMaskPixelData[SVP_CAIRO_BLUE] * 
nBlueMul;
 
                 if (255 != nAlpha)
-                    pMaskPixelData[SVP_CAIRO_ALPHA] = fLuminance / nAlpha;
+                    nAlpha = fLuminance / nAlpha;
                 else
-                    pMaskPixelData[SVP_CAIRO_ALPHA] = 255.0 * fLuminance;
+                    nAlpha = 255.0 * fLuminance;
             }
 
+            pMaskPixelData[SVP_CAIRO_ALPHA] = 255 - nAlpha;
             pMaskPixelData += 4;
         }
     }
 
     cairo_surface_mark_dirty(pMask);
 }
+
+basegfx::B2DRange getDiscreteViewRange(cairo_t* pRT)
+{
+    double clip_x1, clip_x2, clip_y1, clip_y2;
+    cairo_save(pRT);
+    cairo_identity_matrix(pRT);
+    cairo_clip_extents(pRT, &clip_x1, &clip_y1, &clip_x2, &clip_y2);
+    cairo_restore(pRT);
+
+    return basegfx::B2DRange(basegfx::B2DPoint(clip_x1, clip_y1),
+                             basegfx::B2DPoint(clip_x2, clip_y2));
+}
 }
 
 namespace drawinglayer::processor2d
@@ -1093,11 +1106,7 @@ void 
CairoPixelProcessor2D::processTransparencePrimitive2D(
         rTransCandidate.getChildren().getB2DRange(getViewInformation2D()));
     
aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
     basegfx::B2DRange aVisibleRange(aDiscreteRange);
-    double clip_x1, clip_x2, clip_y1, clip_y2;
-    cairo_clip_extents(mpRT, &clip_x1, &clip_y1, &clip_x2, &clip_y2);
-    const basegfx::B2DRange aViewRange(basegfx::B2DPoint(clip_x1, clip_y1),
-                                       basegfx::B2DPoint(clip_x2, clip_y2));
-    aVisibleRange.intersect(aViewRange);
+    aVisibleRange.intersect(getDiscreteViewRange(mpRT));
 
     if (aVisibleRange.isEmpty())
     {
@@ -1157,11 +1166,7 @@ void CairoPixelProcessor2D::processInvertPrimitive2D(
         rInvertCandidate.getChildren().getB2DRange(getViewInformation2D()));
     
aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
     basegfx::B2DRange aVisibleRange(aDiscreteRange);
-    double clip_x1, clip_x2, clip_y1, clip_y2;
-    cairo_clip_extents(mpRT, &clip_x1, &clip_y1, &clip_x2, &clip_y2);
-    const basegfx::B2DRange aViewRange(basegfx::B2DPoint(clip_x1, clip_y1),
-                                       basegfx::B2DPoint(clip_x2, clip_y2));
-    aVisibleRange.intersect(aViewRange);
+    aVisibleRange.intersect(getDiscreteViewRange(mpRT));
 
     if (aVisibleRange.isEmpty())
     {
@@ -1265,9 +1270,7 @@ void CairoPixelProcessor2D::processInvertPrimitive2D(
 }
 
 void CairoPixelProcessor2D::processMaskPrimitive2D(
-    const primitive2d::MaskPrimitive2D& rMaskCandidate,
-    const primitive2d::FillGradientPrimitive2D* pFillGradientPrimitive2D,
-    const attribute::FillGradientAttribute* pFillGradientAlpha)
+    const primitive2d::MaskPrimitive2D& rMaskCandidate)
 {
     if (rMaskCandidate.getChildren().empty())
     {
@@ -1284,14 +1287,9 @@ void CairoPixelProcessor2D::processMaskPrimitive2D(
     }
 
     // calculate visible range
-    double clip_x1, clip_x2, clip_y1, clip_y2;
-    cairo_clip_extents(mpRT, &clip_x1, &clip_y1, &clip_x2, &clip_y2);
     basegfx::B2DRange aMaskRange(aMask.getB2DRange());
     
aMaskRange.transform(getViewInformation2D().getObjectToViewTransformation());
-    const basegfx::B2DRange aViewRange(basegfx::B2DPoint(clip_x1, clip_y1),
-                                       basegfx::B2DPoint(clip_x2, clip_y2));
-
-    if (!aViewRange.overlaps(aMaskRange))
+    if (!getDiscreteViewRange(mpRT).overlaps(aMaskRange))
     {
         // not visible, done
         return;
@@ -1317,20 +1315,12 @@ void CairoPixelProcessor2D::processMaskPrimitive2D(
     cairo_clip(mpRT);
     cairo_new_path(mpRT);
 
-    if (nullptr != pFillGradientPrimitive2D && nullptr != pFillGradientAlpha)
-    {
-        // special case: render given FillGradientPrimitive2D using
-        // FillGradientAlpha as RGBA gradient directly
-        // note that calling this method with nullptr != pFillGradientAlpha
-        // is only allowed internal from
-        // CairoPixelProcessor2D::processPolyPolygonRGBAGradientPrimitive2D
-        processFillGradientPrimitive2D(*pFillGradientPrimitive2D, 
pFillGradientAlpha);
-    }
-    else
-    {
-        // process sub-content (that shall be masked)
-        process(rMaskCandidate.getChildren());
-    }
+    // reset transformation to not have it set when processing
+    // child content below (was only used to set clip path)
+    cairo_identity_matrix(mpRT);
+
+    // process sub-content (that shall be masked)
+    process(rMaskCandidate.getChildren());
 
     cairo_restore(mpRT);
 }
@@ -1396,11 +1386,7 @@ void 
CairoPixelProcessor2D::processUnifiedTransparencePrimitive2D(
         rTransCandidate.getChildren().getB2DRange(getViewInformation2D()));
     
aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
     basegfx::B2DRange aVisibleRange(aDiscreteRange);
-    double clip_x1, clip_x2, clip_y1, clip_y2;
-    cairo_clip_extents(mpRT, &clip_x1, &clip_y1, &clip_x2, &clip_y2);
-    const basegfx::B2DRange aViewRange(basegfx::B2DPoint(clip_x1, clip_y1),
-                                       basegfx::B2DPoint(clip_x2, clip_y2));
-    aVisibleRange.intersect(aViewRange);
+    aVisibleRange.intersect(getDiscreteViewRange(mpRT));
 
     if (aVisibleRange.isEmpty())
     {
@@ -1900,7 +1886,28 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D_drawOutputRange(
     // fill simple rect with outer color
     const basegfx::BColor aColor(
         
maBColorModifierStack.getModifiedColor(rFillGradientPrimitive2D.getOuterColor()));
-    cairo_set_source_rgb(mpRT, aColor.getRed(), aColor.getGreen(), 
aColor.getBlue());
+
+    if (rFillGradientPrimitive2D.hasAlphaGradient())
+    {
+        const attribute::FillGradientAttribute& rAlphaGradient(
+            rFillGradientPrimitive2D.getAlphaGradient());
+        double fLuminance(0.0);
+
+        if (!rAlphaGradient.getColorStops().empty())
+        {
+            if (css::awt::GradientStyle_AXIAL == rAlphaGradient.getStyle())
+                fLuminance = 
rAlphaGradient.getColorStops().back().getStopColor().luminance();
+            else
+                fLuminance = 
rAlphaGradient.getColorStops().front().getStopColor().luminance();
+        }
+
+        cairo_set_source_rgba(mpRT, aColor.getRed(), aColor.getGreen(), 
aColor.getBlue(),
+                              1.0 - fLuminance);
+    }
+    else
+    {
+        cairo_set_source_rgb(mpRT, aColor.getRed(), aColor.getGreen(), 
aColor.getBlue());
+    }
 
     const basegfx::B2DHomMatrix 
aTrans(getViewInformation2D().getObjectToViewTransformation());
     cairo_matrix_t aMatrix;
@@ -1937,9 +1944,12 @@ bool 
CairoPixelProcessor2D::processFillGradientPrimitive2D_isCompletelyBordered(
 }
 
 void CairoPixelProcessor2D::processFillGradientPrimitive2D_linear_axial(
-    const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D,
-    const attribute::FillGradientAttribute* pFillGradientAlpha)
+    const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
 {
+    const attribute::FillGradientAttribute& rFillGradient(
+        rFillGradientPrimitive2D.getFillGradient());
+    assert(!rFillGradientPrimitive2D.hasAlphaGradient()
+           || 
rFillGradient.sameDefinitionThanAlpha(rFillGradientPrimitive2D.getAlphaGradient()));
     assert(
         (css::awt::GradientStyle_LINEAR == 
rFillGradientPrimitive2D.getFillGradient().getStyle()
          || css::awt::GradientStyle_AXIAL == 
rFillGradientPrimitive2D.getFillGradient().getStyle())
@@ -1948,8 +1958,6 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D_linear_axial(
 
     // need to do 'antique' stuff adaptions for rotate/transitionStart in 
object coordinates
     // (DefinitionRange) to have the right 'bending' on rotation
-    const attribute::FillGradientAttribute& rFillGradient(
-        rFillGradientPrimitive2D.getFillGradient());
     basegfx::B2DRange 
aAdaptedRange(rFillGradientPrimitive2D.getDefinitionRange());
     const double fAngle(basegfx::normalizeToRange((2 * M_PI) - 
rFillGradient.getAngle(), 2 * M_PI));
     const bool bAngle(!basegfx::fTools::equalZero(fAngle));
@@ -1981,9 +1989,9 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D_linear_axial(
     // get color stops (make copy, might have to be changed)
     basegfx::BColorStops aBColorStops(rFillGradient.getColorStops());
     basegfx::BColorStops aBColorStopsAlpha;
-    const bool bHasAlpha(nullptr != pFillGradientAlpha);
+    const bool bHasAlpha(rFillGradientPrimitive2D.hasAlphaGradient());
     if (bHasAlpha)
-        aBColorStopsAlpha = pFillGradientAlpha->getColorStops();
+        aBColorStopsAlpha = 
rFillGradientPrimitive2D.getAlphaGradient().getColorStops();
     const bool bAxial(css::awt::GradientStyle_AXIAL == 
rFillGradient.getStyle());
 
     // get and apply border - create soace at start in gradient
@@ -2036,7 +2044,7 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D_linear_axial(
             const basegfx::BColor aAlpha(aBColorStopsAlpha[a].getStopColor());
             cairo_pattern_add_color_stop_rgba(pPattern, rStop.getStopOffset(), 
aColor.getRed(),
                                               aColor.getGreen(), 
aColor.getBlue(),
-                                              aAlpha.luminance());
+                                              1.0 - aAlpha.luminance());
         }
         else
         {
@@ -2066,6 +2074,13 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D_linear_axial(
 void CairoPixelProcessor2D::processFillGradientPrimitive2D_square_rect(
     const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
 {
+    if (rFillGradientPrimitive2D.hasAlphaGradient())
+    {
+        // process recursively
+        process(rFillGradientPrimitive2D);
+        return;
+    }
+
     assert(
         (css::awt::GradientStyle_SQUARE == 
rFillGradientPrimitive2D.getFillGradient().getStyle()
          || css::awt::GradientStyle_RECT == 
rFillGradientPrimitive2D.getFillGradient().getStyle())
@@ -2321,9 +2336,12 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D_square_rect(
 }
 
 void CairoPixelProcessor2D::processFillGradientPrimitive2D_radial_elliptical(
-    const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D,
-    const attribute::FillGradientAttribute* pFillGradientAlpha)
+    const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
 {
+    const attribute::FillGradientAttribute& rFillGradient(
+        rFillGradientPrimitive2D.getFillGradient());
+    assert(!rFillGradientPrimitive2D.hasAlphaGradient()
+           || 
rFillGradient.sameDefinitionThanAlpha(rFillGradientPrimitive2D.getAlphaGradient()));
     assert((css::awt::GradientStyle_RADIAL == 
rFillGradientPrimitive2D.getFillGradient().getStyle()
             || css::awt::GradientStyle_ELLIPTICAL
                    == rFillGradientPrimitive2D.getFillGradient().getStyle())
@@ -2332,8 +2350,6 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D_radial_elliptical(
 
     // need to do 'antique' stuff adaptions for rotate/transitionStart in 
object coordinates
     // (DefinitionRange) to have the right 'bending' on rotation
-    const attribute::FillGradientAttribute& rFillGradient(
-        rFillGradientPrimitive2D.getFillGradient());
     const basegfx::B2DRange 
rDefRange(rFillGradientPrimitive2D.getDefinitionRange());
     const basegfx::B2DPoint aCenter(rDefRange.getCenter());
     double fRadius(1.0);
@@ -2387,9 +2403,9 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D_radial_elliptical(
     // get color stops (make copy, might have to be changed)
     basegfx::BColorStops aBColorStops(rFillGradient.getColorStops());
     basegfx::BColorStops aBColorStopsAlpha;
-    const bool bHasAlpha(nullptr != pFillGradientAlpha);
+    const bool bHasAlpha(rFillGradientPrimitive2D.hasAlphaGradient());
     if (bHasAlpha)
-        aBColorStopsAlpha = pFillGradientAlpha->getColorStops();
+        aBColorStopsAlpha = 
rFillGradientPrimitive2D.getAlphaGradient().getColorStops();
 
     // get and apply border - create soace at start in gradient
     const double fBorder(std::max(std::min(rFillGradient.getBorder(), 1.0), 
0.0));
@@ -2419,7 +2435,7 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D_radial_elliptical(
             const basegfx::BColor aAlpha(aBColorStopsAlpha[a].getStopColor());
             cairo_pattern_add_color_stop_rgba(pPattern, rStop.getStopOffset(), 
aColor.getRed(),
                                               aColor.getGreen(), 
aColor.getBlue(),
-                                              aAlpha.luminance());
+                                              1.0 - aAlpha.luminance());
         }
         else
         {
@@ -2480,6 +2496,13 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D_radial_elliptical(
 void CairoPixelProcessor2D::processFillGradientPrimitive2D_fallback_decompose(
     const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
 {
+    if (rFillGradientPrimitive2D.hasAlphaGradient())
+    {
+        // process recursively to elliminate alpha, cannot be used in 
decompose fallback
+        process(rFillGradientPrimitive2D);
+        return;
+    }
+
     // this helper draws the given gradient using the decompose fallback,
     // maybe needed in some cases an can/will be handy
     cairo_save(mpRT);
@@ -2515,8 +2538,7 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D_fallback_decompose(
 }
 
 void CairoPixelProcessor2D::processFillGradientPrimitive2D(
-    const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D,
-    const attribute::FillGradientAttribute* pFillGradientAlpha)
+    const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
 {
     if (rFillGradientPrimitive2D.getDefinitionRange().isEmpty())
     {
@@ -2564,21 +2586,13 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D(
         return;
     }
 
-    // for direct RGBA gradient render support: assert when the definition
-    // is not allowed, it HAS to fulfil the requested preconditions. Note that
-    // the form to call this function using nullptr != pFillGradientAlpha is
-    // only allowed locally in CairoPixelProcessor2D::processMaskPrimitive2D
-    assert(nullptr == pFillGradientAlpha
-           || rFillGradient.sameDefinitionThanAlpha(*pFillGradientAlpha));
-
     switch (rFillGradient.getStyle())
     {
         case css::awt::GradientStyle_LINEAR:
         case css::awt::GradientStyle_AXIAL:
         {
             // use specialized renderer for this cases - linear, axial
-            
processFillGradientPrimitive2D_linear_axial(rFillGradientPrimitive2D,
-                                                        pFillGradientAlpha);
+            
processFillGradientPrimitive2D_linear_axial(rFillGradientPrimitive2D);
             return;
         }
         case css::awt::GradientStyle_RADIAL:
@@ -2595,8 +2609,7 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D(
             // 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,
-                                                             
pFillGradientAlpha);
+            
processFillGradientPrimitive2D_radial_elliptical(rFillGradientPrimitive2D);
             return;
         }
         case css::awt::GradientStyle_SQUARE:
@@ -2623,53 +2636,6 @@ void 
CairoPixelProcessor2D::processFillGradientPrimitive2D(
     }
 }
 
-void CairoPixelProcessor2D::processPolyPolygonRGBAGradientPrimitive2D(
-    const primitive2d::PolyPolygonRGBAGradientPrimitive2D& 
rPolyPolygonRGBAGradientPrimitive2D)
-{
-    const attribute::FillGradientAttribute& rFill(
-        rPolyPolygonRGBAGradientPrimitive2D.getFillGradient());
-    const attribute::FillGradientAttribute& rAlpha(
-        rPolyPolygonRGBAGradientPrimitive2D.getFillGradientAlpha());
-
-    if (rFill.isDefault())
-    {
-        // no gradient definition, done
-        return;
-    }
-
-    // assert when the definition is not allowed, it HAS to fulfil the
-    // requested preconditions
-    assert(rFill.sameDefinitionThanAlpha(rAlpha));
-
-    // the gradient still needs to be masked to getB2DPolyPolygon() at the
-    // primitive, see PolyPolygonGradientPrimitive2D::create2DDecomposition.
-    // we could repeat here the code inside localprocessMaskPrimitive2D, but
-    // it is easier to just locally temporarily create the needed data 
structure
-    // and hand over the needed extra-data
-    const basegfx::B2DRange aPolyPolygonRange(
-        rPolyPolygonRGBAGradientPrimitive2D.getB2DPolyPolygon().getB2DRange());
-    primitive2d::FillGradientPrimitive2D* pFillGradientPrimitive2D(
-        new primitive2d::FillGradientPrimitive2D(
-            aPolyPolygonRange, 
rPolyPolygonRGBAGradientPrimitive2D.getDefinitionRange(), rFill));
-    primitive2d::Primitive2DContainer aContent{ pFillGradientPrimitive2D };
-
-    // NOTE: I had this like
-    //   const primitive2d::MaskPrimitive2D aMaskPrimitive2D(
-    //       rPolyPolygonRGBAGradientPrimitive2D.getB2DPolyPolygon(), 
std::move(aContent));
-    // but I got
-    //   error: salhelper::SimpleReferenceObject subclass being directly stack 
managed, should
-    //   be managed via rtl::Reference, const primitive2d::MaskPrimitive2D 
[loplugin:refcounting]
-    // thus I have *no choice* and have to use the heap here (?) It is no 
problem to use the stack
-    // and I wanted to do this here by purpose... sigh
-    primitive2d::MaskPrimitive2D* pMaskPrimitive2D(new 
primitive2d::MaskPrimitive2D(
-        rPolyPolygonRGBAGradientPrimitive2D.getB2DPolyPolygon(), 
std::move(aContent)));
-    primitive2d::Primitive2DContainer aMask{ pMaskPrimitive2D };
-    (void)aMask;
-
-    // render masked RGBA gradient
-    processMaskPrimitive2D(*pMaskPrimitive2D, pFillGradientPrimitive2D, 
&rAlpha);
-}
-
 void CairoPixelProcessor2D::processBasePrimitive2D(const 
primitive2d::BasePrimitive2D& rCandidate)
 {
     switch (rCandidate.getPrimitive2DID())
@@ -2729,6 +2695,7 @@ void CairoPixelProcessor2D::processBasePrimitive2D(const 
primitive2d::BasePrimit
                 static_cast<const 
primitive2d::TransformPrimitive2D&>(rCandidate));
             break;
         }
+
         // geometry that *may* be processed due to being able to do it better
         // then using the decomposition
         case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D:
@@ -2785,12 +2752,6 @@ void CairoPixelProcessor2D::processBasePrimitive2D(const 
primitive2d::BasePrimit
                 static_cast<const 
primitive2d::FillGradientPrimitive2D&>(rCandidate));
             break;
         }
-        case PRIMITIVE2D_ID_POLYPOLYGONRGBAGRADIENTPRIMITIVE2D:
-        {
-            processPolyPolygonRGBAGradientPrimitive2D(
-                static_cast<const 
primitive2d::PolyPolygonRGBAGradientPrimitive2D&>(rCandidate));
-            break;
-        }
 
         // continue with decompose
         default:
diff --git a/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx 
b/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx
index e9bcc6c10423..7bc422a98f43 100644
--- a/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx
@@ -1926,6 +1926,14 @@ void D2DPixelProcessor2D::processFillGraphicPrimitive2D(
 void D2DPixelProcessor2D::processFillGradientPrimitive2D(
     const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D)
 {
+    if (rFillGradientPrimitive2D.hasAlphaGradient())
+    {
+        // SDPR: As long as direct alpha is not supported by this
+        // renderer we need to work on the decomposition, so call it
+        process(rFillGradientPrimitive2D);
+        return;
+    }
+
     // draw all-covering initial BG polygon 1st
     bool bDone(drawPolyPolygonColorTransformed(
         basegfx::B2DHomMatrix(),
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx 
b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index f09131b04c30..ea0bea62b0fa 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -930,6 +930,14 @@ void VclPixelProcessor2D::processMetaFilePrimitive2D(const 
primitive2d::BasePrim
 void VclPixelProcessor2D::processFillGradientPrimitive2D(
     const primitive2d::FillGradientPrimitive2D& rPrimitive)
 {
+    if (rPrimitive.hasAlphaGradient())
+    {
+        // SDPR: As long as direct alpha is not supported by this
+        // renderer we need to work on the decomposition, so call it
+        process(rPrimitive);
+        return;
+    }
+
     const attribute::FillGradientAttribute& rFillGradient = 
rPrimitive.getFillGradient();
     bool useDecompose(false);
 
diff --git 
a/include/drawinglayer/primitive2d/PolyPolygonGradientPrimitive2D.hxx 
b/include/drawinglayer/primitive2d/PolyPolygonGradientPrimitive2D.hxx
index 59bbff030abf..13afc0616016 100644
--- a/include/drawinglayer/primitive2d/PolyPolygonGradientPrimitive2D.hxx
+++ b/include/drawinglayer/primitive2d/PolyPolygonGradientPrimitive2D.hxx
@@ -46,6 +46,9 @@ private:
     /// the gradient definition
     attribute::FillGradientAttribute maFillGradient;
 
+    /// evtl. fitting alphaGradient definition
+    attribute::FillGradientAttribute maAlphaGradient;
+
     /// local decomposition.
     virtual Primitive2DReference
     create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) 
const override;
@@ -53,15 +56,19 @@ private:
 public:
     /// constructors. The one without definition range will use output range 
as definition range
     PolyPolygonGradientPrimitive2D(const basegfx::B2DPolyPolygon& rPolyPolygon,
-                                   attribute::FillGradientAttribute 
rFillGradient);
+                                   const attribute::FillGradientAttribute& 
rFillGradient);
     PolyPolygonGradientPrimitive2D(basegfx::B2DPolyPolygon aPolyPolygon,
                                    const basegfx::B2DRange& rDefinitionRange,
-                                   attribute::FillGradientAttribute 
aFillGradient);
+                                   const attribute::FillGradientAttribute& 
rFillGradient,
+                                   const attribute::FillGradientAttribute* 
pAlphaGradient
+                                   = nullptr);
 
     /// data read access
     const basegfx::B2DPolyPolygon& getB2DPolyPolygon() const { return 
maPolyPolygon; }
     const basegfx::B2DRange& getDefinitionRange() const { return 
maDefinitionRange; }
     const attribute::FillGradientAttribute& getFillGradient() const { return 
maFillGradient; }
+    const attribute::FillGradientAttribute& getAlphaGradient() const { return 
maAlphaGradient; }
+    bool hasAlphaGradient() const { return !maAlphaGradient.isDefault(); }
 
     /// compare operator
     virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
@@ -69,46 +76,6 @@ public:
     /// provide unique ID
     virtual sal_uInt32 getPrimitive2DID() const override;
 };
-
-// helper primitive that can be used to directly express RGBA
-// gradient definitions. It will be decomposed to a combined
-// TransparencePrimitive2D if not handled directly. Use the
-// already existing PolyPolygonGradientPrimitive2D as base class,
-// only the additional FillGradientAlpha needs to be added.
-// NOTE: FillGradientAlpha *has* to fulfil the
-// 'sameDefinitionThanAlpha' condition defined by the check
-// method with the same name
-class DRAWINGLAYER_DLLPUBLIC PolyPolygonRGBAGradientPrimitive2D final
-    : public PolyPolygonGradientPrimitive2D
-{
-private:
-    /// the gradient alpha definition
-    attribute::FillGradientAttribute maFillGradientAlpha;
-
-    /// local decomposition.
-    virtual Primitive2DReference
-    create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) 
const override;
-
-public:
-    /// constructors. The one without definition range will use output range 
as definition range
-    PolyPolygonRGBAGradientPrimitive2D(basegfx::B2DPolyPolygon aPolyPolygon,
-                                       const basegfx::B2DRange& 
rDefinitionRange,
-                                       attribute::FillGradientAttribute 
aFillGradient,
-                                       attribute::FillGradientAttribute 
aFillGradientAlpha);
-
-    /// data read access
-    const attribute::FillGradientAttribute& getFillGradientAlpha() const
-    {
-        return maFillGradientAlpha;
-    }
-
-    /// compare operator
-    virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
-
-    /// provide unique ID
-    virtual sal_uInt32 getPrimitive2DID() const override;
-};
-
 } // end of namespace primitive2d::drawinglayer
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx 
b/include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx
index 71d0be9988e7..ba165bb23db2 100644
--- a/include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx
+++ b/include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx
@@ -108,8 +108,7 @@
 #define PRIMITIVE2D_ID_FILLEDRECTANGLEPRIMITIVE2D           
(PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 74)
 #define PRIMITIVE2D_ID_SINGLELINEPRIMITIVE2D                
(PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 75)
 #define PRIMITIVE2D_ID_EXCLUSIVEEDITVIEWPRIMITIVE2D         
(PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 76)
-#define PRIMITIVE2D_ID_POLYPOLYGONRGBAGRADIENTPRIMITIVE2D   
(PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 77)
-#define PRIMITIVE2D_ID_ANIMATEDGRAPHICPRIMITIVE2D           
(PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 78)
+#define PRIMITIVE2D_ID_ANIMATEDGRAPHICPRIMITIVE2D           
(PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 77)
 // When you add a new primitive, please update the 
drawinglayer::primitive2d::idToString() function
 // in drawinglayer/source/primitive2d/Tools.cxx.
 
diff --git a/include/drawinglayer/primitive2d/fillgradientprimitive2d.hxx 
b/include/drawinglayer/primitive2d/fillgradientprimitive2d.hxx
index 42f4de30fd91..41b8c91f507f 100644
--- a/include/drawinglayer/primitive2d/fillgradientprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/fillgradientprimitive2d.hxx
@@ -47,6 +47,12 @@ namespace drawinglayer::primitive2d
             default one since it works with and without AntiAliasing. The 
non-overlapping
             version is used in the MetafilePrimitive2D decomposition when the 
old XOR
             paint was recorded.
+
+            SDPR: Have now added to directly support alpha in the definition 
so that
+            all implementations of primitive renderers may use it. Be aware 
that if a
+            renderer does not support using that alpha it is advised to use the
+            decomposition which separates content and alpha in a 
TransparencePrimitive2D.
+            That way all stuff being used to that before will work unchanged.
          */
         class DRAWINGLAYER_DLLPUBLIC FillGradientPrimitive2D : public 
BufferedDecompositionPrimitive2D
         {
@@ -61,6 +67,9 @@ namespace drawinglayer::primitive2d
             /// the gradient definition
             attribute::FillGradientAttribute        maFillGradient;
 
+            /// evtl. fitting alphaGradient definition
+            attribute::FillGradientAttribute        maAlphaGradient;
+
 
         protected:
             /// local helper
@@ -79,16 +88,19 @@ namespace drawinglayer::primitive2d
             /// constructors. The one without definition range will use output 
range as definition range
             FillGradientPrimitive2D(
                 const basegfx::B2DRange& rOutputRange,
-                attribute::FillGradientAttribute aFillGradient);
+                const attribute::FillGradientAttribute& rFillGradient);
             FillGradientPrimitive2D(
                 const basegfx::B2DRange& rOutputRange,
                 const basegfx::B2DRange& rDefinitionRange,
-                attribute::FillGradientAttribute aFillGradient);
+                const attribute::FillGradientAttribute& rFillGradient,
+                const attribute::FillGradientAttribute* pAlphaGradient = 
nullptr);
 
             /// data read access
             const basegfx::B2DRange& getOutputRange() const { return 
maOutputRange; }
             const basegfx::B2DRange& getDefinitionRange() const { return 
maDefinitionRange; }
             const attribute::FillGradientAttribute& getFillGradient() const { 
return maFillGradient; }
+            const attribute::FillGradientAttribute& getAlphaGradient() const { 
return maAlphaGradient; }
+            bool hasAlphaGradient() const { return 
!maAlphaGradient.isDefault(); }
 
             /// compare operator
             virtual bool operator==(const BasePrimitive2D& rPrimitive) const 
override final;
diff --git a/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx 
b/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx
index 74977b704051..00d75e5f594c 100644
--- a/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx
+++ b/include/drawinglayer/processor2d/cairopixelprocessor2d.hxx
@@ -39,11 +39,6 @@ class PolyPolygonRGBAGradientPrimitive2D;
 class FillGraphicPrimitive2D;
 }
 
-namespace drawinglayer::attribute
-{
-class FillGradientAttribute;
-}
-
 namespace drawinglayer::processor2d
 {
 class UNLESS_MERGELIBS(DRAWINGLAYER_DLLPUBLIC) CairoPixelProcessor2D final : 
public BaseProcessor2D
@@ -65,11 +60,7 @@ class UNLESS_MERGELIBS(DRAWINGLAYER_DLLPUBLIC) 
CairoPixelProcessor2D final : pub
     void processInvertPrimitive2D(const primitive2d::InvertPrimitive2D& 
rTransCandidate);
     void processUnifiedTransparencePrimitive2D(
         const primitive2d::UnifiedTransparencePrimitive2D& rTransCandidate);
-    void processMaskPrimitive2D(const primitive2d::MaskPrimitive2D& 
rMaskCandidate,
-                                const primitive2d::FillGradientPrimitive2D* 
pFillGradientPrimitive2D
-                                = nullptr,
-                                const attribute::FillGradientAttribute* 
pFillGradientAlpha
-                                = nullptr);
+    void processMaskPrimitive2D(const primitive2d::MaskPrimitive2D& 
rMaskCandidate);
     void processModifiedColorPrimitive2D(
         const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate);
     void processTransformPrimitive2D(const primitive2d::TransformPrimitive2D& 
rTransformCandidate);
@@ -88,12 +79,9 @@ class UNLESS_MERGELIBS(DRAWINGLAYER_DLLPUBLIC) 
CairoPixelProcessor2D final : pub
     void
     processSingleLinePrimitive2D(const primitive2d::SingleLinePrimitive2D& 
rSingleLinePrimitive2D);
     void processFillGradientPrimitive2D(
-        const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D,
-        const attribute::FillGradientAttribute* pFillGradientAlpha = nullptr);
+        const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D);
     void processFillGraphicPrimitive2D(
         const primitive2d::FillGraphicPrimitive2D& rFillGraphicPrimitive2D);
-    void processPolyPolygonRGBAGradientPrimitive2D(
-        const primitive2d::PolyPolygonRGBAGradientPrimitive2D& 
rPolyPolygonRGBAGradientPrimitive2D);
 
     /*  the local processor for BasePrimitive2D-Implementation based 
primitives,
         called from the common process()-implementation
@@ -108,11 +96,9 @@ class UNLESS_MERGELIBS(DRAWINGLAYER_DLLPUBLIC) 
CairoPixelProcessor2D final : pub
     bool processFillGradientPrimitive2D_isCompletelyBordered(
         const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D);
     void processFillGradientPrimitive2D_linear_axial(
-        const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D,
-        const attribute::FillGradientAttribute* pFillGradientAlpha = nullptr);
+        const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D);
     void processFillGradientPrimitive2D_radial_elliptical(
-        const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D,
-        const attribute::FillGradientAttribute* pFillGradientAlpha = nullptr);
+        const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D);
     void processFillGradientPrimitive2D_square_rect(
         const primitive2d::FillGradientPrimitive2D& rFillGradientPrimitive2D);
 
diff --git a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx 
b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
index 79bc74bf28a5..56656722d287 100644
--- a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
+++ b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx
@@ -395,39 +395,33 @@ sal_uInt32 
SlideBackgroundFillPrimitive2D::getPrimitive2DID() const
                 return Primitive2DReference();
             }
 
+            // prepare access to FillGradientAttribute
             const attribute::FillGradientAttribute& 
rFillGradient(rFill.getGradient());
 
-            // SDPR: check if RGB and A definitions of gradients are both
-            // used and equal, so that they could be combined to a single
-            // RGBA one
-            if (!rFillGradient.isDefault()
-                && 0.0 == rFill.getTransparence()
-                && !rAlphaGradient.isDefault()
-                && rFillGradient.sameDefinitionThanAlpha(rAlphaGradient))
-            {
-                // if yes, create a primitive expressing that. That primitive's
-                // decompose will do the same as if the code below would be 
executed,
-                // so no primitive renderer who does not want to will have to 
handle
-                // it - but SDPR renderers that can directly render that may 
choose to
-                // do so. NOTE: That helper primitive just holds references to 
what
-                // would be created anyways, so one depth step added but not 
really any
-                // additional data
-                return new PolyPolygonRGBAGradientPrimitive2D(
-                    rPolyPolygon,
-                    rDefinitionRange,
-                    rFillGradient,
-                    rAlphaGradient);
-            }
-
             // prepare fully scaled polygon
             rtl::Reference<BasePrimitive2D> pNewFillPrimitive;
 
             if(!rFillGradient.isDefault())
             {
+                // SDPR: check early if we have a radient and a alpha
+                // gradient that 'fits' in it's geometric definition
+                // so that it can be rendered as RGBA directly. If yes,
+                // create it and return early
+                const bool bIncludeAlpha(
+                    0.0 == rFill.getTransparence()
+                    && !rAlphaGradient.isDefault()
+                    && rFillGradient.sameDefinitionThanAlpha(rAlphaGradient));
+
                 pNewFillPrimitive = new PolyPolygonGradientPrimitive2D(
                     rPolyPolygon,
                     rDefinitionRange,
-                    rFillGradient);
+                    rFillGradient,
+                    bIncludeAlpha ? &rAlphaGradient : nullptr);
+
+                if (bIncludeAlpha)
+                {
+                    return pNewFillPrimitive;
+                }
             }
             else if(!rFill.getHatch().isDefault())
             {

Reply via email to