basegfx/source/tools/gradienttools.cxx                      |   30 +
 drawinglayer/inc/texture/texture.hxx                        |   38 -
 drawinglayer/source/attribute/fillgradientattribute.cxx     |  122 +++--
 drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx |   53 --
 drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx  |    1 
 drawinglayer/source/processor2d/vclpixelprocessor2d.cxx     |    1 
 drawinglayer/source/processor3d/defaultprocessor3d.cxx      |   55 --
 drawinglayer/source/texture/texture.cxx                     |  265 +++++++-----
 drawinglayer/source/tools/primitive2dxmldump.cxx            |    1 
 drawinglayer/source/tools/wmfemfhelper.cxx                  |    1 
 include/basegfx/utils/gradienttools.hxx                     |  115 ++++-
 include/drawinglayer/attribute/fillgradientattribute.hxx    |   68 ---
 svx/source/sdr/attribute/sdrallfillattributeshelper.cxx     |    1 
 svx/source/sdr/primitive2d/sdrattributecreator.cxx          |   13 
 14 files changed, 437 insertions(+), 327 deletions(-)

New commits:
commit ea1d3d11ca113042a99effc168da834894005370
Author:     Armin Le Grand (allotropia) <armin.le.grand.ext...@allotropia.de>
AuthorDate: Wed Feb 15 10:45:10 2023 +0100
Commit:     Armin Le Grand <armin.le.gr...@me.com>
CommitDate: Wed Feb 15 14:46:11 2023 +0000

    MCGR: Add GradientSteps to GeoTexSvxGradient
    
    Move GradientSteps data to GeoTexSvxGradient and adapt
    interfaces. Also move tooling to more isolated place
    in gradienttools in basegfx.
    
    Keep everything still compatible, the work will be now
    to adapt all six different derivations of
    GeoTexSvxGradient to make use of the evtl. given
    GradientSteps.
    
    Change-Id: Iaa212763c603d46de0a94b1b203b979bb7ce359d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147050
    Tested-by: Jenkins
    Reviewed-by: Armin Le Grand <armin.le.gr...@me.com>

diff --git a/basegfx/source/tools/gradienttools.cxx 
b/basegfx/source/tools/gradienttools.cxx
index c6e716510432..3f2480c82e84 100644
--- a/basegfx/source/tools/gradienttools.cxx
+++ b/basegfx/source/tools/gradienttools.cxx
@@ -29,7 +29,7 @@ namespace basegfx
     {
         return getTextureTransform() == rODFGradientInfo.getTextureTransform()
             && getAspectRatio() == rODFGradientInfo.getAspectRatio()
-            && getSteps() == rODFGradientInfo.getSteps();
+            && getRequestedSteps() == rODFGradientInfo.getRequestedSteps();
     }
 
     const B2DHomMatrix& ODFGradientInfo::getBackTextureTransform() const
