From ca8a7fe542f8029d82dcafdc776ecc29752f286f Mon Sep 17 00:00:00 2001 From: "Armin Le Grand (allotropia)" Date: Tue, 21 Feb 2023 18:35:39 +0100 Subject: MCGR: Adapted GradientLinear to make use of MCGR Added to make GradientLinear work using the MCGR as 1st of six types. Had to do quite some tickeling to get it all work, but looks good. Five more to go, already started to put some things to tooling to make re-usable for the other types. Besides adapting this the main change is that the adaption of defined step-count (versus automatic) has to be done in modifyBColor now instead of the back-mapping methods (e.g. getLinearGradientAlpha). It is still 100% backward-compatible, so as long as there is no source using this it will stay invisible - by purpose. I started to do quite some tests (and fixes/ adaptions in consequence), see the static variable nUseGradientSteps. If you want to play with this, you might set it to '1' instead of '0' and use a linear gradient on an object. Change-Id: I9d61934defb0674456247f2879f0a89b6a5e50f7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147413 Tested-by: Jenkins Reviewed-by: Armin Le Grand --- basegfx/source/tools/gradienttools.cxx | 101 +++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 5 deletions(-) (limited to 'basegfx') diff --git a/basegfx/source/tools/gradienttools.cxx b/basegfx/source/tools/gradienttools.cxx index b3bb18f918da..a8d36b9f543d 100644 --- a/basegfx/source/tools/gradienttools.cxx +++ b/basegfx/source/tools/gradienttools.cxx @@ -21,6 +21,8 @@ #include #include #include + +#include #include namespace basegfx @@ -261,6 +263,95 @@ namespace basegfx namespace utils { + BColor modifyBColor( + const ColorSteps& rColorSteps, + double fScaler, + sal_uInt32 nRequestedSteps) + { + // no color at all, done + if (rColorSteps.empty()) + return BColor(); + + // outside range -> at start + if (fScaler <= 0.0) + return rColorSteps.front().getColor(); + + // outside range -> at end + if (fScaler >= 1.0) + return rColorSteps.back().getColor(); + + // special case for the 'classic' case with just two colors: + // we can optimize that and keep the speed/ressources low + // by avoiding some calculatins and an O(log(N)) array access + if (2 == rColorSteps.size()) + { + const basegfx::BColor aCStart(rColorSteps.front().getColor()); + const basegfx::BColor aCEnd(rColorSteps.back().getColor()); + const sal_uInt32 nSteps( + calculateNumberOfSteps( + nRequestedSteps, + aCStart, + aCEnd)); + + return basegfx::interpolate( + aCStart, + aCEnd, + nSteps > 1 ? floor(fScaler * nSteps) / double(nSteps - 1) : fScaler); + } + + // access needed spot in sorted array using binary search + // NOTE: This *seems* slow(er) when developing compared to just + // looping/accessing, but that's just due to the extensive + // debug test code created by the stl. In a pro version, + // all is good/fast as expected + const auto upperBound( + std::lower_bound( + rColorSteps.begin(), + rColorSteps.end(), + ColorStep(fScaler), + [](const ColorStep& x, const ColorStep& y) { return x.getOffset() < y.getOffset(); })); + + // no upper bound, done + if (rColorSteps.end() == upperBound) + return rColorSteps.back().getColor(); + + // lower bound is one entry back + const auto lowerBound(upperBound - 1); + + // no lower bound, done + if (rColorSteps.end() == lowerBound) + return rColorSteps.back().getColor(); + + // we have lower and upper bound, get colors + const BColor aCStart(lowerBound->getColor()); + const BColor aCEnd(upperBound->getColor()); + + // when there are just two color steps this cannot happen, but when using + // a range of colors this *may* be used inside the range to represent + // single-colored regions inside a ColorRange. Use that color & done + if (aCStart == aCEnd) + return aCStart; + + // calculate number of steps + const sal_uInt32 nSteps( + calculateNumberOfSteps( + nRequestedSteps, + aCStart, + aCEnd)); + + // get offsets and scale to new [0.0 .. 1.0] relative range for + // partial outer range + const double fOffsetStart(lowerBound->getOffset()); + const double fOffsetEnd(upperBound->getOffset()); + const double fAdaptedScaler((fScaler - fOffsetStart) / (fOffsetEnd - fOffsetStart)); + + // interpolate & evtl. apply steps + return interpolate( + aCStart, + aCEnd, + nSteps > 1 ? floor(fAdaptedScaler * nSteps) / double(nSteps - 1) : fAdaptedScaler); + } + sal_uInt32 calculateNumberOfSteps( sal_uInt32 nRequestedSteps, const BColor& rStart, @@ -392,12 +483,12 @@ namespace basegfx return 1.0; // end value for outside } - const sal_uInt32 nSteps(rGradInfo.getRequestedSteps()); + // const sal_uInt32 nSteps(rGradInfo.getRequestedSteps()); - if(nSteps) - { - return floor(aCoor.getY() * nSteps) / double(nSteps - 1); - } + // if(nSteps) + // { + // return floor(aCoor.getY() * nSteps) / double(nSteps - 1); + // } return aCoor.getY(); } -- cgit