diff --git a/basegfx/source/tools/bgradient.cxx b/basegfx/source/tools/bgradient.cxx index e27ab160463b..bac738ad3221 100644 --- a/basegfx/source/tools/bgradient.cxx +++ b/basegfx/source/tools/bgradient.cxx @@ -746,6 +746,25 @@ void BColorStops::tryToApplyBColorModifierStack(const BColorModifierStack& rBCol } } +bool BColorStops::sameSizeAndDistances(const BColorStops& rComp) const +{ + if (size() != rComp.size()) + { + return false; + } + + BColorStops::const_iterator EntryA(begin()); + BColorStops::const_iterator EntryB(rComp.begin()); + + while (EntryA != end() && fTools::equal(EntryA->getStopOffset(), EntryB->getStopOffset())) + { + EntryA++; + EntryB++; + } + + return EntryA == end(); +} + std::string BGradient::GradientStyleToString(css::awt::GradientStyle eStyle) { switch (eStyle) diff --git a/drawinglayer/source/attribute/fillgradientattribute.cxx b/drawinglayer/source/attribute/fillgradientattribute.cxx index e02fdd4a5dad..54f455f647ef 100644 --- a/drawinglayer/source/attribute/fillgradientattribute.cxx +++ b/drawinglayer/source/attribute/fillgradientattribute.cxx @@ -223,6 +223,39 @@ namespace drawinglayer::attribute return mpFillGradientAttribute->getSteps(); } + bool FillGradientAttribute::sameDefinitionThanAlpha(const FillGradientAttribute& rAlpha) const + { + // entries that are used by all gradient styles + if (getStyle() != rAlpha.getStyle() + || getBorder() != rAlpha.getBorder() + || getSteps() != rAlpha.getSteps()) + { + return false; + } + + // check for offsets if not ignored + const bool bIgnoreOffset(css::awt::GradientStyle_LINEAR == getStyle() || css::awt::GradientStyle_AXIAL == getStyle()); + if (!bIgnoreOffset && (getOffsetX() != rAlpha.getOffsetX() || getOffsetY() != rAlpha.getOffsetY())) + { + return false; + } + + // check for angle if not ignored + const bool bIgnoreAngle(css::awt::GradientStyle_RADIAL == getStyle()); + if (!bIgnoreAngle && getAngle() != rAlpha.getAngle()) + { + return false; + } + + // check for same count & offsets in the gradients (all except 'colors') + if (!getColorStops().sameSizeAndDistances(rAlpha.getColorStops())) + { + return false; + } + + return true; + } + } // end of namespace /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/drawinglayer/source/primitive2d/PolyPolygonGradientPrimitive2D.cxx b/drawinglayer/source/primitive2d/PolyPolygonGradientPrimitive2D.cxx index 4fe3321e62f8..2e6b83ab526f 100644 --- a/drawinglayer/source/primitive2d/PolyPolygonGradientPrimitive2D.cxx +++ b/drawinglayer/source/primitive2d/PolyPolygonGradientPrimitive2D.cxx @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include @@ -84,6 +86,50 @@ sal_uInt32 PolyPolygonGradientPrimitive2D::getPrimitive2DID() const return PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D; } +Primitive2DReference PolyPolygonRGBAGradientPrimitive2D::create2DDecomposition( + const geometry::ViewInformation2D& /*rViewInformation*/) const +{ + Primitive2DContainer aContent{ new PolyPolygonGradientPrimitive2D( + getB2DPolyPolygon(), getDefinitionRange(), getFillGradient()) }; + + Primitive2DContainer aAlpha{ new FillGradientPrimitive2D( + basegfx::utils::getRange(getB2DPolyPolygon()), getDefinitionRange(), + getFillGradientAlpha()) }; + + return Primitive2DReference{ new TransparencePrimitive2D(std::move(aContent), + std::move(aAlpha)) }; +} + +PolyPolygonRGBAGradientPrimitive2D::PolyPolygonRGBAGradientPrimitive2D( + basegfx::B2DPolyPolygon aPolyPolygon, const basegfx::B2DRange& rDefinitionRange, + attribute::FillGradientAttribute aFillGradient, + attribute::FillGradientAttribute aFillGradientAlpha) + : PolyPolygonGradientPrimitive2D(aPolyPolygon, rDefinitionRange, aFillGradient) + , maFillGradientAlpha(aFillGradientAlpha) +{ + // assert when the definition is not allowed, it HAS to fulfil the + // requested preconditions + assert(aFillGradient.sameDefinitionThanAlpha(aFillGradientAlpha)); +} + +bool PolyPolygonRGBAGradientPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const +{ + if (PolyPolygonGradientPrimitive2D::operator==(rPrimitive)) + { + const PolyPolygonRGBAGradientPrimitive2D& rCompare + = static_cast(rPrimitive); + + return getFillGradientAlpha() == rCompare.getFillGradientAlpha(); + } + + return false; +} + +sal_uInt32 PolyPolygonRGBAGradientPrimitive2D::getPrimitive2DID() const +{ + return PRIMITIVE2D_ID_POLYPOLYGONRGBAGRADIENTPRIMITIVE2D; +} + } // end drawinglayer::primitive2d namespace /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/drawinglayer/source/primitive2d/Tools.cxx b/drawinglayer/source/primitive2d/Tools.cxx index bd74a4b5cd00..b13505bc3fd6 100644 --- a/drawinglayer/source/primitive2d/Tools.cxx +++ b/drawinglayer/source/primitive2d/Tools.cxx @@ -233,6 +233,8 @@ OUString idToString(sal_uInt32 nId) return u"SINGLELINEPRIMITIVE"_ustr; case PRIMITIVE2D_ID_EXCLUSIVEEDITVIEWPRIMITIVE2D: return u"EXCLUSIVEEDITVIEWPRIMITIVE2D"_ustr; + case PRIMITIVE2D_ID_POLYPOLYGONRGBAGRADIENTPRIMITIVE2D: + return u"POLYPOLYGONRGBAGRADIENTPRIMITIVE2D"_ustr; default: return OUString::number((nId >> 16) & 0xFF) + "|" + OUString::number(nId & 0xFF); } diff --git a/include/basegfx/utils/bgradient.hxx b/include/basegfx/utils/bgradient.hxx index f54b8763d87f..2ac8eba41d61 100644 --- a/include/basegfx/utils/bgradient.hxx +++ b/include/basegfx/utils/bgradient.hxx @@ -264,6 +264,10 @@ public: // Apply BColorModifierStack changes void tryToApplyBColorModifierStack(const BColorModifierStack& rBColorModifierStack); + + // check if local and given BColorStops have same count and distances, + // ignore colors + bool sameSizeAndDistances(const BColorStops& rComp) const; }; class BASEGFX_DLLPUBLIC BGradient final diff --git a/include/drawinglayer/attribute/fillgradientattribute.hxx b/include/drawinglayer/attribute/fillgradientattribute.hxx index 462d7fc8151e..62b890b5f0c1 100644 --- a/include/drawinglayer/attribute/fillgradientattribute.hxx +++ b/include/drawinglayer/attribute/fillgradientattribute.hxx @@ -83,6 +83,10 @@ public: // cannot do at all) bool cannotBeHandledByVCL() const; + // check if local and given FillGradientAttribute are identical, + // do take care of exceptions (e.g. no offset for linear/axial, ...) + bool sameDefinitionThanAlpha(const FillGradientAttribute& rAlpha) const; + // compare operator bool operator==(const FillGradientAttribute& rCandidate) const; diff --git a/include/drawinglayer/primitive2d/PolyPolygonGradientPrimitive2D.hxx b/include/drawinglayer/primitive2d/PolyPolygonGradientPrimitive2D.hxx index 1d4495806d15..07ec3460101e 100644 --- a/include/drawinglayer/primitive2d/PolyPolygonGradientPrimitive2D.hxx +++ b/include/drawinglayer/primitive2d/PolyPolygonGradientPrimitive2D.hxx @@ -33,7 +33,7 @@ namespace drawinglayer::primitive2d decomosition will create a MaskPrimitive2D containing a FillGradientPrimitive2D. */ -class DRAWINGLAYER_DLLPUBLIC PolyPolygonGradientPrimitive2D final +class DRAWINGLAYER_DLLPUBLIC PolyPolygonGradientPrimitive2D : public BufferedDecompositionPrimitive2D { private: @@ -70,6 +70,45 @@ public: virtual sal_uInt32 getPrimitive2DID() const override; }; +// helper primitive that can be used to directly express RGBA +// gradient definitions. It will be decomposed to a combined +// TransparencePrimitive2D if not handled directly. Use the +// already existing PolyPolygonGradientPrimitive2D as base class, +// only the additional FillGradientAlpha needs to be added. +// NOTE: FillGradientAlpha *has* to fulfil the +// 'sameDefinitionThanAlpha' coindition defined by the check +// method with the same name +class DRAWINGLAYER_DLLPUBLIC PolyPolygonRGBAGradientPrimitive2D final + : public PolyPolygonGradientPrimitive2D +{ +private: + /// the gradient alpha definition + attribute::FillGradientAttribute maFillGradientAlpha; + + /// local decomposition. + virtual Primitive2DReference + create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const override; + +public: + /// constructors. The one without definition range will use output range as definition range + PolyPolygonRGBAGradientPrimitive2D(basegfx::B2DPolyPolygon aPolyPolygon, + const basegfx::B2DRange& rDefinitionRange, + attribute::FillGradientAttribute aFillGradient, + attribute::FillGradientAttribute aFillGradientAlpha); + + /// data read access + const attribute::FillGradientAttribute& getFillGradientAlpha() const + { + return maFillGradientAlpha; + } + + /// compare operator + virtual bool operator==(const BasePrimitive2D& rPrimitive) const override; + + /// provide unique ID + virtual sal_uInt32 getPrimitive2DID() const override; +}; + } // end of namespace primitive2d::drawinglayer /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx b/include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx index f276caa8ec04..2345a4b86071 100644 --- a/include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx +++ b/include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx @@ -108,6 +108,8 @@ #define PRIMITIVE2D_ID_FILLEDRECTANGLEPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 74) #define PRIMITIVE2D_ID_SINGLELINEPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 75) #define PRIMITIVE2D_ID_EXCLUSIVEEDITVIEWPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 76) +#define PRIMITIVE2D_ID_POLYPOLYGONRGBAGRADIENTPRIMITIVE2D (PRIMITIVE2D_ID_RANGE_DRAWINGLAYER| 77) + // When you add a new primitive, please update the drawinglayer::primitive2d::idToString() function // in drawinglayer/source/primitive2d/Tools.cxx. diff --git a/svx/inc/sdr/primitive2d/sdrdecompositiontools.hxx b/svx/inc/sdr/primitive2d/sdrdecompositiontools.hxx index ac65e0eda30f..e504acd41ab6 100644 --- a/svx/inc/sdr/primitive2d/sdrdecompositiontools.hxx +++ b/svx/inc/sdr/primitive2d/sdrdecompositiontools.hxx @@ -47,13 +47,13 @@ namespace drawinglayer::primitive2d Primitive2DReference SVXCORE_DLLPUBLIC createPolyPolygonFillPrimitive( const basegfx::B2DPolyPolygon& rPolyPolygon, const attribute::SdrFillAttribute& rFill, - const attribute::FillGradientAttribute& rFillGradient); + const attribute::FillGradientAttribute& rAlphaGradient); Primitive2DReference SVXCORE_DLLPUBLIC createPolyPolygonFillPrimitive( const basegfx::B2DPolyPolygon& rPolyPolygon, const basegfx::B2DRange& rDefinitionRange, const attribute::SdrFillAttribute& rFill, - const attribute::FillGradientAttribute& rFillGradient); + const attribute::FillGradientAttribute& rAlphaGradient); Primitive2DReference SVXCORE_DLLPUBLIC createPolygonLinePrimitive( const basegfx::B2DPolygon& rPolygon, diff --git a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx index 2913f19b2548..10b48f851443 100644 --- a/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx +++ b/svx/source/sdr/primitive2d/sdrdecompositiontools.cxx @@ -368,12 +368,10 @@ sal_uInt32 SlideBackgroundFillPrimitive2D::getPrimitive2DID() const }; // end of anonymous namespace - class TransparencePrimitive2D; - Primitive2DReference createPolyPolygonFillPrimitive( const basegfx::B2DPolyPolygon& rPolyPolygon, const attribute::SdrFillAttribute& rFill, - const attribute::FillGradientAttribute& rFillGradient) + const attribute::FillGradientAttribute& rAlphaGradient) { // when we have no given definition range, use the range of the given geometry // also for definition (simplest case) @@ -383,29 +381,53 @@ sal_uInt32 SlideBackgroundFillPrimitive2D::getPrimitive2DID() const rPolyPolygon, aRange, rFill, - rFillGradient); + rAlphaGradient); } Primitive2DReference createPolyPolygonFillPrimitive( const basegfx::B2DPolyPolygon& rPolyPolygon, const basegfx::B2DRange& rDefinitionRange, const attribute::SdrFillAttribute& rFill, - const attribute::FillGradientAttribute& rFillGradient) + const attribute::FillGradientAttribute& rAlphaGradient) { if(basegfx::fTools::moreOrEqual(rFill.getTransparence(), 1.0)) { return Primitive2DReference(); } + const attribute::FillGradientAttribute& rFillGradient(rFill.getGradient()); + + // SDPR: check if RGB and A definitions of gradients are both + // used and equal, so that they could be combined to a single + // RGBA one + if (!rFillGradient.isDefault() + && 0.0 == rFill.getTransparence() + && !rAlphaGradient.isDefault() + && rFillGradient.sameDefinitionThanAlpha(rAlphaGradient)) + { + // if yes, create a primitive expressing that. That primitive's + // decomnpose will do the same as if the code below would be executed, + // so no primitive renderer who does not want to will have to handle + // it - but SDPR renderers that can directly render that may choose to + // do so. NOTE: That helper primitive just holds references to what + // would be created anyways, so one depth step added but not really any + // additional data + return new PolyPolygonRGBAGradientPrimitive2D( + rPolyPolygon, + rDefinitionRange, + rFillGradient, + rAlphaGradient); + } + // prepare fully scaled polygon rtl::Reference pNewFillPrimitive; - if(!rFill.getGradient().isDefault()) + if(!rFillGradient.isDefault()) { pNewFillPrimitive = new PolyPolygonGradientPrimitive2D( rPolyPolygon, rDefinitionRange, - rFill.getGradient()); + rFillGradient); } else if(!rFill.getHatch().isDefault()) { @@ -442,7 +464,7 @@ sal_uInt32 SlideBackgroundFillPrimitive2D::getPrimitive2DID() const Primitive2DContainer aContent { pNewFillPrimitive }; return new UnifiedTransparencePrimitive2D(std::move(aContent), rFill.getTransparence()); } - else if(!rFillGradient.isDefault()) + else if(!rAlphaGradient.isDefault()) { // create sequence with created fill primitive Primitive2DContainer aContent { pNewFillPrimitive }; @@ -453,7 +475,7 @@ sal_uInt32 SlideBackgroundFillPrimitive2D::getPrimitive2DID() const new FillGradientPrimitive2D( basegfx::utils::getRange(rPolyPolygon), rDefinitionRange, - rFillGradient) + rAlphaGradient) }; // create TransparencePrimitive2D using alpha and content