@@ -261,6 +261,26 @@ namespace basegfx
 
     namespace utils
     {
+        sal_uInt32 calculateNumberOfSteps(
+            sal_uInt32 nRequestedSteps,
+            const BColor& rStart,
+            const BColor& rEnd)
+        {
+            const sal_uInt32 
nMaxSteps(sal_uInt32((rStart.getMaximumDistance(rEnd) * 127.5) + 0.5));
+
+            if (0 == nRequestedSteps)
+            {
+                nRequestedSteps = nMaxSteps;
+            }
+
+            if(nRequestedSteps > nMaxSteps)
+            {
+                nRequestedSteps = nMaxSteps;
+            }
+
+            return std::max(sal_uInt32(1), nRequestedSteps);
+        }
+
         ODFGradientInfo createLinearODFGradientInfo(
             const B2DRange& rTargetArea,
             sal_uInt32 nSteps,
@@ -372,7 +392,7 @@ namespace basegfx
                 return 1.0; // end value for outside
             }
 
-            const sal_uInt32 nSteps(rGradInfo.getSteps());
+            const sal_uInt32 nSteps(rGradInfo.getRequestedSteps());
 
             if(nSteps)
             {
@@ -399,7 +419,7 @@ namespace basegfx
                 return 1.0; // use end value when outside in Y
             }
 
-            const sal_uInt32 nSteps(rGradInfo.getSteps());
+            const sal_uInt32 nSteps(rGradInfo.getRequestedSteps());
 
             if(nSteps)
             {
@@ -419,7 +439,7 @@ namespace basegfx
             }
 
             const double t(1.0 - std::hypot(aCoor.getX(), aCoor.getY()));
-            const sal_uInt32 nSteps(rGradInfo.getSteps());
+            const sal_uInt32 nSteps(rGradInfo.getRequestedSteps());
 
             if(nSteps && t < 1.0)
             {
@@ -452,7 +472,7 @@ namespace basegfx
             }
 
             const double t(1.0 - std::max(fAbsX, fAbsY));
-            const sal_uInt32 nSteps(rGradInfo.getSteps());
+            const sal_uInt32 nSteps(rGradInfo.getRequestedSteps());
 
             if(nSteps && t < 1.0)
             {
diff --git a/drawinglayer/inc/texture/texture.hxx 
b/drawinglayer/inc/texture/texture.hxx
index 9cfb2d6d56f7..567a24417f51 100644
--- a/drawinglayer/inc/texture/texture.hxx
+++ b/drawinglayer/inc/texture/texture.hxx
@@ -56,15 +56,15 @@ namespace drawinglayer::texture
         protected:
             basegfx::ODFGradientInfo            maGradientInfo;
             basegfx::B2DRange                   maDefinitionRange;
-            basegfx::BColor                     maStart;
-            basegfx::BColor                     maEnd;
+            sal_uInt32                          mnRequestedSteps;
+            basegfx::ColorSteps                 mnColorSteps;
             double                              mfBorder;
 
         public:
             GeoTexSvxGradient(
                 const basegfx::B2DRange& rDefinitionRange,
-                const basegfx::BColor& rStart,
-                const basegfx::BColor& rEnd,
+                sal_uInt32 nRequestedSteps,
+                const basegfx::ColorSteps& rColorSteps,
                 double fBorder);
             virtual ~GeoTexSvxGradient() override;
 
@@ -87,9 +87,8 @@ namespace drawinglayer::texture
             GeoTexSvxGradientLinear(
                 const basegfx::B2DRange& rDefinitionRange,
                 const basegfx::B2DRange& rOutputRange,
-                const basegfx::BColor& rStart,
-                const basegfx::BColor& rEnd,
-                sal_uInt32 nSteps,
+                sal_uInt32 nRequestedSteps,
+                const basegfx::ColorSteps& rColorSteps,
                 double fBorder,
                 double fAngle);
             virtual ~GeoTexSvxGradientLinear() override;
@@ -109,9 +108,8 @@ namespace drawinglayer::texture
             GeoTexSvxGradientAxial(
                 const basegfx::B2DRange& rDefinitionRange,
                 const basegfx::B2DRange& rOutputRange,
-                const basegfx::BColor& rStart,
-                const basegfx::BColor& rEnd,
-                sal_uInt32 nSteps,
+                sal_uInt32 nRequestedSteps,
+                const basegfx::ColorSteps& rColorSteps,
                 double fBorder,
                 double fAngle);
             virtual ~GeoTexSvxGradientAxial() override;
@@ -127,9 +125,8 @@ namespace drawinglayer::texture
         public:
             GeoTexSvxGradientRadial(
                 const basegfx::B2DRange& rDefinitionRange,
-                const basegfx::BColor& rStart,
-                const basegfx::BColor& rEnd,
-                sal_uInt32 nSteps,
+                sal_uInt32 nRequestedSteps,
+                const basegfx::ColorSteps& rColorSteps,
                 double fBorder,
                 double fOffsetX,
                 double fOffsetY);
@@ -146,9 +143,8 @@ namespace drawinglayer::texture
         public:
             GeoTexSvxGradientElliptical(
                 const basegfx::B2DRange& rDefinitionRange,
-                const basegfx::BColor& rStart,
-                const basegfx::BColor& rEnd,
-                sal_uInt32 nSteps,
+                sal_uInt32 nRequestedSteps,
+                const basegfx::ColorSteps& rColorSteps,
                 double fBorder,
                 double fOffsetX,
                 double fOffsetY,
@@ -166,9 +162,8 @@ namespace drawinglayer::texture
         public:
             GeoTexSvxGradientSquare(
                 const basegfx::B2DRange& rDefinitionRange,
-                const basegfx::BColor& rStart,
-                const basegfx::BColor& rEnd,
-                sal_uInt32 nSteps,
+                sal_uInt32 nRequestedSteps,
+                const basegfx::ColorSteps& rColorSteps,
                 double fBorder,
                 double fOffsetX,
                 double fOffsetY,
@@ -186,9 +181,8 @@ namespace drawinglayer::texture
         public:
             GeoTexSvxGradientRect(
                 const basegfx::B2DRange& rDefinitionRange,
-                const basegfx::BColor& rStart,
-                const basegfx::BColor& rEnd,
-                sal_uInt32 nSteps,
+                sal_uInt32 nRequestedSteps,
+                const basegfx::ColorSteps& rColorSteps,
                 double fBorder,
                 double fOffsetX,
                 double fOffsetY,
diff --git a/drawinglayer/source/attribute/fillgradientattribute.cxx 
b/drawinglayer/source/attribute/fillgradientattribute.cxx
index 32edd39340fe..c653a6e84057 100644
--- a/drawinglayer/source/attribute/fillgradientattribute.cxx
+++ b/drawinglayer/source/attribute/fillgradientattribute.cxx
@@ -18,6 +18,7 @@
  */
 
 #include <drawinglayer/attribute/fillgradientattribute.hxx>
+#include <basegfx/utils/gradienttools.hxx>
 
 namespace drawinglayer::attribute
 {
@@ -29,7 +30,7 @@ namespace drawinglayer::attribute
             double                                  mfOffsetX;
             double                                  mfOffsetY;
             double                                  mfAngle;
-            FillGradientAttribute::ColorSteps       maColorSteps;
+            basegfx::ColorSteps                     maColorSteps;
             GradientStyle                           meStyle;
             sal_uInt16                              mnSteps;
 
@@ -41,7 +42,7 @@ namespace drawinglayer::attribute
                 double fAngle,
                 const basegfx::BColor& rStartColor,
                 const basegfx::BColor& rEndColor,
-                const FillGradientAttribute::ColorSteps* pColorSteps,
+                const basegfx::ColorSteps* pColorSteps,
                 sal_uInt16 nSteps)
             :   mfBorder(fBorder),
                 mfOffsetX(fOffsetX),
@@ -55,47 +56,79 @@ namespace drawinglayer::attribute
                 // to have one and not an empty vector, that spares many 
checks in the using code
                 maColorSteps.emplace_back(0.0, rStartColor);
 
-                // if we have ColorSteps, integrate these
-                if(nullptr != pColorSteps)
+                // if we have given ColorSteps, integrate these
+                if(nullptr != pColorSteps && !pColorSteps->empty())
                 {
-                    for(const auto& candidate : *pColorSteps)
+                    // append early & sort to local to prepare processing and 
correction(s)
+                    maColorSteps.insert(maColorSteps.end(), 
pColorSteps->begin(), pColorSteps->end());
+                    std::sort(maColorSteps.begin(), maColorSteps.end());
+
+                    // use two r/w heads on the data band maColorSteps
+                    size_t curr(0), next(1);
+
+                    // check if all colors are the same. We know the 
StartColor, so
+                    // to all be the same all have to be equal to StartColor, 
including
+                    // EndColor
+                    bool bAllTheSameColor(rStartColor == rEndColor);
+
+                    // remove entries < 0.0, > 1.0 and with equal offset. do
+                    // this inside the already sorted local vector by evtl.
+                    // moving entries towards begin to keep and adapting size
+                    // at the end
+                    for(; next < maColorSteps.size(); next++)
                     {
-                        // only allow ]0.0 .. 1.0[ as offset values, 
*excluding* 0.0 and 1.0
-                        // explicitly - these are reserved for start/end color
-                        if(basegfx::fTools::more(candidate.getOffset(), 0.0) 
&& basegfx::fTools::less(candidate.getOffset(), 1.0))
+                        const double 
fNextOffset(maColorSteps[next].getOffset());
+
+                        if(basegfx::fTools::less(fNextOffset, 0.0))
+                            continue;
+
+                        if(basegfx::fTools::more(fNextOffset, 1.0))
+                            continue;
+
+                        const double 
fCurrOffset(maColorSteps[curr].getOffset());
+                        if(basegfx::fTools::equal(fNextOffset, fCurrOffset))
+                            continue;
+
+                        // next is > 0.0, < 1.0 and != curr, so a valid entry.
+                        // take over by evtl. have to move it left
+                        curr++;
+                        if(curr != next)
                         {
-                            // ignore same offsets, independent from color (so 
1st one wins)
-                            // having two or more same offsets is an error 
(may assert evtl.)
-                            bool bAccept(true);
-
-                            for(const auto& compare : maColorSteps)
-                            {
-                                if(basegfx::fTools::equal(compare.getOffset(), 
candidate.getOffset()))
-                                {
-                                    bAccept = false;
-                                    break;
-                                }
-                            }
-
-                            if(bAccept)
-                            {
-                                maColorSteps.push_back(candidate);
-                            }
+                            maColorSteps[curr] = maColorSteps[next];
                         }
+
+                        // new entry added, check it for all the same color
+                        bAllTheSameColor = bAllTheSameColor && 
maColorSteps[curr].getColor() == rStartColor;
                     }
 
-                    // sort by offset when colors were added
-                    if(maColorSteps.size() > 1)
+                    if(bAllTheSameColor)
                     {
-                        std::sort(maColorSteps.begin(), maColorSteps.end());
+                        // if all the same, reset to StartColor only
+                        maColorSteps.resize(1);
                     }
-                }
+                    else
+                    {
+                        // adapt size to useful entries
+                        curr++;
+                        if(curr != maColorSteps.size())
+                        {
+                            maColorSteps.resize(curr);
+                        }
 
-                // add end color if different from last color - which is the 
start color
-                // when no ColorSteps are given
-                if(rEndColor != maColorSteps.back().getColor())
+                        // add EndColor if in-between colors were added
+                        if(curr > 1)
+                        {
+                            maColorSteps.emplace_back(1.0, rEndColor);
+                        }
+                    }
+                }
+                else
                 {
-                    maColorSteps.emplace_back(1.0, rEndColor);
+                    // add EndColor if different from StartColor
+                    if(rStartColor != rEndColor)
+                    {
+                        maColorSteps.emplace_back(1.0, rEndColor);
+                    }
                 }
             }
 
@@ -118,23 +151,16 @@ namespace drawinglayer::attribute
             double getOffsetX() const { return mfOffsetX; }
             double getOffsetY() const { return mfOffsetY; }
             double getAngle() const { return mfAngle; }
-            const FillGradientAttribute::ColorSteps& getColorSteps() const { 
return maColorSteps; }
+            const basegfx::ColorSteps& getColorSteps() const { return 
maColorSteps; }
             sal_uInt16 getSteps() const { return mnSteps; }
 
             bool hasSingleColor() const
             {
-                // no entries (should not happen, see comments for startColor)
-                if (0 == maColorSteps.size())
-                    return true;
-
-                // check if not all colors are the same
-                const basegfx::BColor& rColor(maColorSteps[0].getColor());
-                for (size_t a(1); a < maColorSteps.size(); a++)
-                    if (maColorSteps[a].getColor() != rColor)
-                        return false;
-
-                // all colors are the same
-                return true;
+                // No entry (should not happen, see comments for startColor 
above)
+                // or single entry -> no gradient.
+                // No need to check for all-the-same color since this is 
checked/done
+                // in the constructor already, see there
+                return maColorSteps.size() < 2;
             }
 
             bool operator==(const ImpFillGradientAttribute& rCandidate) const
@@ -166,7 +192,7 @@ namespace drawinglayer::attribute
             double fAngle,
             const basegfx::BColor& rStartColor,
             const basegfx::BColor& rEndColor,
-            const ColorSteps* pColorSteps,
+            const basegfx::ColorSteps* pColorSteps,
             sal_uInt16 nSteps)
         :   mpFillGradientAttribute(ImpFillGradientAttribute(
                 eStyle, fBorder, fOffsetX, fOffsetY, fAngle, rStartColor, 
rEndColor, pColorSteps, nSteps))
@@ -207,7 +233,7 @@ namespace drawinglayer::attribute
             return rCandidate.mpFillGradientAttribute == 
mpFillGradientAttribute;
         }
 
-        const FillGradientAttribute::ColorSteps& 
FillGradientAttribute::getColorSteps() const
+        const basegfx::ColorSteps& FillGradientAttribute::getColorSteps() const
         {
             return mpFillGradientAttribute->getColorSteps();
         }
