drawinglayer/source/primitive2d/svggradientprimitive2d.cxx  |  461 +++++-------
 drawinglayer/source/tools/emfphelperdata.cxx                |   14 
 include/drawinglayer/primitive2d/svggradientprimitive2d.hxx |   33 
 3 files changed, 242 insertions(+), 266 deletions(-)

New commits:
commit c3f0c527b31f5c88263ea63d3d0e332c4783917c
Author:     Armin Le Grand <armin.le.gr...@me.com>
AuthorDate: Wed Mar 11 14:06:53 2020 +0100
Commit:     Armin Le Grand <armin.le.gr...@me.com>
CommitDate: Wed Mar 11 16:24:36 2020 +0100

    tdf#124424 Enhanced SvgGradientHelper for EMF+
    
    Added support for repeat modes in GDI+ support
    and saw that the SVG primitive gradient helpers
    are not capable to support these completely, so
    had to do some quite complex adaptions which
    OTOH will be useful for more complex gradients
    anyways
    
    Change-Id: Ib9a9e4a55115834a4fb00300b05abe17ae36d105
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/90329
    Tested-by: Jenkins
    Reviewed-by: Armin Le Grand <armin.le.gr...@me.com>

diff --git a/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx 
b/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx
index b6b85390a711..4367d8e3eb1a 100644
--- a/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx
@@ -28,6 +28,8 @@
 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
 #include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <sal/log.hxx>
+#include <cmath>
 
 
 using namespace com::sun::star;
@@ -102,131 +104,191 @@ namespace drawinglayer::primitive2d
 
             if(rEntries.empty())
             {
-                // no fill at all
+                // no fill at all, done
+                return;
             }
-            else
-            {
-                const sal_uInt32 nCount(rEntries.size());
 
-                if(1 == nCount)
+            // sort maGradientEntries by offset, small to big
+            std::sort(maGradientEntries.begin(), maGradientEntries.end());
+
+            // gradient with at least two colors
+            bool bAllInvisible(true);
+            bool bInvalidEntries(false);
+
+            for(const SvgGradientEntry& rCandidate : rEntries)
+            {
+                if(basegfx::fTools::equalZero(rCandidate.getOpacity()))
                 {
-                    // fill with single existing color
-                    setSingleEntry();
+                    // invisible
+                    mbFullyOpaque = false;
+                }
+                else if(basegfx::fTools::equal(rCandidate.getOpacity(), 1.0))
+                {
+                    // completely opaque
+                    bAllInvisible = false;
                 }
                 else
                 {
-                    // sort maGradientEntries when more than one
-                    std::sort(maGradientEntries.begin(), 
maGradientEntries.end());
+                    // opacity
+                    bAllInvisible = false;
+                    mbFullyOpaque = false;
+                }
 
-                    // gradient with at least two colors
-                    bool bAllInvisible(true);
+                
if(!basegfx::fTools::betweenOrEqualEither(rCandidate.getOffset(), 0.0, 1.0))
+                {
+                    bInvalidEntries = true;
+                }
+            }
 
-                    for(sal_uInt32 a(0); a < nCount; a++)
-                    {
-                        const SvgGradientEntry& rCandidate = rEntries[a];
+            if(bAllInvisible)
+            {
+                // all invisible, nothing to do
+                return;
+            }
 
-                        if(basegfx::fTools::equalZero(rCandidate.getOpacity()))
-                        {
-                            // invisible
-                            mbFullyOpaque = false;
-                        }
-                        else 
if(basegfx::fTools::equal(rCandidate.getOpacity(), 1.0))
-                        {
-                            // completely opaque
-                            bAllInvisible = false;
-                        }
-                        else
-                        {
-                            // opacity
-                            bAllInvisible = false;
-                            mbFullyOpaque = false;
-                        }
-                    }
+            if(bInvalidEntries)
+            {
+                // invalid entries, do nothing
+                SAL_WARN("drawinglayer", "SvgGradientHelper got invalid 
SvgGradientEntries outside [0.0 .. 1.0]");
+                return;
+            }
 
-                    if(bAllInvisible)
-                    {
-                        // all invisible, nothing to do
-                    }
-                    else
-                    {
-                        const basegfx::B2DRange 
aPolyRange(getPolyPolygon().getB2DRange());
+            const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange());
 
-                        if(aPolyRange.isEmpty())
-                        {
-                            // no range to fill, nothing to do
-                        }
-                        else
-                        {
-                            const double fPolyWidth(aPolyRange.getWidth());
-                            const double fPolyHeight(aPolyRange.getHeight());
-
-                            if(basegfx::fTools::equalZero(fPolyWidth) || 
basegfx::fTools::equalZero(fPolyHeight))
-                            {
-                                // no width/height to fill, nothing to do
-                            }
-                            else
-                            {
-                                mbCreatesContent = true;
-                            }
-                        }
-                    }
-                }
+            if(aPolyRange.isEmpty())
+            {
+                // no range to fill, nothing to do
+                return;
+            }
+
+            const double fPolyWidth(aPolyRange.getWidth());
+            const double fPolyHeight(aPolyRange.getHeight());
+
+            if(basegfx::fTools::equalZero(fPolyWidth) || 
basegfx::fTools::equalZero(fPolyHeight))
+            {
+                // no width/height to fill, nothing to do
+                return;
+            }
+
+            mbCreatesContent = true;
+
+            if(1 == rEntries.size())
+            {
+                // fill with single existing color
+                setSingleEntry();
             }
         }
 
