diff options
author | Armin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de> | 2023-03-03 18:03:56 +0100 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@me.com> | 2023-03-04 16:32:16 +0000 |
commit | ecae66c41d82fecddd630cfdc144055a069134b0 (patch) | |
tree | 2e657e7e0057a3ce31af895282bd7083d621d1e6 /basegfx | |
parent | 43dcdfae40c9c37032ed5e92cd0634feb53b706d (diff) |
MCGR: ColorSteps handling moved to tooling
Due to the fact that handling of a vector GradientSteps
will get used more often with ongoing changes I moved
some handling to tooling, see sortAndCorrectColorSteps.
That method sorts and corrects a vector of ColorSteps
so that only valid entreis remain in a sorted order,
for details please refer to the docu at function
definition. I took the occasion to rearrange that to
work on the single provided vector which is better for
speed & ressources.
Also changed the ColorStep constructor to not
automatically correct constructed entries: While that
is formally correct, it moves an invalid entry to 0.0
or 1.0, thus creating additional wrong Start/EndColor
entries. Those may then 'overlay' the correct entry
when corrections are applied to the vector of entries
which leads to getting the wanted Start/EndColor to be
factically deleted, what is an error.
Also rearranged FillGradientAttribute to now work
initially with ColorSteps, no longer requires the
Start/EndColor, also adapted all usages. This securely
allows start/end and in-between single-color sections
in gradients.
Also needed to re-formulate GradientRect &
GradientElliptical ::appendTransformationsAndColors
method for correct 2D mapping(s) - always incrementing
from the start to end conflicts with the adaption of
the start value for the inner loop mainly because
increment is at start of inner loop (pre-increment).
Corrected errors from clang plugin, but also some
wrong initialiations for basegfx::ColorSteps.
Change-Id: I292592ed9abcfa591f68a680479f4fcdda46cbeb
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148196
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Diffstat (limited to 'basegfx')
-rw-r--r-- | basegfx/source/tools/gradienttools.cxx | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/basegfx/source/tools/gradienttools.cxx b/basegfx/source/tools/gradienttools.cxx index f35f91f5a79a..5743f71ad980 100644 --- a/basegfx/source/tools/gradienttools.cxx +++ b/basegfx/source/tools/gradienttools.cxx @@ -263,6 +263,121 @@ namespace basegfx namespace utils { + /* Tooling method to guarantee sort and correctness for + the given ColorSteps vector. + At return, the following conditions are guaranteed: + - contains no ColorSteps with offset < 0.0 (will + be removed) + - contains no ColorSteps with offset > 0.0 (will + be removed) + - contains no ColorSteps with identical offset + (will be removed, 1st one wins) + - will be sorted from lowest offset to highest + - if all colors are the same, the content will + be reducved to a single entry with offset 0.0 + (StartColor) + + Some more notes: + - It can happen that the result is empty + - It is allowed to have consecutive entries with + the same color, this represents single-color + regions inside the gradient + - A entry with 0.0 is not required or forced, so + no 'StartColor' is required on this level + - A entry with 1.0 is not required or forced, so + no 'EndColor' is required on this level + + All this is done in one run (sort + O(N)) without + creating a copy of the data in any form + */ + void sortAndCorrectColorSteps(ColorSteps& rColorSteps) + { + // no content, we are done + if (rColorSteps.empty()) + return; + + if (1 == rColorSteps.size()) + { + // no gradient at all, but preserve given color + // and force it to be the StartColor + rColorSteps[0] = ColorStep(0.0, rColorSteps[0].getColor()); + } + + // start with sorting the input data. Remember that + // this preserves the order of equal entries, where + // equal is defined here by offset (see use operator==) + std::sort(rColorSteps.begin(), rColorSteps.end()); + + // preapare status values + bool bSameColorInit(false); + bool bAllTheSameColor(true); + basegfx::BColor aFirstColor; + size_t write(0); + + // use the paradigm of a band machine with two heads, read + // and write with write <= read all the time. Step over the + // data using read and check for valid entry. If valid, decide + // how to keep it + for (size_t read(0); read < rColorSteps.size(); read++) + { + // get offset of entry at read position + const double rOff(rColorSteps[read].getOffset()); + + // step over < 0 values + if (basegfx::fTools::less(rOff, 0.0)) + continue; + + // step over > 1 values; even break, since all following + // entries will also be bigger due to being sorted, so done + if (basegfx::fTools::more(rOff, 1.0)) + break; + + // entry is valid value at read position + + // check/init for all-the-same color + if(bSameColorInit) + { + // already initialized, compare + bAllTheSameColor = bAllTheSameColor && aFirstColor == rColorSteps[read].getColor(); + } + else + { + // do initialize, remember 1st valid color + bSameColorInit = true; + aFirstColor = rColorSteps[read].getColor(); + } + + // copy if write target is empty (write at start) or when + // write target is different to read + if (0 == write || rOff != rColorSteps[write-1].getOffset()) + { + if (write != read) + { + // copy read to write backwards to close gaps + rColorSteps[write] = rColorSteps[read]; + } + + // always forward write position + write++; + } + } + + // correct size when length is reduced. write is always at + // last used position + 1 + if (rColorSteps.size() > write) + { + rColorSteps.resize(write); + } + + if (bSameColorInit && bAllTheSameColor && rColorSteps.size() > 1) + { + // id all-the-same color is detected, reset to single + // entry, but also force to StartColor and preserve the color + rColorSteps.resize(1); + rColorSteps[0] = ColorStep(0.0, aFirstColor); + } + } + BColor modifyBColor( const ColorSteps& rColorSteps, double fScaler, |