diff --git a/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx 
b/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx
index 0f6eef0508cb..a92a5f9e0d8d 100644
--- a/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx
@@ -37,29 +37,6 @@ namespace drawinglayer::primitive2d
         {
             rEntries.clear();
 
-            // make sure steps is not too high/low
-            const basegfx::BColor 
aStart(getFillGradient().getColorSteps().front().getColor());
-            const basegfx::BColor 
aEnd(getFillGradient().getColorSteps().back().getColor());
-            const sal_uInt32 
nMaxSteps(sal_uInt32((aStart.getMaximumDistance(aEnd) * 127.5) + 0.5));
-            sal_uInt32 nSteps(getFillGradient().getSteps());
-
-            if(nSteps == 0)
-            {
-                nSteps = nMaxSteps;
-            }
-
-            if(nSteps < 2)
-            {
-                nSteps = 2;
-            }
-
-            if(nSteps > nMaxSteps)
-            {
-                nSteps = nMaxSteps;
-            }
-
-            nSteps = std::max(sal_uInt32(1), nSteps);
-
             switch(getFillGradient().getStyle())
             {
                 case attribute::GradientStyle::Linear:
@@ -67,9 +44,8 @@ namespace drawinglayer::primitive2d
                     texture::GeoTexSvxGradientLinear aGradient(
                         getDefinitionRange(),
                         getOutputRange(),
-                        aStart,
-                        aEnd,
-                        nSteps,
+                        getFillGradient().getSteps(),
+                        getFillGradient().getColorSteps(),
                         getFillGradient().getBorder(),
                         getFillGradient().getAngle());
                     aGradient.appendTransformationsAndColors(rEntries, 
rOuterColor);
@@ -80,9 +56,8 @@ namespace drawinglayer::primitive2d
                     texture::GeoTexSvxGradientAxial aGradient(
                         getDefinitionRange(),
                         getOutputRange(),
-                        aStart,
-                        aEnd,
-                        nSteps,
+                        getFillGradient().getSteps(),
+                        getFillGradient().getColorSteps(),
                         getFillGradient().getBorder(),
                         getFillGradient().getAngle());
                     aGradient.appendTransformationsAndColors(rEntries, 
rOuterColor);
@@ -92,9 +67,8 @@ namespace drawinglayer::primitive2d
                 {
                     texture::GeoTexSvxGradientRadial aGradient(
                         getDefinitionRange(),
-                        aStart,
-                        aEnd,
-                        nSteps,
+                        getFillGradient().getSteps(),
+                        getFillGradient().getColorSteps(),
                         getFillGradient().getBorder(),
                         getFillGradient().getOffsetX(),
                         getFillGradient().getOffsetY());
@@ -105,9 +79,8 @@ namespace drawinglayer::primitive2d
                 {
                     texture::GeoTexSvxGradientElliptical aGradient(
                         getDefinitionRange(),
-                        aStart,
-                        aEnd,
-                        nSteps,
+                        getFillGradient().getSteps(),
+                        getFillGradient().getColorSteps(),
                         getFillGradient().getBorder(),
                         getFillGradient().getOffsetX(),
                         getFillGradient().getOffsetY(),
@@ -119,9 +92,8 @@ namespace drawinglayer::primitive2d
                 {
                     texture::GeoTexSvxGradientSquare aGradient(
                         getDefinitionRange(),
-                        aStart,
-                        aEnd,
-                        nSteps,
+                        getFillGradient().getSteps(),
+                        getFillGradient().getColorSteps(),
                         getFillGradient().getBorder(),
                         getFillGradient().getOffsetX(),
                         getFillGradient().getOffsetY(),
@@ -133,9 +105,8 @@ namespace drawinglayer::primitive2d
                 {
                     texture::GeoTexSvxGradientRect aGradient(
                         getDefinitionRange(),
-                        aStart,
-                        aEnd,
-                        nSteps,
+                        getFillGradient().getSteps(),
+                        getFillGradient().getColorSteps(),
                         getFillGradient().getBorder(),
                         getFillGradient().getOffsetX(),
                         getFillGradient().getOffsetY(),
diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx 
b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
index b5989303dd43..d2f4a4cc08c5 100644
--- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
@@ -32,6 +32,7 @@
 #include <basegfx/polygon/b2dpolypolygontools.hxx>
 #include <basegfx/polygon/b2dpolygontools.hxx>
 #include <basegfx/polygon/b2dlinegeometry.hxx>
+#include <basegfx/utils/gradienttools.hxx>
 #include <vcl/virdev.hxx>
 #include <vcl/gdimtf.hxx>
 #include <vcl/gradient.hxx>
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx 
b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index 7a171b915524..7efb80db2dfb 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -28,6 +28,7 @@
 #include <vcl/canvastools.hxx>
 #include <basegfx/polygon/b2dpolygontools.hxx>
 #include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/utils/gradienttools.hxx>
 
 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
 #include <drawinglayer/primitive2d/Tools.hxx>
diff --git a/drawinglayer/source/processor3d/defaultprocessor3d.cxx 
b/drawinglayer/source/processor3d/defaultprocessor3d.cxx
index 6be8e78d0d59..caf31e9aa5dc 100644
--- a/drawinglayer/source/processor3d/defaultprocessor3d.cxx
+++ b/drawinglayer/source/processor3d/defaultprocessor3d.cxx
@@ -60,30 +60,10 @@ namespace drawinglayer::processor3d
             const attribute::FillGradientAttribute& rFillGradient = 
rPrimitive.getGradient();
             const basegfx::B2DRange aOutlineRange(0.0, 0.0, 
rPrimitive.getTextureSize().getX(), rPrimitive.getTextureSize().getY());
             const attribute::GradientStyle 
aGradientStyle(rFillGradient.getStyle());
-            sal_uInt32 nSteps(rFillGradient.getSteps());
-            const basegfx::BColor 
aStart(rFillGradient.getColorSteps().front().getColor());
-            const basegfx::BColor 
aEnd(rFillGradient.getColorSteps().back().getColor());
-            const sal_uInt32 
nMaxSteps(sal_uInt32((aStart.getMaximumDistance(aEnd) * 127.5) + 0.5));
             std::shared_ptr< texture::GeoTexSvx > pNewTex;
 
-            if(nMaxSteps)
+            if(!rFillGradient.hasSingleColor())
             {
-                // there IS a color distance
-                if(nSteps == 0)
-                {
-                    nSteps = nMaxSteps;
-                }
-
-                if(nSteps < 2)
-                {
-                    nSteps = 2;
-                }
-
-                if(nSteps > nMaxSteps)
-                {
-                    nSteps = nMaxSteps;
-                }
-
                 switch(aGradientStyle)
                 {
                     case attribute::GradientStyle::Linear:
@@ -91,9 +71,8 @@ namespace drawinglayer::processor3d
                         pNewTex = 
std::make_shared<texture::GeoTexSvxGradientLinear>(
                                 aOutlineRange,
                                 aOutlineRange,
-                                aStart,
-                                aEnd,
-                                nSteps,
+                                rFillGradient.getSteps(),
+                                rFillGradient.getColorSteps(),
                                 rFillGradient.getBorder(),
                                 rFillGradient.getAngle());
                         break;
@@ -103,9 +82,8 @@ namespace drawinglayer::processor3d
                         pNewTex = 
std::make_shared<texture::GeoTexSvxGradientAxial>(
                                 aOutlineRange,
                                 aOutlineRange,
-                                aStart,
-                                aEnd,
-                                nSteps,
+                                rFillGradient.getSteps(),
+                                rFillGradient.getColorSteps(),
                                 rFillGradient.getBorder(),
                                 rFillGradient.getAngle());
                         break;
@@ -115,9 +93,8 @@ namespace drawinglayer::processor3d
                         pNewTex =
                             std::make_shared<texture::GeoTexSvxGradientRadial>(
                                 aOutlineRange,
-                                aStart,
-                                aEnd,
-                                nSteps,
+                                rFillGradient.getSteps(),
+                                rFillGradient.getColorSteps(),
                                 rFillGradient.getBorder(),
                                 rFillGradient.getOffsetX(),
                                 rFillGradient.getOffsetY());
@@ -128,9 +105,8 @@ namespace drawinglayer::processor3d
                         pNewTex =
                             
std::make_shared<texture::GeoTexSvxGradientElliptical>(
                                 aOutlineRange,
-                                aStart,
-                                aEnd,
-                                nSteps,
+                                rFillGradient.getSteps(),
+                                rFillGradient.getColorSteps(),
                                 rFillGradient.getBorder(),
                                 rFillGradient.getOffsetX(),
                                 rFillGradient.getOffsetY(),
@@ -142,9 +118,8 @@ namespace drawinglayer::processor3d
                         pNewTex =
                             std::make_shared<texture::GeoTexSvxGradientSquare>(
                                 aOutlineRange,
-                                aStart,
-                                aEnd,
-                                nSteps,
+                                rFillGradient.getSteps(),
+                                rFillGradient.getColorSteps(),
                                 rFillGradient.getBorder(),
                                 rFillGradient.getOffsetX(),
                                 rFillGradient.getOffsetY(),
@@ -156,9 +131,8 @@ namespace drawinglayer::processor3d
                         pNewTex =
                             std::make_shared<texture::GeoTexSvxGradientRect>(
                                 aOutlineRange,
-                                aStart,
-                                aEnd,
-                                nSteps,
+                                rFillGradient.getSteps(),
+                                rFillGradient.getColorSteps(),
                                 rFillGradient.getBorder(),
                                 rFillGradient.getOffsetX(),
                                 rFillGradient.getOffsetY(),
@@ -171,7 +145,8 @@ namespace drawinglayer::processor3d
             }
             else
             {
-                // no color distance -> same color, use simple texture
+                // only one color, so no real gradient -> use simple texture
+                const basegfx::BColor 
aStart(rFillGradient.getColorSteps().front().getColor());
                 pNewTex = std::make_shared<texture::GeoTexSvxMono>(aStart, 1.0 
- aStart.luminance());
                 mbSimpleTextureActive = true;
             }
diff --git a/drawinglayer/source/texture/texture.cxx 
b/drawinglayer/source/texture/texture.cxx
index 4a92e443c275..623336187495 100644
--- a/drawinglayer/source/texture/texture.cxx
+++ b/drawinglayer/source/texture/texture.cxx
@@ -71,13 +71,13 @@ namespace drawinglayer::texture
 
         GeoTexSvxGradient::GeoTexSvxGradient(
             const basegfx::B2DRange& rDefinitionRange,
-            const basegfx::BColor& rStart,
-            const basegfx::BColor& rEnd,
+            sal_uInt32 nRequestedSteps,
+            const basegfx::ColorSteps& rColorSteps,
             double fBorder)
-        :   maDefinitionRange(rDefinitionRange),
-            maStart(rStart),
-            maEnd(rEnd),
-            mfBorder(fBorder)
+        : maDefinitionRange(rDefinitionRange)
+        , mnRequestedSteps(nRequestedSteps)
+        , mnColorSteps(rColorSteps)
+        , mfBorder(fBorder)
         {
         }
 
@@ -92,26 +92,26 @@ namespace drawinglayer::texture
             return (pCompare
                 && maGradientInfo == pCompare->maGradientInfo
                 && maDefinitionRange == pCompare->maDefinitionRange
+                && mnRequestedSteps == pCompare->mnRequestedSteps
+                && mnColorSteps == pCompare->mnColorSteps
                 && mfBorder == pCompare->mfBorder);
         }
 
-
         GeoTexSvxGradientLinear::GeoTexSvxGradientLinear(
             const basegfx::B2DRange& rDefinitionRange,
             const basegfx::B2DRange& rOutputRange,
-            const basegfx::BColor& rStart,
-            const basegfx::BColor& rEnd,
-            sal_uInt32 nSteps,
+            sal_uInt32 nRequestedSteps,
+            const basegfx::ColorSteps& rColorSteps,
             double fBorder,
             double fAngle)
-        :   GeoTexSvxGradient(rDefinitionRange, rStart, rEnd, fBorder),
-            mfUnitMinX(0.0),
-            mfUnitWidth(1.0),
-            mfUnitMaxY(1.0)
+        : GeoTexSvxGradient(rDefinitionRange, nRequestedSteps, rColorSteps, 
fBorder)
+        , mfUnitMinX(0.0)
+        , mfUnitWidth(1.0)
+        , mfUnitMaxY(1.0)
         {
             maGradientInfo = basegfx::utils::createLinearODFGradientInfo(
                 rDefinitionRange,
-                nSteps,
+                nRequestedSteps,
                 fBorder,
                 fAngle);
 
@@ -134,12 +134,16 @@ namespace drawinglayer::texture
             std::vector< B2DHomMatrixAndBColor >& rEntries,
             basegfx::BColor& rOuterColor)
         {
-            rOuterColor = maStart;
-
-            if(!maGradientInfo.getSteps())
+            if(mnColorSteps.size() <= 1)
                 return;
 
-            const double fStripeWidth(1.0 / maGradientInfo.getSteps());
+            const basegfx::BColor maStart(mnColorSteps.front().getColor());
+            const basegfx::BColor maEnd(mnColorSteps.back().getColor());
+            const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps(
+                maGradientInfo.getRequestedSteps(), maStart, maEnd));
+
+            rOuterColor = maStart;
+            const double fStripeWidth(1.0 / nSteps);
             B2DHomMatrixAndBColor aB2DHomMatrixAndBColor;
             basegfx::B2DHomMatrix aPattern;
 
@@ -151,7 +155,7 @@ namespace drawinglayer::texture
             aPattern.scale(mfUnitWidth, 1.0);
             aPattern.translate(mfUnitMinX, 0.0);
 
-            for(sal_uInt32 a(1); a < maGradientInfo.getSteps(); a++)
+            for(sal_uInt32 a(1); a < nSteps; a++)
             {
                 const double fPos(fStripeWidth * a);
                 basegfx::B2DHomMatrix aNew(aPattern);
@@ -159,7 +163,7 @@ namespace drawinglayer::texture
                 // scale and translate in Y
                 double fHeight(1.0 - fPos);
 
-                if(a + 1 == maGradientInfo.getSteps() && mfUnitMaxY > 1.0)
+                if(a + 1 == nSteps && mfUnitMaxY > 1.0)
                 {
                     fHeight += mfUnitMaxY - 1.0;
                 }
@@ -171,7 +175,7 @@ namespace drawinglayer::texture
                 aB2DHomMatrixAndBColor.maB2DHomMatrix = 
maGradientInfo.getTextureTransform() * aNew;
 
                 // interpolate and set color
-                aB2DHomMatrixAndBColor.maBColor = interpolate(maStart, maEnd, 
double(a) / double(maGradientInfo.getSteps() - 1));
+                aB2DHomMatrixAndBColor.maBColor = interpolate(maStart, maEnd, 
double(a) / double(nSteps - 1));
 
                 rEntries.push_back(aB2DHomMatrixAndBColor);
             }
@@ -179,26 +183,35 @@ namespace drawinglayer::texture
 
         void GeoTexSvxGradientLinear::modifyBColor(const basegfx::B2DPoint& 
rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const
         {
-            const double fScaler(basegfx::utils::getLinearGradientAlpha(rUV, 
maGradientInfo));
+            if(mnColorSteps.size() <= 1)
+            {
+                rBColor = mnColorSteps.front().getColor();
+            }
+            else
+            {
+                const double 
fScaler(basegfx::utils::getLinearGradientAlpha(rUV, maGradientInfo));
+
+                const basegfx::BColor maStart(mnColorSteps.front().getColor());
+                const basegfx::BColor maEnd(mnColorSteps.back().getColor());
 
-            rBColor = basegfx::interpolate(maStart, maEnd, fScaler);
+                rBColor = basegfx::interpolate(maStart, maEnd, fScaler);
+            }
         }
 
         GeoTexSvxGradientAxial::GeoTexSvxGradientAxial(
             const basegfx::B2DRange& rDefinitionRange,
             const basegfx::B2DRange& rOutputRange,
-            const basegfx::BColor& rStart,
-            const basegfx::BColor& rEnd,
-            sal_uInt32 nSteps,
+            sal_uInt32 nRequestedSteps,
+            const basegfx::ColorSteps& rColorSteps,
             double fBorder,
             double fAngle)
-        :   GeoTexSvxGradient(rDefinitionRange, rStart, rEnd, fBorder),
-            mfUnitMinX(0.0),
-            mfUnitWidth(1.0)
+        : GeoTexSvxGradient(rDefinitionRange, nRequestedSteps, rColorSteps, 
fBorder)
+        , mfUnitMinX(0.0)
+        , mfUnitWidth(1.0)
         {
             maGradientInfo = basegfx::utils::createAxialODFGradientInfo(
                 rDefinitionRange,
-                nSteps,
+                nRequestedSteps,
                 fBorder,
                 fAngle);
 
@@ -220,15 +233,19 @@ namespace drawinglayer::texture
             std::vector< B2DHomMatrixAndBColor >& rEntries,
             basegfx::BColor& rOuterColor)
         {
-            rOuterColor = maEnd;
-
-            if(!maGradientInfo.getSteps())
+            if(mnColorSteps.size() <= 1)
                 return;
 
-            const double fStripeWidth(1.0 / maGradientInfo.getSteps());
+            const basegfx::BColor maStart(mnColorSteps.front().getColor());
+            const basegfx::BColor maEnd(mnColorSteps.back().getColor());
+            const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps(
+                maGradientInfo.getRequestedSteps(), maStart, maEnd));
+
+            rOuterColor = maEnd;
+            const double fStripeWidth(1.0 / nSteps);
             B2DHomMatrixAndBColor aB2DHomMatrixAndBColor;
 
-            for(sal_uInt32 a(1); a < maGradientInfo.getSteps(); a++)
+            for(sal_uInt32 a(1); a < nSteps; a++)
             {
                 const double fPos(fStripeWidth * a);
                 basegfx::B2DHomMatrix aNew;
@@ -248,7 +265,7 @@ namespace drawinglayer::texture
                 aB2DHomMatrixAndBColor.maB2DHomMatrix = 
maGradientInfo.getTextureTransform() * aNew;
 
                 // interpolate and set color
-                aB2DHomMatrixAndBColor.maBColor = interpolate(maEnd, maStart, 
double(a) / double(maGradientInfo.getSteps() - 1));
+                aB2DHomMatrixAndBColor.maBColor = interpolate(maEnd, maStart, 
double(a) / double(nSteps - 1));
 
                 rEntries.push_back(aB2DHomMatrixAndBColor);
             }
@@ -256,26 +273,35 @@ namespace drawinglayer::texture
 
         void GeoTexSvxGradientAxial::modifyBColor(const basegfx::B2DPoint& 
rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const
         {
-            const double fScaler(basegfx::utils::getAxialGradientAlpha(rUV, 
maGradientInfo));
+            if(mnColorSteps.size() <= 1)
+            {
+                rBColor = mnColorSteps.front().getColor();
+            }
+            else
+            {
+                const double 
fScaler(basegfx::utils::getAxialGradientAlpha(rUV, maGradientInfo));
+
+                const basegfx::BColor maStart(mnColorSteps.front().getColor());
+                const basegfx::BColor maEnd(mnColorSteps.back().getColor());
 
-            rBColor = basegfx::interpolate(maStart, maEnd, fScaler);
+                rBColor = basegfx::interpolate(maStart, maEnd, fScaler);
+            }
         }
 
 
         GeoTexSvxGradientRadial::GeoTexSvxGradientRadial(
             const basegfx::B2DRange& rDefinitionRange,
-            const basegfx::BColor& rStart,
-            const basegfx::BColor& rEnd,
-            sal_uInt32 nSteps,
+            sal_uInt32 nRequestedSteps,
+            const basegfx::ColorSteps& rColorSteps,
             double fBorder,
             double fOffsetX,
             double fOffsetY)
-        :   GeoTexSvxGradient(rDefinitionRange, rStart, rEnd, fBorder)
+        : GeoTexSvxGradient(rDefinitionRange, nRequestedSteps, rColorSteps, 
fBorder)
         {
             maGradientInfo = basegfx::utils::createRadialODFGradientInfo(
                 rDefinitionRange,
                 basegfx::B2DVector(fOffsetX,fOffsetY),
-                nSteps,
+                nRequestedSteps,
                 fBorder);
         }
 
@@ -287,46 +313,59 @@ namespace drawinglayer::texture
             std::vector< B2DHomMatrixAndBColor >& rEntries,
             basegfx::BColor& rOuterColor)
         {
-            rOuterColor = maStart;
-
-            if(!maGradientInfo.getSteps())
+            if(mnColorSteps.size() <= 1)
                 return;
 
-            const double fStepSize(1.0 / maGradientInfo.getSteps());
+            const basegfx::BColor maStart(mnColorSteps.front().getColor());
+            const basegfx::BColor maEnd(mnColorSteps.back().getColor());
+            const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps(
+                maGradientInfo.getRequestedSteps(), maStart, maEnd));
+
+            rOuterColor = maStart;
+            const double fStepSize(1.0 / nSteps);
             B2DHomMatrixAndBColor aB2DHomMatrixAndBColor;
 
-            for(sal_uInt32 a(1); a < maGradientInfo.getSteps(); a++)
+            for(sal_uInt32 a(1); a < nSteps; a++)
             {
                 const double fSize(1.0 - (fStepSize * a));
                 aB2DHomMatrixAndBColor.maB2DHomMatrix = 
maGradientInfo.getTextureTransform() * 
basegfx::utils::createScaleB2DHomMatrix(fSize, fSize);
-                aB2DHomMatrixAndBColor.maBColor = interpolate(maStart, maEnd, 
double(a) / double(maGradientInfo.getSteps() - 1));
+                aB2DHomMatrixAndBColor.maBColor = interpolate(maStart, maEnd, 
double(a) / double(nSteps - 1));
                 rEntries.push_back(aB2DHomMatrixAndBColor);
             }
         }
 
         void GeoTexSvxGradientRadial::modifyBColor(const basegfx::B2DPoint& 
rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const
         {
-            const double fScaler(basegfx::utils::getRadialGradientAlpha(rUV, 
maGradientInfo));
+            if(mnColorSteps.size() <= 1)
+            {
+                rBColor = mnColorSteps.front().getColor();
+            }
+            else
+            {
+                const double 
fScaler(basegfx::utils::getRadialGradientAlpha(rUV, maGradientInfo));
+
+                const basegfx::BColor maStart(mnColorSteps.front().getColor());
+                const basegfx::BColor maEnd(mnColorSteps.back().getColor());
 
-            rBColor = basegfx::interpolate(maStart, maEnd, fScaler);
+                rBColor = basegfx::interpolate(maStart, maEnd, fScaler);
+            }
         }
 
 
         GeoTexSvxGradientElliptical::GeoTexSvxGradientElliptical(
             const basegfx::B2DRange& rDefinitionRange,
-            const basegfx::BColor& rStart,
-            const basegfx::BColor& rEnd,
-            sal_uInt32 nSteps,
+            sal_uInt32 nRequestedSteps,
+            const basegfx::ColorSteps& rColorSteps,
             double fBorder,
             double fOffsetX,
             double fOffsetY,
             double fAngle)
-        :   GeoTexSvxGradient(rDefinitionRange, rStart, rEnd, fBorder)
+        : GeoTexSvxGradient(rDefinitionRange, nRequestedSteps, rColorSteps, 
fBorder)
         {
             maGradientInfo = basegfx::utils::createEllipticalODFGradientInfo(
                 rDefinitionRange,
                 basegfx::B2DVector(fOffsetX,fOffsetY),
-                nSteps,
+                nRequestedSteps,
                 fBorder,
                 fAngle);
         }
@@ -339,11 +378,15 @@ namespace drawinglayer::texture
             std::vector< B2DHomMatrixAndBColor >& rEntries,
             basegfx::BColor& rOuterColor)
         {
-            rOuterColor = maStart;
-
-            if(!maGradientInfo.getSteps())
+            if(mnColorSteps.size() <= 1)
                 return;
 
+            const basegfx::BColor maStart(mnColorSteps.front().getColor());
+            const basegfx::BColor maEnd(mnColorSteps.back().getColor());
+            const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps(
+                maGradientInfo.getRequestedSteps(), maStart, maEnd));
+
+            rOuterColor = maStart;
             double fWidth(1.0);
             double fHeight(1.0);
             double fIncrementX(0.0);
@@ -351,52 +394,61 @@ namespace drawinglayer::texture
 
             if(maGradientInfo.getAspectRatio() > 1.0)
             {
-                fIncrementY = fHeight / maGradientInfo.getSteps();
+                fIncrementY = fHeight / nSteps;
                 fIncrementX = fIncrementY / maGradientInfo.getAspectRatio();
             }
             else
             {
-                fIncrementX = fWidth / maGradientInfo.getSteps();
+                fIncrementX = fWidth / nSteps;
                 fIncrementY = fIncrementX * maGradientInfo.getAspectRatio();
             }
 
             B2DHomMatrixAndBColor aB2DHomMatrixAndBColor;
 
-            for(sal_uInt32 a(1); a < maGradientInfo.getSteps(); a++)
+            for(sal_uInt32 a(1); a < nSteps; a++)
             {
                 // next step
                 fWidth -= fIncrementX;
                 fHeight -= fIncrementY;
 
                 aB2DHomMatrixAndBColor.maB2DHomMatrix = 
maGradientInfo.getTextureTransform() * 
basegfx::utils::createScaleB2DHomMatrix(fWidth, fHeight);
-                aB2DHomMatrixAndBColor.maBColor = interpolate(maStart, maEnd, 
double(a) / double(maGradientInfo.getSteps() - 1));
+                aB2DHomMatrixAndBColor.maBColor = interpolate(maStart, maEnd, 
double(a) / double(nSteps - 1));
                 rEntries.push_back(aB2DHomMatrixAndBColor);
             }
         }
 
         void GeoTexSvxGradientElliptical::modifyBColor(const 
basegfx::B2DPoint& rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const
         {
-            const double 
fScaler(basegfx::utils::getEllipticalGradientAlpha(rUV, maGradientInfo));
+            if(mnColorSteps.size() <= 1)
+            {
+                rBColor = mnColorSteps.front().getColor();
+            }
+            else
+            {
+                const double 
fScaler(basegfx::utils::getEllipticalGradientAlpha(rUV, maGradientInfo));
 
-            rBColor = basegfx::interpolate(maStart, maEnd, fScaler);
+                const basegfx::BColor maStart(mnColorSteps.front().getColor());
+                const basegfx::BColor maEnd(mnColorSteps.back().getColor());
+
+                rBColor = basegfx::interpolate(maStart, maEnd, fScaler);
+            }
         }
 
 
         GeoTexSvxGradientSquare::GeoTexSvxGradientSquare(
             const basegfx::B2DRange& rDefinitionRange,
-            const basegfx::BColor& rStart,
-            const basegfx::BColor& rEnd,
-            sal_uInt32 nSteps,
+            sal_uInt32 nRequestedSteps,
+            const basegfx::ColorSteps& rColorSteps,
             double fBorder,
             double fOffsetX,
             double fOffsetY,
             double fAngle)
-        :   GeoTexSvxGradient(rDefinitionRange, rStart, rEnd, fBorder)
+        : GeoTexSvxGradient(rDefinitionRange, nRequestedSteps, rColorSteps, 
fBorder)
         {
             maGradientInfo = basegfx::utils::createSquareODFGradientInfo(
                 rDefinitionRange,
                 basegfx::B2DVector(fOffsetX,fOffsetY),
-                nSteps,
+                nRequestedSteps,
                 fBorder,
                 fAngle);
         }
@@ -409,46 +461,59 @@ namespace drawinglayer::texture
             std::vector< B2DHomMatrixAndBColor >& rEntries,
             basegfx::BColor& rOuterColor)
         {
-            rOuterColor = maStart;
-
-            if(!maGradientInfo.getSteps())
+            if(mnColorSteps.size() <= 1)
                 return;
 
-            const double fStepSize(1.0 / maGradientInfo.getSteps());
+            const basegfx::BColor maStart(mnColorSteps.front().getColor());
+            const basegfx::BColor maEnd(mnColorSteps.back().getColor());
+            const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps(
+                maGradientInfo.getRequestedSteps(), maStart, maEnd));
+
+            rOuterColor = maStart;
+            const double fStepSize(1.0 / nSteps);
             B2DHomMatrixAndBColor aB2DHomMatrixAndBColor;
 
-            for(sal_uInt32 a(1); a < maGradientInfo.getSteps(); a++)
+            for(sal_uInt32 a(1); a < nSteps; a++)
             {
                 const double fSize(1.0 - (fStepSize * a));
                 aB2DHomMatrixAndBColor.maB2DHomMatrix = 
maGradientInfo.getTextureTransform() * 
basegfx::utils::createScaleB2DHomMatrix(fSize, fSize);
-                aB2DHomMatrixAndBColor.maBColor = interpolate(maStart, maEnd, 
double(a) / double(maGradientInfo.getSteps() - 1));
+                aB2DHomMatrixAndBColor.maBColor = interpolate(maStart, maEnd, 
double(a) / double(nSteps - 1));
                 rEntries.push_back(aB2DHomMatrixAndBColor);
             }
         }
 
         void GeoTexSvxGradientSquare::modifyBColor(const basegfx::B2DPoint& 
rUV, basegfx::BColor& rBColor, double& /*rfOpacity*/) const
         {
-            const double fScaler(basegfx::utils::getSquareGradientAlpha(rUV, 
maGradientInfo));
+            if(mnColorSteps.size() <= 1)
+            {
+                rBColor = mnColorSteps.front().getColor();
+            }
+            else
+            {
+                const double 
fScaler(basegfx::utils::getSquareGradientAlpha(rUV, maGradientInfo));
+
+                const basegfx::BColor maStart(mnColorSteps.front().getColor());
+                const basegfx::BColor maEnd(mnColorSteps.back().getColor());
 
-            rBColor = basegfx::interpolate(maStart, maEnd, fScaler);
+                rBColor = basegfx::interpolate(maStart, maEnd, fScaler);
+            }
         }
 
 
         GeoTexSvxGradientRect::GeoTexSvxGradientRect(
             const basegfx::B2DRange& rDefinitionRange,
-            const basegfx::BColor& rStart,
-            const basegfx::BColor& rEnd,
-            sal_uInt32 nSteps,
+            sal_uInt32 nRequestedSteps,
+            const basegfx::ColorSteps& rColorSteps,
             double fBorder,
             double fOffsetX,
             double fOffsetY,
             double fAngle)
-        :   GeoTexSvxGradient(rDefinitionRange, rStart, rEnd, fBorder)
+        : GeoTexSvxGradient(rDefinitionRange, nRequestedSteps, rColorSteps, 
fBorder)
         {
             maGradientInfo = basegfx::utils::createRectangularODFGradientInfo(
                 rDefinitionRange,
                 basegfx::B2DVector(fOffsetX,fOffsetY),
-                nSteps,
+                nRequestedSteps,
                 fBorder,
                 fAngle);
         }
@@ -461,11 +526,15 @@ namespace drawinglayer::texture
             std::vector< B2DHomMatrixAndBColor >& rEntries,
             basegfx::BColor& rOuterColor)
         {
-            rOuterColor = maStart;
-
-            if(!maGradientInfo.getSteps())
+            if(mnColorSteps.size() <= 1)
                 return;
 
+            const basegfx::BColor maStart(mnColorSteps.front().getColor());
+            const basegfx::BColor maEnd(mnColorSteps.back().getColor());
+            const sal_uInt32 nSteps(basegfx::utils::calculateNumberOfSteps(
+                maGradientInfo.getRequestedSteps(), maStart, maEnd));
+
+            rOuterColor = maStart;
             double fWidth(1.0);
             double fHeight(1.0);
             double fIncrementX(0.0);
@@ -473,34 +542,44 @@ namespace drawinglayer::texture
 
             if(maGradientInfo.getAspectRatio() > 1.0)
             {
-                fIncrementY = fHeight / maGradientInfo.getSteps();
+                fIncrementY = fHeight / nSteps;
                 fIncrementX = fIncrementY / maGradientInfo.getAspectRatio();
             }
             else
             {
-                fIncrementX = fWidth / maGradientInfo.getSteps();
+                fIncrementX = fWidth / nSteps;
                 fIncrementY = fIncrementX * maGradientInfo.getAspectRatio();
             }
 
             B2DHomMatrixAndBColor aB2DHomMatrixAndBColor;
 
-            for(sal_uInt32 a(1); a < maGradientInfo.getSteps(); a++)
+            for(sal_uInt32 a(1); a < nSteps; a++)
             {
                 // next step
                 fWidth -= fIncrementX;
                 fHeight -= fIncrementY;
 
                 aB2DHomMatrixAndBColor.maB2DHomMatrix = 
maGradientInfo.getTextureTransform() * 
basegfx::utils::createScaleB2DHomMatrix(fWidth, fHeight);
-                aB2DHomMatrixAndBColor.maBColor = interpolate(maStart, maEnd, 
double(a) / double(maGradientInfo.getSteps() - 1));
+                aB2DHomMatrixAndBColor.maBColor = interpolate(maStart, maEnd, 
double(a) / double(nSteps - 1));
                 rEntries.push_back(aB2DHomMatrixAndBColor);
             }
         }
 
         void GeoTexSvxGradientRect::modifyBColor(const basegfx::B2DPoint& rUV, 
basegfx::BColor& rBColor, double& /*rfOpacity*/) const
         {
-            const double 
fScaler(basegfx::utils::getRectangularGradientAlpha(rUV, maGradientInfo));
+            if(mnColorSteps.size() <= 1)
+            {
+                rBColor = mnColorSteps.front().getColor();
+            }
+            else
+            {
+                const double 
fScaler(basegfx::utils::getRectangularGradientAlpha(rUV, maGradientInfo));
+
+                const basegfx::BColor maStart(mnColorSteps.front().getColor());
+                const basegfx::BColor maEnd(mnColorSteps.back().getColor());
 
-            rBColor = basegfx::interpolate(maStart, maEnd, fScaler);
+                rBColor = basegfx::interpolate(maStart, maEnd, fScaler);
+            }
         }
 
 
diff --git a/drawinglayer/source/tools/primitive2dxmldump.cxx 
b/drawinglayer/source/tools/primitive2dxmldump.cxx
index 65967980d110..55d2c6a8e29a 100644
--- a/drawinglayer/source/tools/primitive2dxmldump.cxx
+++ b/drawinglayer/source/tools/primitive2dxmldump.cxx
@@ -44,6 +44,7 @@
 
 #include <basegfx/polygon/b2dpolypolygontools.hxx>
 #include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/utils/gradienttools.hxx>
 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
 #include <toolkit/helper/vclunohelper.hxx>
 
diff --git a/drawinglayer/source/tools/wmfemfhelper.cxx 
b/drawinglayer/source/tools/wmfemfhelper.cxx
index 21a88757c954..0189c621fda3 100644
--- a/drawinglayer/source/tools/wmfemfhelper.cxx
+++ b/drawinglayer/source/tools/wmfemfhelper.cxx
@@ -23,6 +23,7 @@
 #include <vcl/metaact.hxx>
 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
 #include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/utils/gradienttools.hxx>
 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
 #include <drawinglayer/primitive2d/PolygonStrokePrimitive2D.hxx>
 #include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
diff --git a/include/basegfx/utils/gradienttools.hxx 
b/include/basegfx/utils/gradienttools.hxx
index 03892122b54b..289fc730b790 100644
--- a/include/basegfx/utils/gradienttools.hxx
+++ b/include/basegfx/utils/gradienttools.hxx
@@ -23,13 +23,75 @@
 #include <basegfx/point/b2dpoint.hxx>
 #include <basegfx/vector/b2dvector.hxx>
 #include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/color/bcolor.hxx>
 #include <utility>
 #include <basegfx/basegfxdllapi.h>
+#include <vector>
 
 namespace basegfx { class B2DRange; }
 
 namespace basegfx
 {
+    /* MCGR: Provide ColorStep definition
+
+        This is the needed combination of offset and color:
+
+        Offset is defined as:
+        - being in the range of [0.0 .. 1.0] (unit range)
+          - 0.0 being reserved for StartColor
+          - 1.0 being reserved for EndColor
+        - in-between offsets thus being in the range of ]0.0 .. 1.0[
+        - no two equal offsets are allowed
+            - this is an error
+        - missing 1.0 entry (EndColor) is allowed
+          - it means that EndColor == StartColor
+        - at least one value (usually 0.0, StartColor) is required
+            - this allows to avoid massive testing in all places where
+              this data has to be accessed
+
+        Color is defined as:
+        - RGB with unit values [0.0 .. 1.0]
+
+        These definitions are packed in a std::vector<ColorStep> ColorSteps,
+        see typedef below.
+    */
+    class UNLESS_MERGELIBS(BASEGFX_DLLPUBLIC) ColorStep
+    {
+    private:
+        double mfOffset;
+        BColor maColor;
+
+    public:
+        // constructor - defaults are needed to have a default constructor
+        // e.g. for usage in std::vector::insert
+        ColorStep(double fOffset = 0.0, const BColor& rColor = BColor())
+            : mfOffset(fOffset)
+            , maColor(rColor)
+        {
+        }
+
+        double getOffset() const { return mfOffset; }
+        const BColor& getColor() const { return maColor; }
+
+        bool operator<(const ColorStep& rCandidate) const
+        {
+            return getOffset() < rCandidate.getOffset();
+        }
+
+        bool operator==(const ColorStep& rCandidate) const
+        {
+            return getOffset() == rCandidate.getOffset() && getColor() == 
rCandidate.getColor();
+        }
+    };
+
+    /* MCGR: Provide ColorSteps definition to the FillGradientAttribute
+
+        This array is sorted ascending by offsets, from lowest to
+        highest. Since all this primitive data definition is read-only,
+        this can be guaranteed by forcing/checking this in the constructor.
+    */
+    typedef std::vector<ColorStep> ColorSteps;
+
     /** Gradient definition as used in ODF 1.2
 
         This struct collects all data necessary for rendering ODF
@@ -63,22 +125,22 @@ namespace basegfx
            the semantic differs slightly for the different gradient
            types.
          */
-        sal_uInt32      mnSteps;
+        sal_uInt32      mnRequestedSteps;
 
     public:
         ODFGradientInfo()
         :   mfAspectRatio(1.0),
-            mnSteps(0)
+            mnRequestedSteps(0)
         {
         }
 
         ODFGradientInfo(
             B2DHomMatrix aTextureTransform,
             double fAspectRatio,
-            sal_uInt32 nSteps)
+            sal_uInt32 nRequestedSteps)
         :   maTextureTransform(std::move(aTextureTransform)),
             mfAspectRatio(fAspectRatio),
-            mnSteps(nSteps)
+            mnRequestedSteps(nRequestedSteps)
         {
         }
 
@@ -86,7 +148,7 @@ namespace basegfx
         :   maTextureTransform(rODFGradientInfo.getTextureTransform()),
             maBackTextureTransform(rODFGradientInfo.maBackTextureTransform),
             mfAspectRatio(rODFGradientInfo.getAspectRatio()),
-            mnSteps(rODFGradientInfo.getSteps())
+            mnRequestedSteps(rODFGradientInfo.getRequestedSteps())
         {
         }
 
@@ -95,7 +157,7 @@ namespace basegfx
             maTextureTransform = rODFGradientInfo.getTextureTransform();
             maBackTextureTransform = rODFGradientInfo.maBackTextureTransform;
             mfAspectRatio = rODFGradientInfo.getAspectRatio();
-            mnSteps = rODFGradientInfo.getSteps();
+            mnRequestedSteps = rODFGradientInfo.getRequestedSteps();
 
             return *this;
         }
@@ -106,7 +168,7 @@ namespace basegfx
         const B2DHomMatrix& getTextureTransform() const { return 
maTextureTransform; }
         const B2DHomMatrix& getBackTextureTransform() const;
         double getAspectRatio() const { return mfAspectRatio; }
-        sal_uInt32 getSteps() const { return mnSteps; }
+        sal_uInt32 getRequestedSteps() const { return mnRequestedSteps; }
 
         void setTextureTransform(const B2DHomMatrix& rNew)
         {
@@ -117,6 +179,21 @@ namespace basegfx
 
     namespace utils
     {
+        /* Helper to calculate numberOfSteps needed to represent
+           gradient for the given two colors:
+           - to define only based on color distance, give 0 == nRequestedSteps
+               as wanted value, so color distance will be used
+           - if a wanted value of nRequestedSteps is given, it gets synched
+               against the maximum number of steps defined by the color
+               distance of the two colors
+           - a minimum result of 1 is returned which means a single
+               step -> no real gradient
+        */
+        BASEGFX_DLLPUBLIC sal_uInt32 calculateNumberOfSteps(
+            sal_uInt32 nRequestedSteps,
+            const BColor& rStart,
+            const BColor& rEnd);
+
         /** Create matrix for ODF's linear gradient definition
 
             Note that odf linear gradients are varying in y direction.
@@ -129,7 +206,7 @@ namespace basegfx
             Output area, needed for aspect ratio calculations and
             texture transformation
 
-            @param nSteps
+            @param nRequestedSteps
             Number of gradient steps (from ODF)
 
             @param fBorder
@@ -140,7 +217,7 @@ namespace basegfx
          */
         BASEGFX_DLLPUBLIC ODFGradientInfo createLinearODFGradientInfo(
             const B2DRange& rTargetArea,
-            sal_uInt32 nSteps,
+            sal_uInt32 nRequestedSteps,
             double fBorder,
             double fAngle);
 
@@ -179,7 +256,7 @@ namespace basegfx
             Output area, needed for aspect ratio calculations and
             texture transformation
 
-            @param nSteps
+            @param nRequestedSteps
             Number of gradient steps (from ODF)
 
             @param fBorder
@@ -190,7 +267,7 @@ namespace basegfx
          */
         BASEGFX_DLLPUBLIC ODFGradientInfo createAxialODFGradientInfo(
             const B2DRange& rTargetArea,
-            sal_uInt32 nSteps,
+            sal_uInt32 nRequestedSteps,
             double fBorder,
             double fAngle);
 
@@ -224,7 +301,7 @@ namespace basegfx
             @param rOffset
             Gradient offset value (from ODF)
 
-            @param nSteps
+            @param nRequestedSteps
             Number of gradient steps (from ODF)
 
             @param fBorder
@@ -236,7 +313,7 @@ namespace basegfx
         BASEGFX_DLLPUBLIC ODFGradientInfo createRadialODFGradientInfo(
             const B2DRange& rTargetArea,
             const B2DVector& rOffset,
-            sal_uInt32 nSteps,
+            sal_uInt32 nRequestedSteps,
             double fBorder);
 
 
@@ -269,7 +346,7 @@ namespace basegfx
             @param rOffset
             Gradient offset value (from ODF)
 
-            @param nSteps
+            @param nRequestedSteps
             Number of gradient steps (from ODF)
 
             @param fBorder
@@ -281,7 +358,7 @@ namespace basegfx
         BASEGFX_DLLPUBLIC ODFGradientInfo createEllipticalODFGradientInfo(
             const B2DRange& rTargetArea,
             const B2DVector& rOffset,
-            sal_uInt32 nSteps,
+            sal_uInt32 nRequestedSteps,
             double fBorder,
             double fAngle);
 
@@ -315,7 +392,7 @@ namespace basegfx
             @param rOffset
             Gradient offset value (from ODF)
 
-            @param nSteps
+            @param nRequestedSteps
             Number of gradient steps (from ODF)
 
             @param fBorder
@@ -327,7 +404,7 @@ namespace basegfx
         BASEGFX_DLLPUBLIC ODFGradientInfo createSquareODFGradientInfo(
             const B2DRange& rTargetArea,
             const B2DVector& rOffset,
-            sal_uInt32 nSteps,
+            sal_uInt32 nRequestedSteps,
             double fBorder,
             double fAngle);
 
@@ -361,7 +438,7 @@ namespace basegfx
             @param rOffset
             Gradient offset value (from ODF)
 
-            @param nSteps
+            @param nRequestedSteps
             Number of gradient steps (from ODF)
 
             @param fBorder
@@ -373,7 +450,7 @@ namespace basegfx
         BASEGFX_DLLPUBLIC ODFGradientInfo createRectangularODFGradientInfo(
             const B2DRange& rTargetArea,
             const B2DVector& rOffset,
-            sal_uInt32 nSteps,
+            sal_uInt32 nRequestedSteps,
             double fBorder,
             double fAngle);
 
diff --git a/include/drawinglayer/attribute/fillgradientattribute.hxx 
b/include/drawinglayer/attribute/fillgradientattribute.hxx
index 7a10806b1e9f..4b736e678181 100644
--- a/include/drawinglayer/attribute/fillgradientattribute.hxx
+++ b/include/drawinglayer/attribute/fillgradientattribute.hxx
@@ -21,9 +21,15 @@
 
 #include <drawinglayer/drawinglayerdllapi.h>
 #include <o3tl/cow_wrapper.hxx>
-#include <basegfx/color/bcolor.hxx>
 #include <vector>
 
+namespace basegfx
+{
+class ColorStep;
+class BColor;
+typedef std::vector<ColorStep> ColorSteps;
+}
+
 namespace drawinglayer::attribute
 {
 class ImpFillGradientAttribute;
@@ -43,60 +49,6 @@ class DRAWINGLAYER_DLLPUBLIC FillGradientAttribute
 public:
     typedef o3tl::cow_wrapper<ImpFillGradientAttribute> ImplType;
 
-    /* MCGR: Provide ColorSteps to the FillGradientAttribute
-
-       This is the needed combination of offset and color:
-
-       Offset is defined as:
-       - being in the range of [0.0 .. 1.0] (unit range)
-       - 0.0 being reserved for StartColor
-       - 1.0 being reserved for EndColor
-       - in-between offsets thus being in the range of ]0.0 .. 1.0[
-       - no two equal offsets are allowed
-         - this is an error, but will be ignored (maybe assert?)
-       - missing 1.0 entry (EndColor) is allowed
-       - at least one value (usually 0.0, StartColor) is required
-         - this allows to avoid massive testing in all places where
-           this data has to be accessed
-
-       Color is defined as:
-       - RGB with unit values [0.0 .. 1.0]
-
-       These definitions are packed in a std::vector<ColorStep> ColorSteps,
-       see typedef below. This array is sorted ascending by offsets, from
-       lowest to highest. Since all this primitive data definition is
-       read-only, this can be guaranteed by forcing/checking this in the
-       constructor.
-    */
-    class ColorStep
-    {
-    private:
-        double mfOffset;
-        basegfx::BColor maColor;
-
-    public:
-        ColorStep(double fOffset, const basegfx::BColor& rColor)
-            : mfOffset(fOffset)
-            , maColor(rColor)
-        {
-        }
-
-        double getOffset() const { return mfOffset; }
-        const basegfx::BColor& getColor() const { return maColor; }
-
-        bool operator<(const ColorStep& rCandidate) const
-        {
-            return getOffset() < rCandidate.getOffset();
-        }
-
-        bool operator==(const ColorStep& rCandidate) const
-        {
-            return getOffset() == rCandidate.getOffset() && getColor() == 
rCandidate.getColor();
-        }
-    };
-
-    typedef std::vector<ColorStep> ColorSteps;
-
 private:
     ImplType mpFillGradientAttribute;
 
@@ -123,8 +75,8 @@ public:
     /// constructors/assignmentoperator/destructor
     FillGradientAttribute(GradientStyle eStyle, double fBorder, double 
fOffsetX, double fOffsetY,
                           double fAngle, const basegfx::BColor& rStartColor,
-                          const basegfx::BColor& rEndColor, const ColorSteps* 
pColorSteps = nullptr,
-                          sal_uInt16 nSteps = 0);
+                          const basegfx::BColor& rEndColor,
+                          const basegfx::ColorSteps* pColorSteps = nullptr, 
sal_uInt16 nSteps = 0);
     FillGradientAttribute();
     FillGradientAttribute(const FillGradientAttribute&);
     FillGradientAttribute(FillGradientAttribute&&);
@@ -147,7 +99,7 @@ public:
     double getOffsetX() const;
     double getOffsetY() const;
     double getAngle() const;
-    const ColorSteps& getColorSteps() const;
+    const basegfx::ColorSteps& getColorSteps() const;
     sal_uInt16 getSteps() const;
 };
 
diff --git a/svx/source/sdr/attribute/sdrallfillattributeshelper.cxx 
b/svx/source/sdr/attribute/sdrallfillattributeshelper.cxx
index e7bd26ce4f4f..720adcf26a78 100644
--- a/svx/source/sdr/attribute/sdrallfillattributeshelper.cxx
+++ b/svx/source/sdr/attribute/sdrallfillattributeshelper.cxx
@@ -21,6 +21,7 @@
 #include <sdr/primitive2d/sdrdecompositiontools.hxx>
 #include <basegfx/polygon/b2dpolygontools.hxx>
 #include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/utils/gradienttools.hxx>
 #include <drawinglayer/attribute/fillhatchattribute.hxx>
 #include <drawinglayer/attribute/sdrfillgraphicattribute.hxx>
 #include <vcl/graph.hxx>
diff --git a/svx/source/sdr/primitive2d/sdrattributecreator.cxx 
b/svx/source/sdr/primitive2d/sdrattributecreator.cxx
index f79ea50e5a88..434be3ee3197 100644
--- a/svx/source/sdr/primitive2d/sdrattributecreator.cxx
+++ b/svx/source/sdr/primitive2d/sdrattributecreator.cxx
@@ -61,6 +61,7 @@
 #include <vcl/svapp.hxx>
 #include <vcl/GraphicLoader.hxx>
 #include <basegfx/range/b2drange.hxx>
+#include <basegfx/utils/gradienttools.hxx>
 #include <svx/svx3ditems.hxx>
 #include <com/sun/star/drawing/ProjectionMode.hpp>
 #include <com/sun/star/drawing/ShadeMode.hpp>
@@ -492,6 +493,16 @@ namespace drawinglayer::primitive2d
                                 aEnd = interpolate(aBlack, aEnd, 
static_cast<double>(nEndIntens) * 0.01);
                             }
 
+                            basegfx::ColorSteps aColorSteps;
+
+                            // test code here, will be removed later
+                            // if(false)
+                            // {
+                            //     aStart = basegfx::BColor(1.0, 0.0, 0.0); // 
red
+                            //     aEnd = basegfx::BColor(0.0, 0.0, 1.0); // 
blue
+                            //     aColorSteps.emplace_back(0.25, 
basegfx::BColor(0.0, 1.0, 0.0)); // green@25%
+                            // }
+
                             aGradient = attribute::FillGradientAttribute(
                                 
XGradientStyleToGradientStyle(aXGradient.GetGradientStyle()),
                                 static_cast<double>(aXGradient.GetBorder()) * 
0.01,
@@ -500,7 +511,7 @@ namespace drawinglayer::primitive2d
                                 toRadians(aXGradient.GetAngle()),
                                 aStart,
                                 aEnd,
-                                nullptr,
+                                aColorSteps.empty() ? nullptr : &aColorSteps,
                                 rSet.Get(XATTR_GRADIENTSTEPCOUNT).GetValue());
 
                             break;

Reply via email to