diff options
author | Armin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de> | 2023-02-10 11:36:15 +0100 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@me.com> | 2023-02-12 10:54:06 +0000 |
commit | 43de98fb59ef3cd1c6eabd3174d57634b7d501a9 (patch) | |
tree | 2e926642ae6c4d595fa546bd02b21535c9e6a740 /drawinglayer | |
parent | 496b1b3179ca096dea1fd91ab2408c02f16b06cf (diff) |
MCGR: Add/Provide GradientSteps to FillGradientAttribute
MCGR stands for MultiColorGRadient. This change allows/
prepares adding multiple color steps to gradient rendering.
This is preparation work to allow rendering MCGRs in the
future. All places are adapted in a way that currently
no change of behaviour will happen. It will be the base
to get MCGR rendering/decompose for Primitives and our
internal/existing gradients working.
Change-Id: I28bbd7d10b8670042343ada2a66b5909d3d31bbd
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146748
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Diffstat (limited to 'drawinglayer')
7 files changed, 128 insertions, 41 deletions
diff --git a/drawinglayer/source/attribute/fillgradientattribute.cxx b/drawinglayer/source/attribute/fillgradientattribute.cxx index b8b06e20bbbf..3d13c4050670 100644 --- a/drawinglayer/source/attribute/fillgradientattribute.cxx +++ b/drawinglayer/source/attribute/fillgradientattribute.cxx @@ -18,8 +18,6 @@ */ #include <drawinglayer/attribute/fillgradientattribute.hxx> -#include <basegfx/color/bcolor.hxx> - namespace drawinglayer::attribute { @@ -31,8 +29,7 @@ namespace drawinglayer::attribute double mfOffsetX; double mfOffsetY; double mfAngle; - basegfx::BColor maStartColor; - basegfx::BColor maEndColor; + FillGradientAttribute::ColorSteps maColorSteps; GradientStyle meStyle; sal_uInt16 mnSteps; @@ -44,16 +41,62 @@ namespace drawinglayer::attribute double fAngle, const basegfx::BColor& rStartColor, const basegfx::BColor& rEndColor, + const FillGradientAttribute::ColorSteps* pColorSteps, sal_uInt16 nSteps) : mfBorder(fBorder), mfOffsetX(fOffsetX), mfOffsetY(fOffsetY), mfAngle(fAngle), - maStartColor(rStartColor), - maEndColor(rEndColor), + maColorSteps(), meStyle(eStyle), mnSteps(nSteps) { + // always add start color to guarentee a color at all. It's also just safer + // 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) + { + for(const auto& candidate : *pColorSteps) + { + // only allow ]0.0 .. 1.0[ as offset values, *excluding* 0.0 and 1.0 + // explicitely - these are reserved for start/end color + if(basegfx::fTools::more(candidate.getOffset(), 0.0) && basegfx::fTools::less(candidate.getOffset(), 1.0)) + { + // 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); + } + } + } + + // sort by offset when colors were added + if(maColorSteps.size() > 1) + { + std::sort(maColorSteps.begin(), maColorSteps.end()); + } + } + + // add end color if different from last color - which is the start color + // when no ColorSteps are given + if(rEndColor != maColorSteps.back().getColor()) + { + maColorSteps.emplace_back(1.0, rEndColor); + } } ImpFillGradientAttribute() @@ -61,9 +104,12 @@ namespace drawinglayer::attribute mfOffsetX(0.0), mfOffsetY(0.0), mfAngle(0.0), + maColorSteps(), meStyle(GradientStyle::Linear), mnSteps(0) { + // always add a fallback color, see above + maColorSteps.emplace_back(0.0, basegfx::BColor()); } // data read access @@ -72,10 +118,25 @@ namespace drawinglayer::attribute double getOffsetX() const { return mfOffsetX; } double getOffsetY() const { return mfOffsetY; } double getAngle() const { return mfAngle; } - const basegfx::BColor& getStartColor() const { return maStartColor; } - const basegfx::BColor& getEndColor() const { return maEndColor; } + const FillGradientAttribute::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; + } + bool operator==(const ImpFillGradientAttribute& rCandidate) const { return (getStyle() == rCandidate.getStyle() @@ -83,8 +144,7 @@ namespace drawinglayer::attribute && getOffsetX() == rCandidate.getOffsetX() && getOffsetY() == rCandidate.getOffsetY() && getAngle() == rCandidate.getAngle() - && getStartColor() == rCandidate.getStartColor() - && getEndColor() == rCandidate.getEndColor() + && getColorSteps() == rCandidate.getColorSteps() && getSteps() == rCandidate.getSteps()); } }; @@ -106,9 +166,10 @@ namespace drawinglayer::attribute double fAngle, const basegfx::BColor& rStartColor, const basegfx::BColor& rEndColor, + const ColorSteps* pColorSteps, sal_uInt16 nSteps) : mpFillGradientAttribute(ImpFillGradientAttribute( - eStyle, fBorder, fOffsetX, fOffsetY, fAngle, rStartColor, rEndColor, nSteps)) + eStyle, fBorder, fOffsetX, fOffsetY, fAngle, rStartColor, rEndColor, pColorSteps, nSteps)) { } @@ -128,6 +189,11 @@ namespace drawinglayer::attribute return mpFillGradientAttribute.same_object(theGlobalDefault()); } + bool FillGradientAttribute::hasSingleColor() const + { + return mpFillGradientAttribute->hasSingleColor(); + } + FillGradientAttribute& FillGradientAttribute::operator=(const FillGradientAttribute&) = default; FillGradientAttribute& FillGradientAttribute::operator=(FillGradientAttribute&&) = default; @@ -141,14 +207,9 @@ namespace drawinglayer::attribute return rCandidate.mpFillGradientAttribute == mpFillGradientAttribute; } - const basegfx::BColor& FillGradientAttribute::getStartColor() const - { - return mpFillGradientAttribute->getStartColor(); - } - - const basegfx::BColor& FillGradientAttribute::getEndColor() const + const FillGradientAttribute::ColorSteps& FillGradientAttribute::getColorSteps() const { - return mpFillGradientAttribute->getEndColor(); + return mpFillGradientAttribute->getColorSteps(); } double FillGradientAttribute::getBorder() const diff --git a/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx b/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx index 5ca0b5852642..0f6eef0508cb 100644 --- a/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx @@ -38,8 +38,8 @@ namespace drawinglayer::primitive2d rEntries.clear(); // make sure steps is not too high/low - const basegfx::BColor aStart(getFillGradient().getStartColor()); - const basegfx::BColor aEnd(getFillGradient().getEndColor()); + 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()); diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index 33257f48175a..b5989303dd43 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -258,19 +258,20 @@ void VclMetafileProcessor2D::impConvertFillGradientAttributeToVCLGradient( Gradient& o_rVCLGradient, const attribute::FillGradientAttribute& rFiGrAtt, bool bIsTransparenceGradient) const { + const basegfx::BColor aStartColor(rFiGrAtt.getColorSteps().front().getColor()); + const basegfx::BColor aEndColor(rFiGrAtt.getColorSteps().back().getColor()); + if (bIsTransparenceGradient) { // it's about transparence channel intensities (black/white), do not use color modifier - o_rVCLGradient.SetStartColor(Color(rFiGrAtt.getStartColor())); - o_rVCLGradient.SetEndColor(Color(rFiGrAtt.getEndColor())); + o_rVCLGradient.SetStartColor(Color(aStartColor)); + o_rVCLGradient.SetEndColor(Color(aEndColor)); } else { // use color modifier to influence start/end color of gradient - o_rVCLGradient.SetStartColor( - Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getStartColor()))); - o_rVCLGradient.SetEndColor( - Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getEndColor()))); + o_rVCLGradient.SetStartColor(Color(maBColorModifierStack.getModifiedColor(aStartColor))); + o_rVCLGradient.SetEndColor(Color(maBColorModifierStack.getModifiedColor(aEndColor))); } o_rVCLGradient.SetAngle( diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index 7852131ee98f..7a171b915524 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -498,8 +498,10 @@ void VclPixelProcessor2D::processPolyPolygonGradientPrimitive2D( { // direct draw of gradient const attribute::FillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient()); - basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor())); - basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor())); + basegfx::BColor aStartColor( + maBColorModifierStack.getModifiedColor(rGradient.getColorSteps().front().getColor())); + basegfx::BColor aEndColor( + maBColorModifierStack.getModifiedColor(rGradient.getColorSteps().back().getColor())); basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon()); if (!aLocalPolyPolygon.count()) @@ -935,6 +937,14 @@ void VclPixelProcessor2D::processFillGradientPrimitive2D( { const attribute::FillGradientAttribute& rFillGradient = rPrimitive.getFillGradient(); + // MCGR: If GradientSteps are used, use decomposition since vcl is not able + // to render multi-color gradients + if (rFillGradient.getColorSteps().size() > 2) + { + process(rPrimitive); + return; + } + // VCL should be able to handle all styles, but for tdf#133477 the VCL result // is different from processing the gradient manually by drawinglayer // (and the Writer unittest for it fails). Keep using the drawinglayer code @@ -983,8 +993,8 @@ void VclPixelProcessor2D::processFillGradientPrimitive2D( GradientStyle eGradientStyle = convertGradientStyle(rFillGradient.getStyle()); - Gradient aGradient(eGradientStyle, Color(rFillGradient.getStartColor()), - Color(rFillGradient.getEndColor())); + Gradient aGradient(eGradientStyle, Color(rFillGradient.getColorSteps().front().getColor()), + Color(rFillGradient.getColorSteps().back().getColor())); aGradient.SetAngle(Degree10(static_cast<int>(basegfx::rad2deg<10>(rFillGradient.getAngle())))); aGradient.SetBorder(rFillGradient.getBorder() * 100); diff --git a/drawinglayer/source/processor3d/defaultprocessor3d.cxx b/drawinglayer/source/processor3d/defaultprocessor3d.cxx index b9159c46c73f..6be8e78d0d59 100644 --- a/drawinglayer/source/processor3d/defaultprocessor3d.cxx +++ b/drawinglayer/source/processor3d/defaultprocessor3d.cxx @@ -61,8 +61,8 @@ namespace drawinglayer::processor3d 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.getStartColor()); - const basegfx::BColor& aEnd(rFillGradient.getEndColor()); + 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; diff --git a/drawinglayer/source/tools/primitive2dxmldump.cxx b/drawinglayer/source/tools/primitive2dxmldump.cxx index 74e95836fdf9..65967980d110 100644 --- a/drawinglayer/source/tools/primitive2dxmldump.cxx +++ b/drawinglayer/source/tools/primitive2dxmldump.cxx @@ -299,8 +299,22 @@ void writeSdrFillAttribute(::tools::XmlWriter& rWriter, rWriter.attribute("offsetY", rGradient.getOffsetY()); rWriter.attribute("angle", rGradient.getAngle()); rWriter.attribute("steps", rGradient.getSteps()); - rWriter.attribute("startColor", convertColorToString(rGradient.getStartColor())); - rWriter.attribute("endColor", convertColorToString(rGradient.getEndColor())); + + auto const& rColorSteps(rGradient.getColorSteps()); + for (size_t a(0); a < rColorSteps.size(); a++) + { + if (0 == a) + rWriter.attribute("startColor", convertColorToString(rColorSteps[a].getColor())); + else if (rColorSteps.size() == a + 1) + rWriter.attribute("endColor", convertColorToString(rColorSteps[a].getColor())); + else + { + rWriter.startElement("colorStep"); + rWriter.attribute("offset", rColorSteps[a].getOffset()); + rWriter.attribute("color", convertColorToString(rColorSteps[a].getColor())); + rWriter.endElement(); + } + } rWriter.endElement(); } diff --git a/drawinglayer/source/tools/wmfemfhelper.cxx b/drawinglayer/source/tools/wmfemfhelper.cxx index 3a06f6423665..21a88757c954 100644 --- a/drawinglayer/source/tools/wmfemfhelper.cxx +++ b/drawinglayer/source/tools/wmfemfhelper.cxx @@ -718,6 +718,7 @@ namespace wmfemfhelper toRadians(rGradient.GetAngle()), aStart, aEnd, + nullptr, rGradient.GetSteps()); } @@ -919,10 +920,10 @@ namespace wmfemfhelper { drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient)); - if(aAttribute.getStartColor() == aAttribute.getEndColor()) + if(aAttribute.hasSingleColor()) { // not really a gradient. Create filled rectangle - return CreateColorWallpaper(rRange, aAttribute.getStartColor(), rPropertyHolder); + return CreateColorWallpaper(rRange, aAttribute.getColorSteps().front().getColor(), rPropertyHolder); } else { @@ -2089,7 +2090,7 @@ namespace wmfemfhelper drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient)); basegfx::B2DPolyPolygon aOutline(basegfx::utils::createPolygonFromRect(aRange)); - if(aAttribute.getStartColor() == aAttribute.getEndColor()) + if(aAttribute.hasSingleColor()) { // not really a gradient. Create filled rectangle createFillPrimitive( @@ -2799,13 +2800,13 @@ namespace wmfemfhelper const Gradient& rGradient = pA->GetGradient(); drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient)); - if(aAttribute.getStartColor() == aAttribute.getEndColor()) + if(aAttribute.hasSingleColor()) { // not really a gradient; create UnifiedTransparencePrimitive2D rTargetHolders.Current().append( new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( std::move(xSubContent), - aAttribute.getStartColor().luminance())); + aAttribute.getColorSteps().front().getColor().luminance())); } else { @@ -2919,13 +2920,13 @@ namespace wmfemfhelper const Gradient& rGradient = pMetaGradientExAction->GetGradient(); drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient)); - if(aAttribute.getStartColor() == aAttribute.getEndColor()) + if(aAttribute.hasSingleColor()) { // not really a gradient rTargetHolders.Current().append( new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( std::move(aPolyPolygon), - aAttribute.getStartColor())); + aAttribute.getColorSteps().front().getColor())); } else { |