-        double SvgGradientHelper::createRun(
-            Primitive2DContainer& rTargetColor,
-            Primitive2DContainer& rTargetOpacity,
-            double fPos,
-            double fMax,
-            const SvgGradientEntryVector& rEntries,
-            sal_Int32 nOffset) const
+        const SvgGradientEntry& SvgGradientHelper::FindEntryLessOrEqual(
+            sal_Int32& rInt,
+            const double fFrac) const
         {
-            const sal_uInt32 nCount(rEntries.size());
+            const bool bMirror(SpreadMethod::Reflect == getSpreadMethod() && 0 
!= rInt % 2);
+            const SvgGradientEntryVector& rCurrent(bMirror ? 
getMirroredGradientEntries() : getGradientEntries());
 
-            if(nCount)
+            for(SvgGradientEntryVector::const_reverse_iterator 
aIter(rCurrent.rbegin()); aIter != rCurrent.rend(); aIter++)
             {
-                const SvgGradientEntry& rStart = rEntries[0];
-                const bool bCreateStartPad(fPos < 0.0 && SpreadMethod::Pad == 
getSpreadMethod());
-                const bool bCreateStartFill(rStart.getOffset() > 0.0);
-                sal_uInt32 nIndex(0);
+               if(basegfx::fTools::lessOrEqual(aIter->getOffset(), fFrac))
+               {
+                   return *aIter;
+               }
+            }
 
-                if(bCreateStartPad || bCreateStartFill)
-                {
-                    const SvgGradientEntry aTemp(bCreateStartPad ? fPos : 0.0, 
rStart.getColor(), rStart.getOpacity());
+            // walk over gap to the left, be prepared for missing 0.0/1.0 
entries
+            rInt--;
+            const bool bMirror2(SpreadMethod::Reflect == getSpreadMethod() && 
0 != rInt % 2);
+            const SvgGradientEntryVector& rCurrent2(bMirror2 ? 
getMirroredGradientEntries() : getGradientEntries());
+            return rCurrent2.back();
+        }
 
-                    createAtom(rTargetColor, rTargetOpacity, aTemp, rStart, 
nOffset);
-                    fPos = rStart.getOffset();
-                }
+        const SvgGradientEntry& SvgGradientHelper::FindEntryMore(
+            sal_Int32& rInt,
+            const double fFrac) const
+        {
+            const bool bMirror(SpreadMethod::Reflect == getSpreadMethod() && 0 
!= rInt % 2);
+            const SvgGradientEntryVector& rCurrent(bMirror ? 
getMirroredGradientEntries() : getGradientEntries());
+
+            for(SvgGradientEntryVector::const_iterator 
aIter(rCurrent.begin()); aIter != rCurrent.end(); aIter++)
+            {
+               if(basegfx::fTools::more(aIter->getOffset(), fFrac))
+               {
+                   return *aIter;
+               }
+            }
 
-                while(fPos < 1.0 && nIndex + 1 < nCount)
+            // walk over gap to the right, be prepared for missing 0.0/1.0 
entries
+            rInt++;
+            const bool bMirror2(SpreadMethod::Reflect == getSpreadMethod() && 
0 != rInt % 2);
+            const SvgGradientEntryVector& rCurrent2(bMirror2 ? 
getMirroredGradientEntries() : getGradientEntries());
+            return rCurrent2.front();
+        }
+
+        // tdf#124424 Adapted creation of color runs to do in a single effort. 
Previous
+        // version tried to do this from [0.0 .. 1.0] and to re-use 
transformed versions
+        // in the caller if SpreadMethod was on some repeat mode, but had 
problems when
+        // e.g. like in the bugdoc from the task a negative-only fStart/fEnd 
run was
+        // requested in which case it did nothing. Even when reusing the 
spread might
+        // not have been a full one from [0.0 .. 1.0].
+        // This gets complicated due to mirrored runs, but also for gradient 
definitions
+        // with missing entries for 0.0 and 1.0 in which case these have to be 
guessed
+        // to be there with same parametrisation as their nearest existing 
entries. These
+        // *could* have been added at checkPreconditions() but would then 
create unnecessary
+        // spreads on zone overlaps.
+        void SvgGradientHelper::createRun(
+            Primitive2DContainer& rTargetColor,
+            Primitive2DContainer& rTargetOpacity,
+            double fStart,
+            double fEnd) const
+        {
+            if(SpreadMethod::Pad == getSpreadMethod())
+            {
+                if(fStart < 0.0)
                 {
-                    const SvgGradientEntry& rCandidateA = rEntries[nIndex++];
-                    const SvgGradientEntry& rCandidateB = rEntries[nIndex];
+                    const SvgGradientEntry& 
rFront(getGradientEntries().front());
+                    const SvgGradientEntry aTemp(fStart, rFront.getColor(), 
rFront.getOpacity());
+                    createAtom(rTargetColor, rTargetOpacity, aTemp, rFront, 0, 
0);
+                    fStart = rFront.getOffset();
+                }
 
-                    createAtom(rTargetColor, rTargetOpacity, rCandidateA, 
rCandidateB, nOffset);
-                    fPos = rCandidateB.getOffset();
+                if(fEnd < 1.0)
+                {
+                    const SvgGradientEntry& rBack(getGradientEntries().back());
+                    const SvgGradientEntry aTemp(fEnd, rBack.getColor(), 
rBack.getOpacity());
+                    createAtom(rTargetColor, rTargetOpacity, rBack, aTemp, 0, 
0);
+                    fEnd = rBack.getOffset();
                 }
+            }
 
-                const SvgGradientEntry& rEnd = rEntries[nCount - 1];
-                const bool bCreateEndPad(fPos < fMax && SpreadMethod::Pad == 
getSpreadMethod());
-                const bool bCreateEndFill(rEnd.getOffset() < 1.0);
+            while(fStart < fEnd)
+            {
+                double fInt(0.0);
+                double fFrac(std::modf(fStart, &fInt));
 
-                if(bCreateEndPad || bCreateEndFill)
+                if(fFrac < 0.0)
                 {
-                    fPos = bCreateEndPad ? fMax : 1.0;
-                    const SvgGradientEntry aTemp(fPos, rEnd.getColor(), 
rEnd.getOpacity());
+                    fInt -= 1;
+                    fFrac = 1.0 + fFrac;
+                }
+
+                sal_Int32 nIntLeft(static_cast<sal_Int32>(fInt));
+                sal_Int32 nIntRight(nIntLeft);
 
-                    createAtom(rTargetColor, rTargetOpacity, rEnd, aTemp, 
nOffset);
+                const SvgGradientEntry& rLeft(FindEntryLessOrEqual(nIntLeft, 
fFrac));
+                const SvgGradientEntry& rRight(FindEntryMore(nIntRight, 
fFrac));
+                createAtom(rTargetColor, rTargetOpacity, rLeft, rRight, 
nIntLeft, nIntRight);
+
+                const double fNextfStart(static_cast<double>(nIntRight) + 
rRight.getOffset());
+
+                if(basegfx::fTools::more(fNextfStart, fStart))
+                {
+                    fStart = fNextfStart;
+                }
+                else
+                {
+                    SAL_WARN("drawinglayer", "SvgGradientHelper spread error");
+                    fStart += 1.0;
                 }
             }
-            else
-            {
-                OSL_ENSURE(false, "GradientAtom creation without ColorStops 
(!)");
-                fPos = fMax;
-            }
-
-            return fPos;
         }
 
         void SvgGradientHelper::createResult(
@@ -276,6 +338,7 @@ namespace drawinglayer::primitive2d
         :   maGradientTransform(rGradientTransform),
             maPolyPolygon(rPolyPolygon),
             maGradientEntries(rGradientEntries),
+            maMirroredGradientEntries(),
             maStart(rStart),
             maSpreadMethod(aSpreadMethod),
             mbPreconditionsChecked(false),
@@ -290,6 +353,36 @@ namespace drawinglayer::primitive2d
         {
         }
 
+        const SvgGradientEntryVector& 
SvgGradientHelper::getMirroredGradientEntries() const
+        {
+            if(maMirroredGradientEntries.empty() && 
!getGradientEntries().empty())
+            {
+                const_cast< SvgGradientHelper* 
>(this)->createMirroredGradientEntries();
+            }
+
+            return maMirroredGradientEntries;
+        }
+
+        void SvgGradientHelper::createMirroredGradientEntries()
+        {
+            if(maMirroredGradientEntries.empty() && 
!getGradientEntries().empty())
+            {
+                const sal_uInt32 nCount(getGradientEntries().size());
+                maMirroredGradientEntries.clear();
+                maMirroredGradientEntries.reserve(nCount);
+
+                for(sal_uInt32 a(0); a < nCount; a++)
+                {
+                    const SvgGradientEntry& rCandidate = 
getGradientEntries()[nCount - 1 - a];
+
+                    maMirroredGradientEntries.emplace_back(
+                            1.0 - rCandidate.getOffset(),
+                            rCandidate.getColor(),
+                            rCandidate.getOpacity());
+                }
+            }
+        }
+
         bool SvgGradientHelper::operator==(const SvgGradientHelper& 
rSvgGradientHelper) const
         {
             const SvgGradientHelper& rCompare = rSvgGradientHelper;
@@ -330,7 +423,8 @@ namespace drawinglayer::primitive2d
             Primitive2DContainer& rTargetOpacity,
             const SvgGradientEntry& rFrom,
             const SvgGradientEntry& rTo,
-            sal_Int32 nOffset) const
+            sal_Int32 nOffsetFrom,
+            sal_Int32 nOffsetTo) const
         {
             // create gradient atom [rFrom.getOffset() .. rTo.getOffset()] 
with (rFrom.getOffset() > rTo.getOffset())
             if(rFrom.getOffset() == rTo.getOffset())
@@ -341,8 +435,8 @@ namespace drawinglayer::primitive2d
             {
                 rTargetColor.push_back(
                     new SvgLinearAtomPrimitive2D(
-                        rFrom.getColor(), rFrom.getOffset() + nOffset,
-                        rTo.getColor(), rTo.getOffset() + nOffset));
+                        rFrom.getColor(), rFrom.getOffset() + nOffsetFrom,
+                        rTo.getColor(), rTo.getOffset() + nOffsetTo));
 
                 if(!getFullyOpaque())
                 {
@@ -353,8 +447,8 @@ namespace drawinglayer::primitive2d
 
                     rTargetOpacity.push_back(
                         new SvgLinearAtomPrimitive2D(
-                            aColorFrom, rFrom.getOffset() + nOffset,
-                            aColorTo, rTo.getOffset() + nOffset));
+                            aColorFrom, rFrom.getOffset() + nOffsetFrom,
+                            aColorTo, rTo.getOffset() + nOffsetTo));
                 }
             }
         }
