diff options
Diffstat (limited to 'drawinglayer/source/primitive2d/svggradientprimitive2d.cxx')
-rw-r--r-- | drawinglayer/source/primitive2d/svggradientprimitive2d.cxx | 445 |
1 files changed, 236 insertions, 209 deletions
diff --git a/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx b/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx index d3e32e22ea46..5784e8ec9e1b 100644 --- a/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/svggradientprimitive2d.cxx @@ -20,17 +20,18 @@ #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx> #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> #include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx> -#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> #include <basegfx/polygon/b2dpolygontools.hxx> #include <basegfx/polygon/b2dpolygon.hxx> #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx> #include <drawinglayer/primitive2d/transformprimitive2d.hxx> #include <drawinglayer/primitive2d/maskprimitive2d.hxx> -#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <drawinglayer/primitive2d/PolyPolygonRGBAPrimitive2D.hxx> +#include <osl/diagnose.h> #include <sal/log.hxx> #include <cmath> - +#include <utility> +#include <vcl/skia/SkiaHelper.hxx> using namespace com::sun::star; @@ -61,45 +62,46 @@ namespace namespace drawinglayer::primitive2d { - void SvgGradientHelper::createSingleGradientEntryFill(Primitive2DContainer& rContainer) const + Primitive2DReference SvgGradientHelper::createSingleGradientEntryFill() const { - const SvgGradientEntryVector& rEntries = getGradientEntries(); + const SvgGradientEntryVector& rEntries(getGradientEntries()); const sal_uInt32 nCount(rEntries.size()); - if(nCount) + if(0 == nCount) { - const SvgGradientEntry& rSingleEntry = rEntries[nCount - 1]; - const double fOpacity(rSingleEntry.getOpacity()); - - if(fOpacity > 0.0) - { - Primitive2DReference xRef( - new PolyPolygonColorPrimitive2D( - getPolyPolygon(), - rSingleEntry.getColor())); - - if(fOpacity < 1.0) - { - const Primitive2DContainer aContent { xRef }; + // no entries, done + OSL_ENSURE(false, "Single gradient entry construction without entry (!)"); + return nullptr; + } - xRef = Primitive2DReference( - new UnifiedTransparencePrimitive2D( - aContent, - 1.0 - fOpacity)); - } + const SvgGradientEntry& rSingleEntry(rEntries[nCount - 1]); + const double fOpacity(rSingleEntry.getOpacity()); - rContainer.push_back(xRef); - } + if (fOpacity <= 0.0 || basegfx::fTools::equalZero(fOpacity)) + { + // completely opaque, done + return nullptr; } - else + + if (basegfx::fTools::moreOrEqual(fOpacity, 1.0)) { - OSL_ENSURE(false, "Single gradient entry construction without entry (!)"); + // no opacity + return Primitive2DReference { + new PolyPolygonColorPrimitive2D( + getPolyPolygon(), + rSingleEntry.getColor()) }; } + + // if transparent, use PolyPolygonRGBAPrimitive2D + return Primitive2DReference { + new PolyPolygonRGBAPrimitive2D( + getPolyPolygon(), + rSingleEntry.getColor(), + 1.0 - fOpacity) }; } void SvgGradientHelper::checkPreconditions() { - mbPreconditionsChecked = true; const SvgGradientEntryVector& rEntries = getGradientEntries(); if(rEntries.empty()) @@ -186,7 +188,7 @@ namespace drawinglayer::primitive2d const bool bMirror(SpreadMethod::Reflect == getSpreadMethod() && 0 != rInt % 2); const SvgGradientEntryVector& rCurrent(bMirror ? getMirroredGradientEntries() : getGradientEntries()); - for(SvgGradientEntryVector::const_reverse_iterator aIter(rCurrent.rbegin()); aIter != rCurrent.rend(); aIter++) + for(SvgGradientEntryVector::const_reverse_iterator aIter(rCurrent.rbegin()); aIter != rCurrent.rend(); ++aIter) { if(basegfx::fTools::lessOrEqual(aIter->getOffset(), fFrac)) { @@ -208,7 +210,7 @@ namespace drawinglayer::primitive2d const bool bMirror(SpreadMethod::Reflect == getSpreadMethod() && 0 != rInt % 2); const SvgGradientEntryVector& rCurrent(bMirror ? getMirroredGradientEntries() : getGradientEntries()); - for(SvgGradientEntryVector::const_iterator aIter(rCurrent.begin()); aIter != rCurrent.end(); aIter++) + for(SvgGradientEntryVector::const_iterator aIter(rCurrent.begin()); aIter != rCurrent.end(); ++aIter) { if(basegfx::fTools::more(aIter->getOffset(), fFrac)) { @@ -303,26 +305,25 @@ namespace drawinglayer::primitive2d } } - void SvgGradientHelper::createResult( - Primitive2DContainer& rContainer, - const Primitive2DContainer& rTargetColor, - const Primitive2DContainer& rTargetOpacity, + Primitive2DReference SvgGradientHelper::createResult( + Primitive2DContainer aTargetColor, + Primitive2DContainer aTargetOpacity, const basegfx::B2DHomMatrix& rUnitGradientToObject, bool bInvert) const { - const Primitive2DContainer aTargetColorEntries(rTargetColor.maybeInvert(bInvert)); - const Primitive2DContainer aTargetOpacityEntries(rTargetOpacity.maybeInvert(bInvert)); + Primitive2DContainer aTargetColorEntries(aTargetColor.maybeInvert(bInvert)); + Primitive2DContainer aTargetOpacityEntries(aTargetOpacity.maybeInvert(bInvert)); if(aTargetColorEntries.empty()) - return; + return nullptr; Primitive2DReference xRefContent; if(!aTargetOpacityEntries.empty()) { const Primitive2DReference xRefOpacity = new TransparencePrimitive2D( - aTargetColorEntries, - aTargetOpacityEntries); + std::move(aTargetColorEntries), + std::move(aTargetOpacityEntries)); xRefContent = new TransformPrimitive2D( rUnitGradientToObject, @@ -332,28 +333,26 @@ namespace drawinglayer::primitive2d { xRefContent = new TransformPrimitive2D( rUnitGradientToObject, - aTargetColorEntries); + std::move(aTargetColorEntries)); } - rContainer.push_back(new MaskPrimitive2D( + return new MaskPrimitive2D( getPolyPolygon(), - Primitive2DContainer { xRefContent })); + Primitive2DContainer { xRefContent }); } SvgGradientHelper::SvgGradientHelper( - const basegfx::B2DHomMatrix& rGradientTransform, - const basegfx::B2DPolyPolygon& rPolyPolygon, - const SvgGradientEntryVector& rGradientEntries, + basegfx::B2DHomMatrix aGradientTransform, + basegfx::B2DPolyPolygon aPolyPolygon, + SvgGradientEntryVector&& rGradientEntries, const basegfx::B2DPoint& rStart, bool bUseUnitCoordinates, SpreadMethod aSpreadMethod) - : maGradientTransform(rGradientTransform), - maPolyPolygon(rPolyPolygon), - maGradientEntries(rGradientEntries), - maMirroredGradientEntries(), + : maGradientTransform(std::move(aGradientTransform)), + maPolyPolygon(std::move(aPolyPolygon)), + maGradientEntries(std::move(rGradientEntries)), maStart(rStart), maSpreadMethod(aSpreadMethod), - mbPreconditionsChecked(false), mbCreatesContent(false), mbSingleEntry(false), mbFullyOpaque(true), @@ -377,7 +376,7 @@ namespace drawinglayer::primitive2d void SvgGradientHelper::createMirroredGradientEntries() { - if(!(maMirroredGradientEntries.empty() && !getGradientEntries().empty())) + if(!maMirroredGradientEntries.empty() || getGradientEntries().empty()) return; const sal_uInt32 nCount(getGradientEntries().size()); @@ -465,64 +464,66 @@ namespace drawinglayer::primitive2d } } - void SvgLinearGradientPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const + basegfx::B2DHomMatrix SvgLinearGradientPrimitive2D::createUnitGradientToObjectTransformation() const { - if(!getPreconditionsChecked()) + const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange()); + const double fPolyWidth(aPolyRange.getWidth()); + const double fPolyHeight(aPolyRange.getHeight()); + + // create ObjectTransform based on polygon range + const basegfx::B2DHomMatrix aObjectTransform( + basegfx::utils::createScaleTranslateB2DHomMatrix( + fPolyWidth, fPolyHeight, + aPolyRange.getMinX(), aPolyRange.getMinY())); + basegfx::B2DHomMatrix aUnitGradientToObject; + + if(getUseUnitCoordinates()) { - const_cast< SvgLinearGradientPrimitive2D* >(this)->checkPreconditions(); + // interpret in unit coordinate system -> object aspect ratio will scale result + // create unit transform from unit vector [0.0 .. 1.0] along the X-Axis to given + // gradient vector defined by Start,End + const basegfx::B2DVector aVector(getEnd() - getStart()); + const double fVectorLength(aVector.getLength()); + + aUnitGradientToObject.scale(fVectorLength, 1.0); + aUnitGradientToObject.rotate(atan2(aVector.getY(), aVector.getX())); + aUnitGradientToObject.translate(getStart().getX(), getStart().getY()); + + aUnitGradientToObject *= getGradientTransform(); + + // create full transform from unit gradient coordinates to object coordinates + // including the SvgGradient transformation + aUnitGradientToObject *= aObjectTransform; } + else + { + // interpret in object coordinate system -> object aspect ratio will not scale result + const basegfx::B2DPoint aStart(aObjectTransform * getStart()); + const basegfx::B2DPoint aEnd(aObjectTransform * getEnd()); + const basegfx::B2DVector aVector(aEnd - aStart); + + aUnitGradientToObject.scale(aVector.getLength(), 1.0); + aUnitGradientToObject.rotate(atan2(aVector.getY(), aVector.getX())); + aUnitGradientToObject.translate(aStart.getX(), aStart.getY()); + + aUnitGradientToObject *= getGradientTransform(); + } + + return aUnitGradientToObject; + } + Primitive2DReference SvgLinearGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { if(getSingleEntry()) { // fill with last existing color - createSingleGradientEntryFill(rContainer); + return createSingleGradientEntryFill(); } else if(getCreatesContent()) { // at least two color stops in range [0.0 .. 1.0], sorted, non-null vector, not completely // invisible, width and height to fill are not empty - const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange()); - const double fPolyWidth(aPolyRange.getWidth()); - const double fPolyHeight(aPolyRange.getHeight()); - - // create ObjectTransform based on polygon range - const basegfx::B2DHomMatrix aObjectTransform( - basegfx::utils::createScaleTranslateB2DHomMatrix( - fPolyWidth, fPolyHeight, - aPolyRange.getMinX(), aPolyRange.getMinY())); - basegfx::B2DHomMatrix aUnitGradientToObject; - - if(getUseUnitCoordinates()) - { - // interpret in unit coordinate system -> object aspect ratio will scale result - // create unit transform from unit vector [0.0 .. 1.0] along the X-Axis to given - // gradient vector defined by Start,End - const basegfx::B2DVector aVector(getEnd() - getStart()); - const double fVectorLength(aVector.getLength()); - - aUnitGradientToObject.scale(fVectorLength, 1.0); - aUnitGradientToObject.rotate(atan2(aVector.getY(), aVector.getX())); - aUnitGradientToObject.translate(getStart().getX(), getStart().getY()); - - aUnitGradientToObject *= getGradientTransform(); - - // create full transform from unit gradient coordinates to object coordinates - // including the SvgGradient transformation - aUnitGradientToObject *= aObjectTransform; - } - else - { - // interpret in object coordinate system -> object aspect ratio will not scale result - const basegfx::B2DPoint aStart(aObjectTransform * getStart()); - const basegfx::B2DPoint aEnd(aObjectTransform * getEnd()); - const basegfx::B2DVector aVector(aEnd - aStart); - - aUnitGradientToObject.scale(aVector.getLength(), 1.0); - aUnitGradientToObject.rotate(atan2(aVector.getY(), aVector.getX())); - aUnitGradientToObject.translate(aStart.getX(), aStart.getY()); - - aUnitGradientToObject *= getGradientTransform(); - } + basegfx::B2DHomMatrix aUnitGradientToObject(createUnitGradientToObjectTransformation()); // create inverse from it basegfx::B2DHomMatrix aObjectToUnitGradient(aUnitGradientToObject); @@ -538,7 +539,7 @@ namespace drawinglayer::primitive2d Primitive2DContainer aTargetColor; Primitive2DContainer aTargetOpacity; - if(basegfx::fTools::more(aUnitRange.getWidth(), 0.0)) + if(aUnitRange.getWidth() > 0.0) { // add a pre-multiply to aUnitGradientToObject to allow // multiplication of the polygon(xl, 0.0, xr, 1.0) @@ -555,22 +556,24 @@ namespace drawinglayer::primitive2d aUnitRange.getMaxX()); } - createResult(rContainer, aTargetColor, aTargetOpacity, aUnitGradientToObject); + return createResult(std::move(aTargetColor), std::move(aTargetOpacity), aUnitGradientToObject); } + return nullptr; } SvgLinearGradientPrimitive2D::SvgLinearGradientPrimitive2D( const basegfx::B2DHomMatrix& rGradientTransform, const basegfx::B2DPolyPolygon& rPolyPolygon, - const SvgGradientEntryVector& rGradientEntries, + SvgGradientEntryVector&& rGradientEntries, const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd, bool bUseUnitCoordinates, SpreadMethod aSpreadMethod) - : BufferedDecompositionPrimitive2D(), - SvgGradientHelper(rGradientTransform, rPolyPolygon, rGradientEntries, rStart, bUseUnitCoordinates, aSpreadMethod), + : SvgGradientHelper(rGradientTransform, rPolyPolygon, std::move(rGradientEntries), rStart, bUseUnitCoordinates, aSpreadMethod), maEnd(rEnd) { + // ensure Preconditions are checked + checkPreconditions(); } SvgLinearGradientPrimitive2D::~SvgLinearGradientPrimitive2D() @@ -598,7 +601,10 @@ namespace drawinglayer::primitive2d } // provide unique ID - ImplPrimitive2DIDBlock(SvgLinearGradientPrimitive2D, PRIMITIVE2D_ID_SVGLINEARGRADIENTPRIMITIVE2D) + sal_uInt32 SvgLinearGradientPrimitive2D::getPrimitive2DID() const + { + return PRIMITIVE2D_ID_SVGLINEARGRADIENTPRIMITIVE2D; + } } // end of namespace drawinglayer::primitive2d @@ -641,8 +647,9 @@ namespace drawinglayer::primitive2d if(isFocalSet()) { - const basegfx::B2DVector aTranslateFrom(maFocalVector * (maFocalLength - fScaleFrom)); - const basegfx::B2DVector aTranslateTo(maFocalVector * (maFocalLength - fScaleTo)); + const basegfx::B2DVector aFocalVector(getFocal() - getStart()); + const basegfx::B2DVector aTranslateFrom(aFocalVector * (maFocalLength - fScaleFrom)); + const basegfx::B2DVector aTranslateTo(aFocalVector * (maFocalLength - fScaleTo)); rTargetColor.push_back( new SvgRadialAtomPrimitive2D( @@ -666,8 +673,9 @@ namespace drawinglayer::primitive2d if(isFocalSet()) { - const basegfx::B2DVector aTranslateFrom(maFocalVector * (maFocalLength - fScaleFrom)); - const basegfx::B2DVector aTranslateTo(maFocalVector * (maFocalLength - fScaleTo)); + const basegfx::B2DVector aFocalVector(getFocal() - getStart()); + const basegfx::B2DVector aTranslateFrom(aFocalVector * (maFocalLength - fScaleFrom)); + const basegfx::B2DVector aTranslateTo(aFocalVector * (maFocalLength - fScaleTo)); rTargetOpacity.push_back( new SvgRadialAtomPrimitive2D( @@ -685,62 +693,64 @@ namespace drawinglayer::primitive2d } } - void SvgRadialGradientPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const + basegfx::B2DHomMatrix SvgRadialGradientPrimitive2D::createUnitGradientToObjectTransformation() const { - if(!getPreconditionsChecked()) + const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange()); + const double fPolyWidth(aPolyRange.getWidth()); + const double fPolyHeight(aPolyRange.getHeight()); + + // create ObjectTransform based on polygon range + const basegfx::B2DHomMatrix aObjectTransform( + basegfx::utils::createScaleTranslateB2DHomMatrix( + fPolyWidth, fPolyHeight, + aPolyRange.getMinX(), aPolyRange.getMinY())); + basegfx::B2DHomMatrix aUnitGradientToObject; + + if(getUseUnitCoordinates()) + { + // interpret in unit coordinate system -> object aspect ratio will scale result + // create unit transform from unit vector to given linear gradient vector + aUnitGradientToObject.scale(getRadius(), getRadius()); + aUnitGradientToObject.translate(getStart().getX(), getStart().getY()); + + if(!getGradientTransform().isIdentity()) + { + aUnitGradientToObject = getGradientTransform() * aUnitGradientToObject; + } + + // create full transform from unit gradient coordinates to object coordinates + // including the SvgGradient transformation + aUnitGradientToObject = aObjectTransform * aUnitGradientToObject; + } + else { - const_cast< SvgRadialGradientPrimitive2D* >(this)->checkPreconditions(); + // interpret in object coordinate system -> object aspect ratio will not scale result + // use X-Axis with radius, it was already made relative to object width when coming from + // SVG import + const double fRadius((aObjectTransform * basegfx::B2DVector(getRadius(), 0.0)).getLength()); + const basegfx::B2DPoint aStart(aObjectTransform * getStart()); + + aUnitGradientToObject.scale(fRadius, fRadius); + aUnitGradientToObject.translate(aStart.getX(), aStart.getY()); + + aUnitGradientToObject *= getGradientTransform(); } + return aUnitGradientToObject; + } + + Primitive2DReference SvgRadialGradientPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const + { if(getSingleEntry()) { // fill with last existing color - createSingleGradientEntryFill(rContainer); + return createSingleGradientEntryFill(); } else if(getCreatesContent()) { // at least two color stops in range [0.0 .. 1.0], sorted, non-null vector, not completely // invisible, width and height to fill are not empty - const basegfx::B2DRange aPolyRange(getPolyPolygon().getB2DRange()); - const double fPolyWidth(aPolyRange.getWidth()); - const double fPolyHeight(aPolyRange.getHeight()); - - // create ObjectTransform based on polygon range - const basegfx::B2DHomMatrix aObjectTransform( - basegfx::utils::createScaleTranslateB2DHomMatrix( - fPolyWidth, fPolyHeight, - aPolyRange.getMinX(), aPolyRange.getMinY())); - basegfx::B2DHomMatrix aUnitGradientToObject; - - if(getUseUnitCoordinates()) - { - // interpret in unit coordinate system -> object aspect ratio will scale result - // create unit transform from unit vector to given linear gradient vector - aUnitGradientToObject.scale(getRadius(), getRadius()); - aUnitGradientToObject.translate(getStart().getX(), getStart().getY()); - - if(!getGradientTransform().isIdentity()) - { - aUnitGradientToObject = getGradientTransform() * aUnitGradientToObject; - } - - // create full transform from unit gradient coordinates to object coordinates - // including the SvgGradient transformation - aUnitGradientToObject = aObjectTransform * aUnitGradientToObject; - } - else - { - // interpret in object coordinate system -> object aspect ratio will not scale result - // use X-Axis with radius, it was already made relative to object width when coming from - // SVG import - const double fRadius((aObjectTransform * basegfx::B2DVector(getRadius(), 0.0)).getLength()); - const basegfx::B2DPoint aStart(aObjectTransform * getStart()); - - aUnitGradientToObject.scale(fRadius, fRadius); - aUnitGradientToObject.translate(aStart.getX(), aStart.getY()); - - aUnitGradientToObject *= getGradientTransform(); - } + basegfx::B2DHomMatrix aUnitGradientToObject(createUnitGradientToObjectTransformation()); // create inverse from it basegfx::B2DHomMatrix aObjectToUnitGradient(aUnitGradientToObject); @@ -779,33 +789,32 @@ namespace drawinglayer::primitive2d fMax); } - createResult(rContainer, aTargetColor, aTargetOpacity, aUnitGradientToObject, true); + return createResult(std::move(aTargetColor), std::move(aTargetOpacity), aUnitGradientToObject, true); } + return nullptr; } SvgRadialGradientPrimitive2D::SvgRadialGradientPrimitive2D( const basegfx::B2DHomMatrix& rGradientTransform, const basegfx::B2DPolyPolygon& rPolyPolygon, - const SvgGradientEntryVector& rGradientEntries, + SvgGradientEntryVector&& rGradientEntries, const basegfx::B2DPoint& rStart, double fRadius, bool bUseUnitCoordinates, SpreadMethod aSpreadMethod, const basegfx::B2DPoint* pFocal) - : BufferedDecompositionPrimitive2D(), - SvgGradientHelper(rGradientTransform, rPolyPolygon, rGradientEntries, rStart, bUseUnitCoordinates, aSpreadMethod), + : SvgGradientHelper(rGradientTransform, rPolyPolygon, std::move(rGradientEntries), rStart, bUseUnitCoordinates, aSpreadMethod), mfRadius(fRadius), maFocal(rStart), - maFocalVector(0.0, 0.0), - maFocalLength(0.0), - mbFocalSet(false) + maFocalLength(0.0) { if(pFocal && !pFocal->equal(getStart())) { maFocal = *pFocal; - maFocalVector = maFocal - getStart(); - mbFocalSet = true; } + + // ensure Preconditions are checked + checkPreconditions(); } SvgRadialGradientPrimitive2D::~SvgRadialGradientPrimitive2D() @@ -816,22 +825,22 @@ namespace drawinglayer::primitive2d { const SvgGradientHelper* pSvgGradientHelper = dynamic_cast< const SvgGradientHelper* >(&rPrimitive); - if(pSvgGradientHelper && SvgGradientHelper::operator==(*pSvgGradientHelper)) - { - const SvgRadialGradientPrimitive2D& rCompare = static_cast< const SvgRadialGradientPrimitive2D& >(rPrimitive); + if(!pSvgGradientHelper || !SvgGradientHelper::operator==(*pSvgGradientHelper)) + return false; + + const SvgRadialGradientPrimitive2D& rCompare = static_cast< const SvgRadialGradientPrimitive2D& >(rPrimitive); - if(getRadius() == rCompare.getRadius()) + if(getRadius() == rCompare.getRadius()) + { + if(isFocalSet() == rCompare.isFocalSet()) { - if(isFocalSet() == rCompare.isFocalSet()) + if(isFocalSet()) { - if(isFocalSet()) - { - return getFocal() == rCompare.getFocal(); - } - else - { - return true; - } + return getFocal() == rCompare.getFocal(); + } + else + { + return true; } } } @@ -846,7 +855,10 @@ namespace drawinglayer::primitive2d } // provide unique ID - ImplPrimitive2DIDBlock(SvgRadialGradientPrimitive2D, PRIMITIVE2D_ID_SVGRADIALGRADIENTPRIMITIVE2D) + sal_uInt32 SvgRadialGradientPrimitive2D::getPrimitive2DID() const + { + return PRIMITIVE2D_ID_SVGRADIALGRADIENTPRIMITIVE2D; + } } // end of namespace drawinglayer::primitive2d @@ -855,12 +867,12 @@ namespace drawinglayer::primitive2d namespace drawinglayer::primitive2d { - void SvgLinearAtomPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const + Primitive2DReference SvgLinearAtomPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const { const double fDelta(getOffsetB() - getOffsetA()); if(basegfx::fTools::equalZero(fDelta)) - return; + return nullptr; // use one discrete unit for overlap (one pixel) const double fDiscreteUnit(getDiscreteUnit()); @@ -868,6 +880,12 @@ namespace drawinglayer::primitive2d // use color distance and discrete lengths to calculate step count const sal_uInt32 nSteps(calculateStepsForSvgGradient(getColorA(), getColorB(), fDelta, fDiscreteUnit)); + // HACK: Splitting a gradient into adjacent polygons with gradually changing color is silly. + // If antialiasing is used to draw them, the AA-ed adjacent edges won't line up perfectly + // because of the AA (see SkiaSalGraphicsImpl::mergePolyPolygonToPrevious()). + // Make the polygons a bit wider, so they the partial overlap "fixes" this. + const double fixup = SkiaHelper::isVCLSkiaEnabled() ? fDiscreteUnit / 2 : 0; + // tdf#117949 Use a small amount of discrete overlap at the edges. Usually this // should be exactly 0.0 and 1.0, but there were cases when this gets clipped // against the mask polygon which got numerically problematic. @@ -881,29 +899,31 @@ namespace drawinglayer::primitive2d basegfx::B2DRange( getOffsetA() - fDiscreteUnit, -0.0001, // TTTT -> should be 0.0, see comment above - getOffsetA() + (fDelta / nSteps) + fDiscreteUnit, + getOffsetA() + (fDelta / nSteps) + fDiscreteUnit + fixup, 1.0001))); // TTTT -> should be 1.0, see comment above // prepare loop (inside to outside, [0.0 .. 1.0[) double fUnitScale(0.0); const double fUnitStep(1.0 / nSteps); + Primitive2DContainer aContainer; + aContainer.resize(nSteps); for(sal_uInt32 a(0); a < nSteps; a++, fUnitScale += fUnitStep) { basegfx::B2DPolygon aNew(aPolygon); - aNew.transform(basegfx::utils::createTranslateB2DHomMatrix(fDelta * fUnitScale, 0.0)); - rContainer.push_back(new PolyPolygonColorPrimitive2D( + aNew.translate(fDelta * fUnitScale, 0.0); + aContainer[a] = new PolyPolygonColorPrimitive2D( basegfx::B2DPolyPolygon(aNew), - basegfx::interpolate(getColorA(), getColorB(), fUnitScale))); + basegfx::interpolate(getColorA(), getColorB(), fUnitScale)); } + return new GroupPrimitive2D(std::move(aContainer)); } SvgLinearAtomPrimitive2D::SvgLinearAtomPrimitive2D( const basegfx::BColor& aColorA, double fOffsetA, const basegfx::BColor& aColorB, double fOffsetB) - : DiscreteMetricDependentPrimitive2D(), - maColorA(aColorA), + : maColorA(aColorA), maColorB(aColorB), mfOffsetA(fOffsetA), mfOffsetB(fOffsetB) @@ -931,7 +951,10 @@ namespace drawinglayer::primitive2d } // provide unique ID - ImplPrimitive2DIDBlock(SvgLinearAtomPrimitive2D, PRIMITIVE2D_ID_SVGLINEARATOMPRIMITIVE2D) + sal_uInt32 SvgLinearAtomPrimitive2D::getPrimitive2DID() const + { + return PRIMITIVE2D_ID_SVGLINEARATOMPRIMITIVE2D; + } } // end of namespace drawinglayer::primitive2d @@ -940,12 +963,12 @@ namespace drawinglayer::primitive2d namespace drawinglayer::primitive2d { - void SvgRadialAtomPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const + Primitive2DReference SvgRadialAtomPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const { const double fDeltaScale(getScaleB() - getScaleA()); if(basegfx::fTools::equalZero(fDeltaScale)) - return; + return nullptr; // use one discrete unit for overlap (one pixel) const double fDiscreteUnit(getDiscreteUnit()); @@ -957,6 +980,8 @@ namespace drawinglayer::primitive2d double fUnitScale(0.0); const double fUnitStep(1.0 / nSteps); + Primitive2DContainer aContainer; + aContainer.resize(nSteps); for(sal_uInt32 a(0); a < nSteps; a++, fUnitScale += fUnitStep) { basegfx::B2DHomMatrix aTransform; @@ -986,17 +1011,17 @@ namespace drawinglayer::primitive2d basegfx::B2DPolygon aNew(basegfx::utils::createPolygonFromUnitCircle()); aNew.transform(aTransform); - rContainer.push_back(new PolyPolygonColorPrimitive2D( + aContainer[a] = new PolyPolygonColorPrimitive2D( basegfx::B2DPolyPolygon(aNew), - basegfx::interpolate(getColorB(), getColorA(), fUnitScale))); + basegfx::interpolate(getColorB(), getColorA(), fUnitScale)); } + return new GroupPrimitive2D(std::move(aContainer)); } SvgRadialAtomPrimitive2D::SvgRadialAtomPrimitive2D( const basegfx::BColor& aColorA, double fScaleA, const basegfx::B2DVector& rTranslateA, const basegfx::BColor& aColorB, double fScaleB, const basegfx::B2DVector& rTranslateB) - : DiscreteMetricDependentPrimitive2D(), - maColorA(aColorA), + : maColorA(aColorA), maColorB(aColorB), mfScaleA(fScaleA), mfScaleB(fScaleB) @@ -1027,8 +1052,7 @@ namespace drawinglayer::primitive2d SvgRadialAtomPrimitive2D::SvgRadialAtomPrimitive2D( const basegfx::BColor& aColorA, double fScaleA, const basegfx::BColor& aColorB, double fScaleB) - : DiscreteMetricDependentPrimitive2D(), - maColorA(aColorA), + : maColorA(aColorA), maColorB(aColorB), mfScaleA(fScaleA), mfScaleB(fScaleB) @@ -1051,24 +1075,24 @@ namespace drawinglayer::primitive2d bool SvgRadialAtomPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const { - if(DiscreteMetricDependentPrimitive2D::operator==(rPrimitive)) - { - const SvgRadialAtomPrimitive2D& rCompare = static_cast< const SvgRadialAtomPrimitive2D& >(rPrimitive); + if(!DiscreteMetricDependentPrimitive2D::operator==(rPrimitive)) + return false; - if(getColorA() == rCompare.getColorA() - && getColorB() == rCompare.getColorB() - && getScaleA() == rCompare.getScaleA() - && getScaleB() == rCompare.getScaleB()) + const SvgRadialAtomPrimitive2D& rCompare = static_cast< const SvgRadialAtomPrimitive2D& >(rPrimitive); + + if(getColorA() == rCompare.getColorA() + && getColorB() == rCompare.getColorB() + && getScaleA() == rCompare.getScaleA() + && getScaleB() == rCompare.getScaleB()) + { + if(isTranslateSet() && rCompare.isTranslateSet()) { - if(isTranslateSet() && rCompare.isTranslateSet()) - { - return (getTranslateA() == rCompare.getTranslateA() - && getTranslateB() == rCompare.getTranslateB()); - } - else if(!isTranslateSet() && !rCompare.isTranslateSet()) - { - return true; - } + return (getTranslateA() == rCompare.getTranslateA() + && getTranslateB() == rCompare.getTranslateB()); + } + else if(!isTranslateSet() && !rCompare.isTranslateSet()) + { + return true; } } @@ -1076,7 +1100,10 @@ namespace drawinglayer::primitive2d } // provide unique ID - ImplPrimitive2DIDBlock(SvgRadialAtomPrimitive2D, PRIMITIVE2D_ID_SVGRADIALATOMPRIMITIVE2D) + sal_uInt32 SvgRadialAtomPrimitive2D::getPrimitive2DID() const + { + return PRIMITIVE2D_ID_SVGRADIALATOMPRIMITIVE2D; + } } // end of namespace |