basegfx/source/tools/gradienttools.cxx | 38 +++++++++++++++++ include/basegfx/utils/gradienttools.hxx | 15 +++++++ svx/source/sdr/primitive2d/sdrattributecreator.cxx | 45 +++++++++++++-------- 3 files changed, 81 insertions(+), 17 deletions(-)
New commits: commit 64007cb308ead90ba6ffa2963c5de8ef89cec5ce Author: Armin Le Grand (allotropia) <armin.le.grand.ext...@allotropia.de> AuthorDate: Mon Apr 3 12:09:16 2023 +0200 Commit: Armin Le Grand <armin.le.gr...@me.com> CommitDate: Mon Apr 3 17:16:48 2023 +0200 MCGR: Unify Gradient intensity handling in tooling Moved the Gradient intensity handling to tooling since it is also needed for TransparencyGradients. Added missing use of GradientStepCount for transparency. Change-Id: I63ae6683fa0131be7faadc8572e19f5c43bf27e3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149957 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 49cf831da262..d1b5874e5b77 100644 --- a/basegfx/source/tools/gradienttools.cxx +++ b/basegfx/source/tools/gradienttools.cxx @@ -264,6 +264,44 @@ namespace basegfx namespace utils { + /* Tooling method to linearly blend the Colors contained in + a given ColorStop vector against a given Color using the + given intensity values. + The intensity values fStartIntensity, fEndIntensity are + in the range of [0.0 .. 1.0] and describe how much the + blend is supposed to be done at the start color position + and the end color position resprectively, where 0.0 means + to fully use the given BlendColor, 1.0 means to not change + the existing color in the ColorStop. + Every color entry in the given ColorStop is blended + relative to it's StopPosition, interpolating the + given intensities with the range [0.0 .. 1.0] to do so. + */ + void blendColorStopsToIntensity(ColorStops& rColorStops, double fStartIntensity, double fEndIntensity, const basegfx::BColor& rBlendColor) + { + // no entries, done + if (rColorStops.empty()) + return; + + // correct intensities (maybe assert when input was wrong) + fStartIntensity = std::max(std::min(1.0, fStartIntensity), 0.0); + fEndIntensity = std::max(std::min(1.0, fEndIntensity), 0.0); + + // all 100%, no real blend, done + if (basegfx::fTools::equal(fStartIntensity, 1.0) && basegfx::fTools::equal(fEndIntensity, 1.0)) + return; + + // blend relative to StopOffset position + for (auto& candidate : rColorStops) + { + const double fOffset(candidate.getStopOffset()); + const double fIntensity((fStartIntensity * (1.0 - fOffset)) + (fEndIntensity * fOffset)); + candidate = basegfx::ColorStop( + fOffset, + basegfx::interpolate(rBlendColor, candidate.getStopColor(), fIntensity)); + } + } + /* Tooling method to check if a ColorStop vector is defined by a single color. It returns true if this is the case. If true is returned, rSingleColor contains that single diff --git a/include/basegfx/utils/gradienttools.hxx b/include/basegfx/utils/gradienttools.hxx index c7123bc81db3..dfa1f35b38c4 100644 --- a/include/basegfx/utils/gradienttools.hxx +++ b/include/basegfx/utils/gradienttools.hxx @@ -196,6 +196,21 @@ namespace basegfx namespace utils { + /* Tooling method to linearly blend the Colors contained in + a given ColorStop vector against a given Color using the + given intensity values. + The intensity values fStartIntensity, fEndIntensity are + in the range of [0.0 .. 1.0] and describe how much the + blend is supposed to be done at the start color position + and the end color position resprectively, where 0.0 means + to fully use the given BlendColor, 1.0 means to not change + the existing color in the ColorStop. + Every color entry in the given ColorStop is blended + relative to it's StopPosition, interpolating the + given intensities with the range [0.0 .. 1.0] to do so. + */ + BASEGFX_DLLPUBLIC void blendColorStopsToIntensity(ColorStops& rColorStops, double fStartIntensity, double fEndIntensity, const basegfx::BColor& rBlendColor); + /* Tooling method to check if a ColorStop vector is defined by a single color. It returns true if this is the case. If true is returned, rSingleColor contains that single diff --git a/svx/source/sdr/primitive2d/sdrattributecreator.cxx b/svx/source/sdr/primitive2d/sdrattributecreator.cxx index 813c9884bc9b..89493e4d5a45 100644 --- a/svx/source/sdr/primitive2d/sdrattributecreator.cxx +++ b/svx/source/sdr/primitive2d/sdrattributecreator.cxx @@ -756,23 +756,16 @@ namespace drawinglayer::primitive2d } } - if(aXGradient.GetStartIntens() != 100 || aXGradient.GetEndIntens() != 100) + if (aXGradient.GetStartIntens() != 100 || aXGradient.GetEndIntens() != 100) { // Need to do the (old, crazy) blend against black for a // used intensity, but now for all ColorStops relative to their // offsets, where 0 means black and 100 means original color - const double fStartIntensity(aXGradient.GetStartIntens() * 0.01); - const double fEndIntensity(aXGradient.GetEndIntens() * 0.01); - const basegfx::BColor aBlack; - - for (auto& candidate : aColorStops) - { - const double fOffset(candidate.getStopOffset()); - const double fIntensity((fStartIntensity * (1.0 - fOffset)) + (fEndIntensity * fOffset)); - candidate = basegfx::ColorStop( - fOffset, - basegfx::interpolate(aBlack, candidate.getStopColor(), fIntensity)); - } + basegfx::utils::blendColorStopsToIntensity( + aColorStops, + aXGradient.GetStartIntens() * 0.01, + aXGradient.GetEndIntens() * 0.01, + basegfx::BColor()); // COL_BLACK } aGradient = attribute::FillGradientAttribute( @@ -919,8 +912,8 @@ namespace drawinglayer::primitive2d if((pGradientItem = rSet.GetItemIfSet(XATTR_FILLFLOATTRANSPARENCE)) && pGradientItem->IsEnabled()) { - // test if float transparence is completely transparent - const XGradient& rGradient = pGradientItem->GetGradientValue(); + // test if float transparency is completely transparent + const XGradient& rGradient(pGradientItem->GetGradientValue()); basegfx::BColor aSingleColor; const bool bSingleColor(basegfx::utils::isSingleColor(rGradient.GetColorStops(), aSingleColor)); const bool bCompletelyTransparent(bSingleColor && basegfx::fTools::equal(aSingleColor.luminance(), 1.0)); @@ -930,15 +923,33 @@ namespace drawinglayer::primitive2d // normal fill attributes, XFILL_NONE will be used. // create nothing when not transparent: use normal fill, no need t create a FillGradientAttribute. // Both cases are optimizations, always creating FillGradientAttribute will work, too - if(!bNotTransparent && !bCompletelyTransparent) + if (!bNotTransparent && !bCompletelyTransparent) { + basegfx::ColorStops aColorStops(rGradient.GetColorStops()); + + if (rGradient.GetStartIntens() != 100 || rGradient.GetEndIntens() != 100) + { + // this may also be set for transparence, so need to take care of it + basegfx::utils::blendColorStopsToIntensity( + aColorStops, + rGradient.GetStartIntens() * 0.01, + rGradient.GetEndIntens() * 0.01, + basegfx::BColor()); // COL_BLACK + } + return attribute::FillGradientAttribute( XGradientStyleToGradientStyle(rGradient.GetGradientStyle()), static_cast<double>(rGradient.GetBorder()) * 0.01, static_cast<double>(rGradient.GetXOffset()) * 0.01, static_cast<double>(rGradient.GetYOffset()) * 0.01, toRadians(rGradient.GetAngle()), - rGradient.GetColorStops()); + aColorStops, + // oops - the gradientStepCount was missing here. If we want to use + // a combination of gradient & transparencyGradient to represent + // imported gradients of formats which do originally support transparency + // in gradients, then the gradient has to be exactly defined the same, + // including the (evtl. used) gradientStepCount + rSet.Get(XATTR_GRADIENTSTEPCOUNT).GetValue()); } }