@@ -441,92 +535,12 @@ namespace drawinglayer::primitive2d
                             1.0, aUnitRange.getHeight(), 0.0, 
aUnitRange.getMinY()));
                     aUnitGradientToObject = aUnitGradientToObject * 
aPreMultiply;
 
-                    // create central run, may also already do all necessary 
when
-                    // SpreadMethod::Pad is set as SpreadMethod and/or the 
range is smaller
-                    double fPos(createRun(aTargetColor, aTargetOpacity, 
aUnitRange.getMinX(), aUnitRange.getMaxX(), getGradientEntries(), 0));
-
-                    if(fPos < aUnitRange.getMaxX())
-                    {
-                        // can only happen when SpreadMethod is 
SpreadMethod::Reflect or SpreadMethod::Repeat,
-                        // else the start and end pads are already created and 
fPos == aUnitRange.getMaxX().
-                        // Its possible to express the repeated linear 
gradient by adding the
-                        // transformed central run. Create it this way
-                        Primitive2DContainer 
aTargetColorEntries(aTargetColor.maybeInvert());
-                        Primitive2DContainer 
aTargetOpacityEntries(aTargetOpacity.maybeInvert());
-                        aTargetColor.clear();
-                        aTargetOpacity.clear();
-
-                        if(!aTargetColorEntries.empty())
-                        {
-                            // add original central run as group primitive
-                            aTargetColor.push_back(new 
GroupPrimitive2D(aTargetColorEntries));
-
-                            if(!aTargetOpacityEntries.empty())
-                            {
-                                aTargetOpacity.push_back(new 
GroupPrimitive2D(aTargetOpacityEntries));
-                            }
-
-                            // add negative runs
-                            fPos = 0.0;
-                            sal_Int32 nOffset(0);
-
-                            while(fPos > aUnitRange.getMinX())
-                            {
-                                fPos -= 1.0;
-                                nOffset++;
-
-                                basegfx::B2DHomMatrix aTransform;
-                                const bool bMirror(SpreadMethod::Reflect == 
getSpreadMethod() && (nOffset % 2));
-
-                                if(bMirror)
-                                {
-                                    aTransform.scale(-1.0, 1.0);
-                                    aTransform.translate(fPos + 1.0, 0.0);
-                                }
-                                else
-                                {
-                                    aTransform.translate(fPos, 0.0);
-                                }
-
-                                aTargetColor.push_back(new 
TransformPrimitive2D(aTransform, aTargetColorEntries));
-
-                                if(!aTargetOpacityEntries.empty())
-                                {
-                                    aTargetOpacity.push_back(new 
TransformPrimitive2D(aTransform, aTargetOpacityEntries));
-                                }
-                            }
-
-                            // add positive runs
-                            fPos = 1.0;
-                            nOffset = 1;
-
-                            while(fPos < aUnitRange.getMaxX())
-                            {
-                                basegfx::B2DHomMatrix aTransform;
-                                const bool bMirror(SpreadMethod::Reflect == 
getSpreadMethod() && (nOffset % 2));
-
-                                if(bMirror)
-                                {
-                                    aTransform.scale(-1.0, 1.0);
-                                    aTransform.translate(fPos + 1.0, 0.0);
-                                }
-                                else
-                                {
-                                    aTransform.translate(fPos, 0.0);
-                                }
-
-                                aTargetColor.push_back(new 
TransformPrimitive2D(aTransform, aTargetColorEntries));
-
-                                if(!aTargetOpacityEntries.empty())
-                                {
-                                    aTargetOpacity.push_back(new 
TransformPrimitive2D(aTransform, aTargetOpacityEntries));
-                                }
-
-                                fPos += 1.0;
-                                nOffset++;
-                            }
-                        }
-                    }
+                    // create full color run, including all SpreadMethod 
variants
+                    createRun(
+                        aTargetColor,
+                        aTargetOpacity,
+                        aUnitRange.getMinX(),
+                        aUnitRange.getMaxX());
                 }
 
                 createResult(rContainer, aTargetColor, aTargetOpacity, 
aUnitGradientToObject);
@@ -600,7 +614,8 @@ namespace drawinglayer::primitive2d
             Primitive2DContainer& rTargetOpacity,
             const SvgGradientEntry& rFrom,
             const SvgGradientEntry& rTo,
