diff options
author | Armin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de> | 2023-05-12 15:32:51 +0200 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@me.com> | 2023-05-15 15:19:53 +0200 |
commit | 438f0752deaf7d6e6d9d1df381b64aca4628e944 (patch) | |
tree | f1907b25dad1cbf2604b16c657e11f5623c8b5b2 /include/basegfx | |
parent | efa965969c6d3dfe5745a535605a6b9a482a03bd (diff) |
MCGR: consolidations/cleanups for changes so far
Change-Id: I85cf40e4803b0485bb40349d8e81adc8123666c4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151706
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Diffstat (limited to 'include/basegfx')
-rw-r--r-- | include/basegfx/utils/bgradient.hxx | 323 | ||||
-rw-r--r-- | include/basegfx/utils/gradienttools.hxx | 242 |
2 files changed, 377 insertions, 188 deletions
diff --git a/include/basegfx/utils/bgradient.hxx b/include/basegfx/utils/bgradient.hxx new file mode 100644 index 000000000000..37de614faba7 --- /dev/null +++ b/include/basegfx/utils/bgradient.hxx @@ -0,0 +1,323 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <config_options.h> +#include <basegfx/color/bcolor.hxx> +#include <basegfx/basegfxdllapi.h> +#include <vector> +#include <com/sun/star/awt/Gradient2.hpp> +#include <com/sun/star/awt/GradientStyle.hpp> +#include <tools/degree.hxx> +#include <boost/property_tree/ptree_fwd.hpp> + +namespace com +{ +namespace sun +{ +namespace star +{ +namespace uno +{ +class Any; +} +} +} +} + +namespace basegfx +{ +/* MCGR: Provide ColorStop 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<ColorStop> ColorStops, + see typedef below. + */ +class BASEGFX_DLLPUBLIC BColorStop +{ +private: + // offset in the range of [0.0 .. 1.0] + double mfStopOffset; + + // RGB color of ColorStop entry + BColor maStopColor; + +public: + // constructor - defaults are needed to have a default constructor + // e.g. for usage in std::vector::insert (even when only reducing) + // ensure [0.0 .. 1.0] range for mfStopOffset + BColorStop(double fStopOffset = 0.0, const BColor& rStopColor = BColor()) + : mfStopOffset(fStopOffset) + , maStopColor(rStopColor) + { + // NOTE: I originally *corrected* mfStopOffset here by using + // mfStopOffset(std::max(0.0, std::min(fOffset, 1.0))) + // While that is formally correct, it moves an invalid + // entry to 0.0 or 1.0, thus creating additional wrong + // Start/EndColor entries. That may then 'overlay' the + // correct entry when corrections are applied to the + // vector of entries (see sortAndCorrectColorStops) + // which leads to getting the wanted Start/EndColor + // to be factically deleted, what is an error. + } + + double getStopOffset() const { return mfStopOffset; } + const BColor& getStopColor() const { return maStopColor; } + + // needed for std::sort + bool operator<(const BColorStop& rCandidate) const + { + return getStopOffset() < rCandidate.getStopOffset(); + } + + bool operator==(const BColorStop& rCandidate) const + { + return getStopOffset() == rCandidate.getStopOffset() + && getStopColor() == rCandidate.getStopColor(); + } +}; + +/* MCGR: Provide ColorStops definition to the FillGradientAttribute + + This array should be sorted ascending by offsets, from lowest to + highest. Since all the primitive data definition where it is used + is read-only, this can/will be guaranteed by forcing/checking this + in the constructor, see ::FillGradientAttribute + */ +class BASEGFX_DLLPUBLIC BColorStops final : public std::vector<BColorStop> +{ +private: + void setColorStopSequence(const css::awt::ColorStopSequence& rColorStops); + +public: + explicit BColorStops() + : vector() + { + } + BColorStops(const BColorStops& other) + : vector(other) + { + } + BColorStops(BColorStops&& other) noexcept + : vector(std::move(other)) + { + } + BColorStops(std::initializer_list<BColorStop> init) + : vector(init) + { + } + BColorStops(const_iterator first, const_iterator last) + : vector(first, last) + { + } + BColorStops(const css::awt::ColorStopSequence& rColorStops); + BColorStops(const css::uno::Any& rVal); + + // constuctor with two colors to explicitly create a + // BColorStops for StartColor @0.0 & EndColor @1.0 + BColorStops(const BColor& rStart, const BColor& rEnd); + + BColorStops& operator=(const BColorStops& r) + { + vector::operator=(r); + return *this; + } + BColorStops& operator=(BColorStops&& r) noexcept + { + vector::operator=(std::move(r)); + return *this; + } + + // helper data struct to support buffering entries in + // gradient texture mapping, see usages for more info + struct BColorStopRange + { + basegfx::BColor maColorStart; + basegfx::BColor maColorEnd; + double mfOffsetStart; + double mfOffsetEnd; + + BColorStopRange() + : maColorStart() + , maColorEnd() + , mfOffsetStart(0.0) + , mfOffsetEnd(0.0) + { + } + }; + + /* Helper to grep the correct ColorStop out of + ColorStops and interpolate as needed for given + relative value in fPosition in the range of [0.0 .. 1.0]. + It also takes care of evtl. given RequestedSteps. + */ + BColor getInterpolatedBColor(double fPosition, sal_uInt32 nRequestedSteps, + BColorStopRange& rLastColorStopRange) const; + + /* Tooling method that allows to replace the StartColor in a + vector of ColorStops. A vector in 'ordered state' is expected, + so you may use/have used sortAndCorrect. + This method is for convenience & backwards compatibility, please + think about handling multi-colored gradients directly. + */ + void replaceStartColor(const BColor& rStart); + + /* Tooling method that allows to replace the EndColor in a + vector of ColorStops. A vector in 'ordered state' is expected, + so you may use/have used sortAndCorrect. + This method is for convenience & backwards compatibility, please + think about handling multi-colored gradients directly. + */ + void replaceEndColor(const BColor& rEnd); + + /* 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 respectively, 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 blendToIntensity(double fStartIntensity, double fEndIntensity, const BColor& rBlendColor); + + /* Tooling method to guarantee sort and correctness for + the given ColorStops vector. + A vector fulfilling these conditions is called to be + in 'ordered state'. + + At return, the following conditions are guaranteed: + - contains no ColorStops with offset < 0.0 (will + be removed) + - contains no ColorStops with offset > 1.0 (will + be removed) + - ColorStops with identical offsets are now allowed + - will be sorted from lowest offset to highest + + 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 technically required + - A entry with 1.0 is not required or forced, so + no 'EndColor' is technically required + + All this is done in one run (sort + O(N)) without + creating a copy of the data in any form + */ + void sortAndCorrect(); + + // check if we need last-ColorStop-correction. This returns true if the last + // two ColorStops have the same offset but different Colors. In that case the + // tesselation for gradients does have to create an extra ending/closing enty + bool checkPenultimate() const; + + /* Tooling method to fill a awt::ColorStopSequence with + the data from the given ColorStops. This is used in + UNO API implementations. + */ + css::awt::ColorStopSequence getAsColorStopSequence() const; + + /* 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 + color for convenience. + NOTE: If no ColorStop is defined, a fallback to BColor-default + (which is black) and true will be returned + */ + bool isSingleColor(BColor& rSingleColor) const; + + /* Tooling method to reverse ColorStops, including offsets. + When also mirroring offsets a valid sort keeps valid. + */ + void reverseColorStops(); +}; + +class BASEGFX_DLLPUBLIC BGradient final +{ + css::awt::GradientStyle eStyle; + + // MCGS: ColorStops in the range [0.0 .. 1.0], including StartColor/EndColor + basegfx::BColorStops aColorStops; + + Degree10 nAngle; + sal_uInt16 nBorder; + sal_uInt16 nOfsX; + sal_uInt16 nOfsY; + sal_uInt16 nIntensStart; + sal_uInt16 nIntensEnd; + sal_uInt16 nStepCount; + + static std::string GradientStyleToString(css::awt::GradientStyle eStyle); + +public: + BGradient(); + BGradient(const basegfx::BColorStops& rColorStops, + css::awt::GradientStyle eStyle = css::awt::GradientStyle_LINEAR, + Degree10 nAngle = 0_deg10, sal_uInt16 nXOfs = 50, sal_uInt16 nYOfs = 50, + sal_uInt16 nBorder = 0, sal_uInt16 nStartIntens = 100, sal_uInt16 nEndIntens = 100, + sal_uInt16 nSteps = 0); + BGradient(const css::awt::Gradient2& rGradient2); + BGradient(const css::uno::Any& rVal); + + bool operator==(const BGradient& rGradient) const; + + void SetGradientStyle(css::awt::GradientStyle eNewStyle) { eStyle = eNewStyle; } + void SetColorStops(const basegfx::BColorStops& rSteps); + void SetAngle(Degree10 nNewAngle) { nAngle = nNewAngle; } + void SetBorder(sal_uInt16 nNewBorder) { nBorder = nNewBorder; } + void SetXOffset(sal_uInt16 nNewOffset) { nOfsX = nNewOffset; } + void SetYOffset(sal_uInt16 nNewOffset) { nOfsY = nNewOffset; } + void SetStartIntens(sal_uInt16 nNewIntens) { nIntensStart = nNewIntens; } + void SetEndIntens(sal_uInt16 nNewIntens) { nIntensEnd = nNewIntens; } + void SetSteps(sal_uInt16 nSteps) { nStepCount = nSteps; } + + css::awt::GradientStyle GetGradientStyle() const { return eStyle; } + const basegfx::BColorStops& GetColorStops() const { return aColorStops; } + Degree10 GetAngle() const { return nAngle; } + sal_uInt16 GetBorder() const { return nBorder; } + sal_uInt16 GetXOffset() const { return nOfsX; } + sal_uInt16 GetYOffset() const { return nOfsY; } + sal_uInt16 GetStartIntens() const { return nIntensStart; } + sal_uInt16 GetEndIntens() const { return nIntensEnd; } + sal_uInt16 GetSteps() const { return nStepCount; } + + boost::property_tree::ptree dumpAsJSON() const; + static BGradient fromJSON(std::u16string_view rJSON); + + /// Tooling method to fill awt::Gradient2 from data contained in the given basegfx::BGradient + css::awt::Gradient2 getAsGradient2() const; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/utils/gradienttools.hxx b/include/basegfx/utils/gradienttools.hxx index 502ef190b8ce..d9e685a87fb6 100644 --- a/include/basegfx/utils/gradienttools.hxx +++ b/include/basegfx/utils/gradienttools.hxx @@ -28,88 +28,77 @@ #include <basegfx/basegfxdllapi.h> #include <vector> #include <com/sun/star/awt/ColorStopSequence.hdl> +#include <basegfx/utils/bgradient.hxx> +#include <osl/endian.h> namespace com { namespace sun { namespace star { namespace uno { class Any; } } } } namespace com { namespace sun { namespace star { namespace awt { struct Gradient2; } } } } namespace basegfx { class B2DRange; } -namespace basegfx +namespace { - /* MCGR: Provide ColorStop 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<ColorStop> ColorStops, - see typedef below. + /* Internal helper to convert ::Color from tools::color.hxx to BColor + without the need to link against tools library. Be on the + safe side by using the same union */ - class UNLESS_MERGELIBS(BASEGFX_DLLPUBLIC) ColorStop + struct ColorToBColorConverter { - private: - // offset in the range of [0.0 .. 1.0] - double mfStopOffset; + union { + sal_uInt32 mValue; + struct { +#ifdef OSL_BIGENDIAN + sal_uInt8 T; + sal_uInt8 R; + sal_uInt8 G; + sal_uInt8 B; +#else + sal_uInt8 B; + sal_uInt8 G; + sal_uInt8 R; + sal_uInt8 T; +#endif + }; + }; + + ColorToBColorConverter GetRGBColor() const + { + return {R, G, B}; + } - // RGB color of ColorStop entry - BColor maStopColor; + ColorToBColorConverter(sal_uInt32 nColor) + : mValue(nColor) + { T=0; } - public: - // constructor - defaults are needed to have a default constructor - // e.g. for usage in std::vector::insert (even when only reducing) - // ensure [0.0 .. 1.0] range for mfStopOffset - ColorStop(double fStopOffset = 0.0, const BColor& rStopColor = BColor()) - : mfStopOffset(fStopOffset) - , maStopColor(rStopColor) + constexpr ColorToBColorConverter(sal_uInt8 nRed, sal_uInt8 nGreen, sal_uInt8 nBlue) + : mValue(sal_uInt32(nBlue) | (sal_uInt32(nGreen) << 8) | (sal_uInt32(nRed) << 16)) + {} + + explicit ColorToBColorConverter(const basegfx::BColor& rBColor) + : ColorToBColorConverter( + sal_uInt8(std::lround(rBColor.getRed() * 255.0)), + sal_uInt8(std::lround(rBColor.getGreen() * 255.0)), + sal_uInt8(std::lround(rBColor.getBlue() * 255.0))) + {} + + basegfx::BColor getBColor() const { - // NOTE: I originally *corrected* mfStopOffset here by using - // mfStopOffset(std::max(0.0, std::min(fOffset, 1.0))) - // While that is formally correct, it moves an invalid - // entry to 0.0 or 1.0, thus creating additional wrong - // Start/EndColor entries. That may then 'overlay' the - // correct entry when corrections are applied to the - // vector of entries (see sortAndCorrectColorStops) - // which leads to getting the wanted Start/EndColor - // to be factically deleted, what is an error. + return basegfx::BColor(R / 255.0, G / 255.0, B / 255.0); } - double getStopOffset() const { return mfStopOffset; } - const BColor& getStopColor() const { return maStopColor; } - - // needed for std::sort - bool operator<(const ColorStop& rCandidate) const + constexpr explicit operator sal_Int32() const { - return getStopOffset() < rCandidate.getStopOffset(); + return sal_Int32(mValue); } - bool operator==(const ColorStop& rCandidate) const + constexpr explicit operator sal_uInt32() const { - return getStopOffset() == rCandidate.getStopOffset() && getStopColor() == rCandidate.getStopColor(); + return mValue; } }; +} - /* MCGR: Provide ColorStops definition to the FillGradientAttribute - - This array should be sorted ascending by offsets, from lowest to - highest. Since all the primitive data definition where it is used - is read-only, this can/will be guaranteed by forcing/checking this - in the constructor, see ::FillGradientAttribute - */ - typedef std::vector<ColorStop> ColorStops; - +namespace basegfx +{ /** Gradient definition as used in ODF 1.2 This struct collects all data necessary for rendering ODF @@ -195,23 +184,6 @@ namespace basegfx } }; - // helper data struct to support buffering entries in - // gradient texture mapping, see usages for more info - struct UNLESS_MERGELIBS(BASEGFX_DLLPUBLIC) ColorStopRange - { - basegfx::BColor maColorStart; - basegfx::BColor maColorEnd; - double mfOffsetStart; - double mfOffsetEnd; - - ColorStopRange() - : maColorStart() - , maColorEnd() - , mfOffsetStart(0.0) - , mfOffsetEnd(0.0) - {} - }; - namespace utils { /// Tooling method to fill awt::Gradient2 from data contained in the given Any @@ -235,7 +207,7 @@ namespace basegfx */ BASEGFX_DLLPUBLIC void prepareColorStops( const com::sun::star::awt::Gradient2& rGradient, - ColorStops& rColorStops, + BColorStops& rColorStops, BColor& rSingleColor); /* Tooling method to synchronize the given ColorStops. @@ -256,117 +228,11 @@ namespace basegfx 'FillTransparenceGradient' method (at import time). */ BASEGFX_DLLPUBLIC void synchronizeColorStops( - ColorStops& rColorStops, - ColorStops& rAlphaStops, + BColorStops& rColorStops, + BColorStops& rAlphaStops, const BColor& rSingleColor, const BColor& rSingleAlpha); - /* 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 respectively, 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 - color for convenience. - NOTE: If no ColorStop is defined, a fallback to BColor-default - (which is black) and true will be returned - */ - BASEGFX_DLLPUBLIC bool isSingleColor(const ColorStops& rColorStops, BColor& rSingleColor); - - /* Tooling method to reverse ColorStops, including offsets. - When also mirroring offsets a valid sort keeps valid. - */ - BASEGFX_DLLPUBLIC void reverseColorStops(ColorStops& rColorStops); - - /* Tooling method to convert UNO API data to ColorStops. - This will try to extract ColorStop data from the given - awt::Gradient2. - */ - BASEGFX_DLLPUBLIC void fillColorStopsFromGradient2(ColorStops& rColorStops, const com::sun::star::awt::Gradient2& rGradient); - - /* Tooling method to convert UNO API data to ColorStops. - This will try to extract ColorStop data from the given - Any, so if it's of type awt::Gradient2 that data will be - extracted, converted and copied into the given ColorStops. - */ - BASEGFX_DLLPUBLIC void fillColorStopsFromAny(ColorStops& rColorStops, const css::uno::Any& rVal); - - /* Tooling method to fill a awt::ColorStopSequence with - the data from the given ColorStops. This is used in - UNO API implementations. - */ - BASEGFX_DLLPUBLIC void fillColorStopSequenceFromColorStops(css::awt::ColorStopSequence& rColorStopSequence, const ColorStops& rColorStops); - - /* Tooling method that allows to replace the StartColor in a - vector of ColorStops. A vector in 'ordered state' is expected, - so you may use/have used sortAndCorrectColorStops, see below. - This method is for convenience & backwards compatibility, please - think about handling multi-colored gradients directly. - */ - BASEGFX_DLLPUBLIC void replaceStartColor(ColorStops& rColorStops, const BColor& rStart); - - /* Tooling method that allows to replace the EndColor in a - vector of ColorStops. A vector in 'ordered state' is expected, - so you may use/have used sortAndCorrectColorStops, see below. - This method is for convenience & backwards compatibility, please - think about handling multi-colored gradients directly. - */ - BASEGFX_DLLPUBLIC void replaceEndColor(ColorStops& rColorStops, const BColor& rEnd); - - // Tooling method to quickly create a ColorStop vector for a given set of Start/EndColor - BASEGFX_DLLPUBLIC ColorStops createColorStopsFromStartEndColor(const BColor& rStart, const BColor& rEnd); - - /* Tooling method to guarantee sort and correctness for - the given ColorStops vector. - A vector fulfilling these conditions is called to be - in 'ordered state'. - - At return, the following conditions are guaranteed: - - contains no ColorStops with offset < 0.0 (will - be removed) - - contains no ColorStops with offset > 1.0 (will - be removed) - - ColorStops with identical offsets are now allowed - - will be sorted from lowest offset to highest - - 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 technically required - - A entry with 1.0 is not required or forced, so - no 'EndColor' is technically required - - All this is done in one run (sort + O(N)) without - creating a copy of the data in any form - */ - BASEGFX_DLLPUBLIC void sortAndCorrectColorStops(ColorStops& rColorStops); - - /* Helper to grep the correct ColorStop out of - ColorStops and interpolate as needed for given - relative value in fScaler in the range of [0.0 .. 1.0]. - It also takes care of evtl. given RequestedSteps. - */ - BASEGFX_DLLPUBLIC BColor modifyBColor( - const ColorStops& rColorStops, - double fScaler, - sal_uInt32 nRequestedSteps, - ColorStopRange& rLastColorStopRange); - /* Helper to calculate numberOfSteps needed to represent gradient for the given two colors: - to define only based on color distance, give 0 == nRequestedSteps |