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;