-            sal_Int32 nOffset) const
+            sal_Int32 nOffsetFrom,
+            sal_Int32 nOffsetTo) const
         {
             // create gradient atom [rFrom.getOffset() .. rTo.getOffset()] 
with (rFrom.getOffset() > rTo.getOffset())
             if(rFrom.getOffset() == rTo.getOffset())
@@ -609,8 +624,8 @@ namespace drawinglayer::primitive2d
             }
             else
             {
-                const double fScaleFrom(rFrom.getOffset() + nOffset);
-                const double fScaleTo(rTo.getOffset() + nOffset);
+                const double fScaleFrom(rFrom.getOffset() + nOffsetFrom);
+                const double fScaleTo(rTo.getOffset() + nOffsetTo);
 
                 if(isFocalSet())
                 {
@@ -658,36 +673,6 @@ namespace drawinglayer::primitive2d
             }
         }
 
-        const SvgGradientEntryVector& 
SvgRadialGradientPrimitive2D::getMirroredGradientEntries() const
-        {
-            if(maMirroredGradientEntries.empty() && 
!getGradientEntries().empty())
-            {
-                const_cast< SvgRadialGradientPrimitive2D* 
>(this)->createMirroredGradientEntries();
-            }
-
-            return maMirroredGradientEntries;
-        }
-
-        void SvgRadialGradientPrimitive2D::createMirroredGradientEntries()
-        {
-            if(maMirroredGradientEntries.empty() && 
!getGradientEntries().empty())
-            {
-                const sal_uInt32 nCount(getGradientEntries().size());
-                maMirroredGradientEntries.clear();
-                maMirroredGradientEntries.reserve(nCount);
-
-                for(sal_uInt32 a(0); a < nCount; a++)
-                {
-                    const SvgGradientEntry& rCandidate = 
getGradientEntries()[nCount - 1 - a];
-
-                    maMirroredGradientEntries.emplace_back(
-                            1.0 - rCandidate.getOffset(),
-                            rCandidate.getColor(),
-                            rCandidate.getOpacity());
-                }
-            }
-        }
-
         void 
SvgRadialGradientPrimitive2D::create2DDecomposition(Primitive2DContainer& 
rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const
         {
             if(!getPreconditionsChecked())
@@ -774,35 +759,12 @@ namespace drawinglayer::primitive2d
                         const_cast< SvgRadialGradientPrimitive2D* 
>(this)->maFocalLength = fMax;
                     }
 
-                    // create central run, may also already do all necessary 
when
-                    // SpreadMethod::Pad is set as SpreadMethod and/or the 
range is smaller
-                    double fPos(createRun(aTargetColor, aTargetOpacity, 0.0, 
fMax, getGradientEntries(), 0));
-
-                    if(fPos < fMax)
-                    {
-                        // can only happen when SpreadMethod is 
SpreadMethod::Reflect or SpreadMethod::Repeat,
-                        // else the start and end pads are already created and 
fPos == fMax.
-                        // For radial there is no way to transform the already 
created
-                        // central run, it needs to be created from 1.0 to fMax
-                        sal_Int32 nOffset(1);
-
-                        while(fPos < fMax)
-                        {
-                            const bool bMirror(SpreadMethod::Reflect == 
getSpreadMethod() && (nOffset % 2));
-
-                            if(bMirror)
-                            {
-                                createRun(aTargetColor, aTargetOpacity, 0.0, 
fMax, getMirroredGradientEntries(), nOffset);
-                            }
-                            else
-                            {
-                                createRun(aTargetColor, aTargetOpacity, 0.0, 
fMax, getGradientEntries(), nOffset);
-                            }
-
-                            nOffset++;
-                            fPos += 1.0;
-                        }
-                    }
+                    // create full color run, including all SpreadMethod 
variants
+                    createRun(
+                        aTargetColor,
+                        aTargetOpacity,
+                        0.0,
+                        fMax);
                 }
 
                 createResult(rContainer, aTargetColor, aTargetOpacity, 
aUnitGradientToObject, true);
@@ -824,7 +786,6 @@ namespace drawinglayer::primitive2d
             maFocal(rStart),
             maFocalVector(0.0, 0.0),
             maFocalLength(0.0),
-            maMirroredGradientEntries(),
             mbFocalSet(false)
         {
             if(pFocal && !pFocal->equal(getStart()))
diff --git a/drawinglayer/source/tools/emfphelperdata.cxx 
b/drawinglayer/source/tools/emfphelperdata.cxx
index 936afec29364..9b16f6af51a3 100644
--- a/drawinglayer/source/tools/emfphelperdata.cxx
+++ b/drawinglayer/source/tools/emfphelperdata.cxx
@@ -877,11 +877,23 @@ namespace emfplushelper
 
                 if (brush->type == BrushTypeLinearGradient)
                 {
+                    // support for public enum EmfPlusWrapMode
                     basegfx::B2DPoint aStartPoint = Map(brush->firstPointX, 
brush->firstPointY);
                     aStartPoint = aPolygonTransformation * aStartPoint;
                     basegfx::B2DPoint aEndPoint = Map(brush->firstPointX + 
brush->secondPointX, brush->firstPointY + brush->secondPointY);
                     aEndPoint = aPolygonTransformation * aEndPoint;
 
+                    // support for public enum EmfPlusWrapMode
+                    drawinglayer::primitive2d::SpreadMethod 
aSpreadMethod(drawinglayer::primitive2d::SpreadMethod::Pad);
+                    switch(brush->wrapMode)
+                    {
+                        case 0 : aSpreadMethod = 
drawinglayer::primitive2d::SpreadMethod::Repeat; break;
+                        case 1 :
+                        case 2 :
+                        case 3 : aSpreadMethod = 
drawinglayer::primitive2d::SpreadMethod::Reflect; break;
+                        default: break;
+                    }
+
                     // create the same one used for SVG
                     mrTargetHolders.Current().append(
                         
std::make_unique<drawinglayer::primitive2d::SvgLinearGradientPrimitive2D>(
@@ -891,7 +903,7 @@ namespace emfplushelper
                             aStartPoint,
                             aEndPoint,
                             false,                  // do not use 
UnitCoordinates
-                            drawinglayer::primitive2d::SpreadMethod::Pad));
+                            aSpreadMethod));
                 }
                 else // BrushTypePathGradient
                 {
diff --git a/include/drawinglayer/primitive2d/svggradientprimitive2d.hxx 
b/include/drawinglayer/primitive2d/svggradientprimitive2d.hxx
index c130368bf5b9..871a4aea822d 100644
--- a/include/drawinglayer/primitive2d/svggradientprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/svggradientprimitive2d.hxx
@@ -101,6 +101,9 @@ namespace drawinglayer
             /// the gradient definition
             SvgGradientEntryVector      maGradientEntries;
 
+            // internal helper for case SpreadMethod::Reflect
+            SvgGradientEntryVector      maMirroredGradientEntries;
+
             /// start and/or center point
             basegfx::B2DPoint           maStart;
 
@@ -117,6 +120,12 @@ namespace drawinglayer
             // (related to SVG's gradientUnits 
(userSpaceOnUse|objectBoundingBox)
             bool                        mbUseUnitCoordinates : 1;
 
+            /// local helpers
+            const SvgGradientEntryVector& getMirroredGradientEntries() const;
+            void createMirroredGradientEntries();
+            const SvgGradientEntry& FindEntryLessOrEqual(sal_Int32& rInt, 
const double fFrac) const;
+            const SvgGradientEntry& FindEntryMore(sal_Int32& rInt,const double 
fFrac) const;
+
         protected:
             /// local helpers
             void createSingleGradientEntryFill(Primitive2DContainer& 
rContainer) const;
@@ -125,14 +134,13 @@ namespace drawinglayer
                 Primitive2DContainer& rTargetOpacity,
                 const SvgGradientEntry& rFrom,
                 const SvgGradientEntry& rTo,
-                sal_Int32 nOffset) const = 0;
-            double createRun(
+                sal_Int32 nOffsetFrom,
+                sal_Int32 nOffsetTo) const = 0;
+            void createRun(
                 Primitive2DContainer& rTargetColor,
                 Primitive2DContainer& rTargetOpacity,
-                double fPos,
-                double fMax,
-                const SvgGradientEntryVector& rEntries,
-                sal_Int32 nOffset) const;
+                double fStart,
+                double fEnd) const;
             virtual void checkPreconditions();
             void createResult(
                 Primitive2DContainer& rContainer,
@@ -191,7 +199,8 @@ namespace drawinglayer
                 Primitive2DContainer& rTargetOpacity,
                 const SvgGradientEntry& rFrom,
                 const SvgGradientEntry& rTo,
-                sal_Int32 nOffset) const override;
+                sal_Int32 nOffsetFrom,
+                sal_Int32 nOffsetTo) const override;
             virtual void checkPreconditions() override;
 
             /// local decomposition.
@@ -243,22 +252,16 @@ namespace drawinglayer
             basegfx::B2DVector                      maFocalVector;
             double                                  maFocalLength;
 
-            // internal helper for case SpreadMethod::Reflect
-            SvgGradientEntryVector                  maMirroredGradientEntries;
-
             bool                                    mbFocalSet : 1;
 
-            /// local helpers
-            const SvgGradientEntryVector& getMirroredGradientEntries() const;
-            void createMirroredGradientEntries();
-
             /// local helpers
             virtual void createAtom(
                 Primitive2DContainer& rTargetColor,
                 Primitive2DContainer& rTargetOpacity,
                 const SvgGradientEntry& rFrom,
                 const SvgGradientEntry& rTo,
-                sal_Int32 nOffset) const override;
+                sal_Int32 nOffsetFrom,
+                sal_Int32 nOffsetTo) const override;
             virtual void checkPreconditions() override;
 
             /// local decomposition.
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to