diff options
author | Armin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de> | 2023-03-23 16:13:26 +0100 |
---|---|---|
committer | Armin Le Grand <Armin.Le.Grand@me.com> | 2023-03-23 17:14:04 +0000 |
commit | 462ebbd10bd537f42104fe991a0aeebcd563f178 (patch) | |
tree | 77ad4e2aa83424efa458f99a6e5deee5d321dfa0 /drawinglayer/source | |
parent | 7ecc9925f3b0d1cea4ee7201473dd6fbbb95c271 (diff) |
MCGR: Speedup Gradient Paint for VCLPixelProcessor
To do this, I re-organized FillGradientPrimitive2D and
how it creates it's decompose. This provides the needed
tooling to also do a more direct rendering in primitive
processors if needed.
The decompose no longer collects the matrices & colors
as a 1st step in a helper data struecture (so I removed
B2DHomMatrixAndBColor). It now uses a lambda function
callback that hands over the matrix & color for each
created step, so you can process it directly, in this
case to create the needed primitives.
NOTE: The decompositions are both tested. There was
createNonOverlappingFill, but also createOverlappingFill
that I am not sure is still used - and if in re-creating
an old, strange XOR-using gradient paint mechanism in
old metafiles (encapsulated with gradient info anyways),
but I converted that and made sure it works.
To do so I forced it to be used in paint. This is not
really usable in paint since we need to paint using AA
(else we would get staircase effects, esp. in new 'hard'
color changes in multi-color gradients) and - as should
be known - same edges painted in AA do *not* add up to
full opacity, but leave behind awful 'jaggies' (e.g.
opacity 0.5 and 0.5 create 0.75 and *not* 1.0). Still
important to have the working geometry creation for this
case.
This already makes the decompose faster, but the main
purpose is to use it as tooling for painting in own
primitive renderers.
Thus processFillGradientPrimitive2D now uses that
instead of using the decomposition by default.
This avoids one level of primitive creation, use
that new FillGradientPrimitive2D tooling to directly
create needed geoemtry & color for getting better
performance (to partially compensate for potentially
more expensive multi color gradients). It then paints
directly using OutputDevice calls.
NOTE: This can also be used in SDPRs as a 1st step
to just directly and rapidly render filled single-
color polygons, but of course there an implementation
using the back-transformations (which are also
adapted for MCGRs aleady and work) will be superior.
Change-Id: I5079f76d6d8fe86007a098614c276447f2bfebce
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149456
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Diffstat (limited to 'drawinglayer/source')
-rw-r--r-- | drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx | 255 | ||||
-rw-r--r-- | drawinglayer/source/processor2d/vclpixelprocessor2d.cxx | 84 | ||||
-rw-r--r-- | drawinglayer/source/texture/texture.cxx | 92 |
3 files changed, 234 insertions, 197 deletions
diff --git a/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx b/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx index c1246f1cce36..088e69357213 100644 --- a/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/fillgradientprimitive2d.cxx @@ -24,6 +24,7 @@ #include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx> #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx> #include <utility> +#include <algorithm> using namespace com::sun::star; @@ -31,12 +32,34 @@ using namespace com::sun::star; namespace drawinglayer::primitive2d { - void FillGradientPrimitive2D::generateMatricesAndColors( - std::vector< drawinglayer::texture::B2DHomMatrixAndBColor >& rEntries, - basegfx::BColor& rOuterColor) const + // Get the OuterColor. Take into account that for attribute::GradientStyle::Axial + // this is the last one due to inverted gradient usage (see constructor there) + basegfx::BColor FillGradientPrimitive2D::getOuterColor() const { - rEntries.clear(); + if (getFillGradient().getColorStops().empty()) + return basegfx::BColor(); + + if (attribute::GradientStyle::Axial == getFillGradient().getStyle()) + return getFillGradient().getColorStops().back().getStopColor(); + + return getFillGradient().getColorStops().front().getStopColor(); + } + + // Get the needed UnitPolygon dependent on the GradientStyle + basegfx::B2DPolygon FillGradientPrimitive2D::getUnitPolygon() const + { + if (attribute::GradientStyle::Radial == getFillGradient().getStyle() + || attribute::GradientStyle::Elliptical == getFillGradient().getStyle()) + { + return basegfx::utils::createPolygonFromCircle(basegfx::B2DPoint(0.0, 0.0), 1.0); + } + + return basegfx::utils::createPolygonFromRect(basegfx::B2DRange(-1.0, -1.0, 1.0, 1.0)); + } + void FillGradientPrimitive2D::generateMatricesAndColors( + std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)> aCallback) const + { switch(getFillGradient().getStyle()) { case attribute::GradientStyle::Linear: @@ -48,7 +71,7 @@ namespace drawinglayer::primitive2d getFillGradient().getColorStops(), getFillGradient().getBorder(), getFillGradient().getAngle()); - aGradient.appendTransformationsAndColors(rEntries, rOuterColor); + aGradient.appendTransformationsAndColors(aCallback); break; } case attribute::GradientStyle::Axial: @@ -60,7 +83,7 @@ namespace drawinglayer::primitive2d getFillGradient().getColorStops(), getFillGradient().getBorder(), getFillGradient().getAngle()); - aGradient.appendTransformationsAndColors(rEntries, rOuterColor); + aGradient.appendTransformationsAndColors(aCallback); break; } case attribute::GradientStyle::Radial: @@ -72,7 +95,7 @@ namespace drawinglayer::primitive2d getFillGradient().getBorder(), getFillGradient().getOffsetX(), getFillGradient().getOffsetY()); - aGradient.appendTransformationsAndColors(rEntries, rOuterColor); + aGradient.appendTransformationsAndColors(aCallback); break; } case attribute::GradientStyle::Elliptical: @@ -85,7 +108,7 @@ namespace drawinglayer::primitive2d getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle()); - aGradient.appendTransformationsAndColors(rEntries, rOuterColor); + aGradient.appendTransformationsAndColors(aCallback); break; } case attribute::GradientStyle::Square: @@ -98,7 +121,7 @@ namespace drawinglayer::primitive2d getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle()); - aGradient.appendTransformationsAndColors(rEntries, rOuterColor); + aGradient.appendTransformationsAndColors(aCallback); break; } case attribute::GradientStyle::Rect: @@ -111,134 +134,124 @@ namespace drawinglayer::primitive2d getFillGradient().getOffsetX(), getFillGradient().getOffsetY(), getFillGradient().getAngle()); - aGradient.appendTransformationsAndColors(rEntries, rOuterColor); + aGradient.appendTransformationsAndColors(aCallback); break; } } } - void FillGradientPrimitive2D::createOverlappingFill( - Primitive2DContainer& rContainer, - const std::vector< drawinglayer::texture::B2DHomMatrixAndBColor >& rEntries, - const basegfx::BColor& rOuterColor, - const basegfx::B2DPolygon& rUnitPolygon) const - { - // create solid fill with outmost color - rContainer.push_back( - new PolyPolygonColorPrimitive2D( - basegfx::B2DPolyPolygon( - basegfx::utils::createPolygonFromRect(getOutputRange())), - rOuterColor)); - - // create solid fill steps - for(const auto &a : rEntries) - { - // create part polygon - basegfx::B2DPolygon aNewPoly(rUnitPolygon); - - aNewPoly.transform(a.maB2DHomMatrix); - - // create solid fill - rContainer.push_back( - new PolyPolygonColorPrimitive2D( - basegfx::B2DPolyPolygon(aNewPoly), - a.maBColor)); - } - } - - void FillGradientPrimitive2D::createNonOverlappingFill( - Primitive2DContainer& rContainer, - const std::vector< drawinglayer::texture::B2DHomMatrixAndBColor >& rEntries, - const basegfx::BColor& rOuterColor, - const basegfx::B2DPolygon& rUnitPolygon) const + void FillGradientPrimitive2D::createFill(Primitive2DContainer& rContainer, bool bOverlapping) const { - // get outmost visible range from object - basegfx::B2DRange aOutmostRange(getOutputRange()); - basegfx::B2DPolyPolygon aCombinedPolyPoly; - - if(!rEntries.empty()) - { - // extend aOutmostRange with first polygon - basegfx::B2DPolygon aFirstPoly(rUnitPolygon); - - aFirstPoly.transform(rEntries[0].maB2DHomMatrix); - aCombinedPolyPoly.append(aFirstPoly); - aOutmostRange.expand(aFirstPoly.getB2DRange()); - } - - // add outmost range to combined polypolygon (in 1st place), create first primitive - aCombinedPolyPoly.insert(0, basegfx::utils::createPolygonFromRect(aOutmostRange)); - rContainer.push_back( - new PolyPolygonColorPrimitive2D( - aCombinedPolyPoly, - rOuterColor)); - - if(rEntries.empty()) - return; - - // reuse first polygon, it's the second one - aCombinedPolyPoly.remove(0); - - for(size_t a(0); a < rEntries.size() - 1; a++) + if (bOverlapping) { - // create next inner polygon, combined with last one - basegfx::B2DPolygon aNextPoly(rUnitPolygon); - - aNextPoly.transform(rEntries[a + 1].maB2DHomMatrix); - aCombinedPolyPoly.append(aNextPoly); - - // create primitive with correct color + // OverlappingFill: create solid fill with outmost color rContainer.push_back( new PolyPolygonColorPrimitive2D( - aCombinedPolyPoly, - rEntries[a].maBColor)); - - // reuse inner polygon, it's the 2nd one - aCombinedPolyPoly.remove(0); + basegfx::B2DPolyPolygon( + basegfx::utils::createPolygonFromRect(getOutputRange())), + getOuterColor())); + + // create solid fill steps by providing callback as lambda + auto aCallback([&rContainer,this]( + const basegfx::B2DHomMatrix& rMatrix, + const basegfx::BColor& rColor) + { + // create part polygon + basegfx::B2DPolygon aNewPoly(getUnitPolygon()); + aNewPoly.transform(rMatrix); + + // create solid fill + rContainer.push_back( + new PolyPolygonColorPrimitive2D( + basegfx::B2DPolyPolygon(aNewPoly), + rColor)); + }); + + // call value generator to trigger callbacks + generateMatricesAndColors(aCallback); } - - // add last inner polygon with last color - rContainer.push_back( - new PolyPolygonColorPrimitive2D( - std::move(aCombinedPolyPoly), - rEntries[rEntries.size() - 1].maBColor)); - } - - void FillGradientPrimitive2D::createFill(Primitive2DContainer& rContainer, bool bOverlapping) const - { - // prepare shape of the Unit Polygon - basegfx::B2DPolygon aUnitPolygon; - - switch(getFillGradient().getStyle()) + else { - case attribute::GradientStyle::Radial: - case attribute::GradientStyle::Elliptical: + // NonOverlappingFill + if (getFillGradient().getColorStops().size() < 2) { - aUnitPolygon = basegfx::utils::createPolygonFromCircle(basegfx::B2DPoint(0.0, 0.0), 1.0); - break; + // not really a gradient, we need to create a start primitive + // entry using the single color and the covered area + const basegfx::B2DRange aOutmostRange(getOutputRange()); + rContainer.push_back( + new PolyPolygonColorPrimitive2D( + basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aOutmostRange)), + getOuterColor())); } - default: // GradientStyle::Linear, attribute::GradientStyle::Axial, attribute::GradientStyle::Square, attribute::GradientStyle::Rect + else { - aUnitPolygon = basegfx::utils::createPolygonFromRect(basegfx::B2DRange(-1.0, -1.0, 1.0, 1.0)); - break; + // gradient with stops, prepare CombinedPolyPoly, use callback + basegfx::B2DPolyPolygon aCombinedPolyPoly; + basegfx::BColor aLastColor; + + auto aCallback([&rContainer,&aCombinedPolyPoly,&aLastColor,this]( + const basegfx::B2DHomMatrix& rMatrix, + const basegfx::BColor& rColor) + { + if (rContainer.empty()) + { + // 1st callback, init CombinedPolyPoly & create 1st entry + basegfx::B2DRange aOutmostRange(getOutputRange()); + + // expand aOutmostRange with transformed first polygon + // to ensure confinement + basegfx::B2DPolygon aFirstPoly(getUnitPolygon()); + aFirstPoly.transform(rMatrix); + aOutmostRange.expand(aFirstPoly.getB2DRange()); + + // build 1st combined polygon; outmost range 1st, then + // the shaped, transformed polygon + aCombinedPolyPoly.append(basegfx::utils::createPolygonFromRect(aOutmostRange)); + aCombinedPolyPoly.append(aFirstPoly); + + // create first primitive + rContainer.push_back( + new PolyPolygonColorPrimitive2D( + aCombinedPolyPoly, + getOuterColor())); + + // save first polygon for re-use in next call, it's the second + // one, so remove 1st + aCombinedPolyPoly.remove(0); + + // remember color for next primitive creation + aLastColor = rColor; + } + else + { + // regular n-th callback, create combined entry by re-using + // CombinedPolyPoly and aLastColor + basegfx::B2DPolygon aNextPoly(getUnitPolygon()); + aNextPoly.transform(rMatrix); + aCombinedPolyPoly.append(aNextPoly); + + // create primitive with correct color + rContainer.push_back( + new PolyPolygonColorPrimitive2D( + aCombinedPolyPoly, + aLastColor)); + + // prepare re-use of inner polygon, save color + aCombinedPolyPoly.remove(0); + aLastColor = rColor; + } + }); + + // call value generator to trigger callbacks + generateMatricesAndColors(aCallback); + + // add last inner polygon with last color + rContainer.push_back( + new PolyPolygonColorPrimitive2D( + aCombinedPolyPoly, + aLastColor)); } } - - // get the transform matrices and colors (where colors - // will have one more entry that matrices) - std::vector< drawinglayer::texture::B2DHomMatrixAndBColor > aEntries; - basegfx::BColor aOuterColor; - - generateMatricesAndColors(aEntries, aOuterColor); - - if(bOverlapping) - { - createOverlappingFill(rContainer, aEntries, aOuterColor, aUnitPolygon); - } - else - { - createNonOverlappingFill(rContainer, aEntries, aOuterColor, aUnitPolygon); - } } void FillGradientPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*rViewInformation*/) const diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx index 9f0875e2f489..d6a259157886 100644 --- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx @@ -950,13 +950,13 @@ void VclPixelProcessor2D::processFillGradientPrimitive2D( const primitive2d::FillGradientPrimitive2D& rPrimitive) { const attribute::FillGradientAttribute& rFillGradient = rPrimitive.getFillGradient(); + bool useDecompose(false); // MCGR: *many* - and not only GradientStops - cases cannot be handled by VCL // so use decomposition if (rFillGradient.cannotBeHandledByVCL()) { - process(rPrimitive); - return; + useDecompose = true; } // tdf#149754 VCL gradient draw is not capable to handle all primitive gradient definitions, @@ -972,27 +972,87 @@ void VclPixelProcessor2D::processFillGradientPrimitive2D( // I see no real reason to fallback here to OutputDevice::DrawGradient and VCL // gradient paint at all (system-dependent renderers wouldn't in the future), but // will for convenience only add that needed additional correcting case - if (!rPrimitive.getDefinitionRange().isInside(rPrimitive.getOutputRange())) + if (!useDecompose && !rPrimitive.getDefinitionRange().isInside(rPrimitive.getOutputRange())) { - process(rPrimitive); - return; + useDecompose = true; } // tdf#151081 need to use regular primitive decomposition when the gradient // is transformed in any other way then just translate & scale - basegfx::B2DVector aScale, aTranslate; - double fRotate, fShearX; + if (!useDecompose) + { + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + + maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX); - maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + // detect if transformation is rotated, sheared or mirrored in X and/or Y + if (!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX) + || aScale.getX() < 0.0 || aScale.getY() < 0.0) + { + useDecompose = true; + } + } - // detect if transformation is rotated, sheared or mirrored in X and/or Y - if (!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX) - || aScale.getX() < 0.0 || aScale.getY() < 0.0) + if (useDecompose) { - process(rPrimitive); + // default is to use the direct render below. For security, + // keep the (simple) fallback to decompose in place here + static bool bTryDirectRender(true); + + if (bTryDirectRender) + { + // MCGR: Avoid one level of primitive creation, use FillGradientPrimitive2D + // tooling to directly create needed geoemtry & color for getting better + // performance (partially compensate for potentially more expensive multi + // color gradients). + // To handle a primitive that needs paint, either use decompose, or - when you + // do not want that for any reason, e.g. extra primitives created - implement + // a direct handling in your primitive rendererer. This is always possible + // since primitives by definition are self-contained what means they have all + // needed data locally available to do so. + // The question is the complexity to invest - the implemented decompose + // is always a good hint what is neeed to do this. In this case I decided + // to add some tooling methods to the primitive itself to support this. These + // are used in decompose and can be used - as here now - for direct handling, + // too. This is always a possibility in primitive handling - you can, but do not + // have to. + mpOutputDevice->SetFillColor( + Color(maBColorModifierStack.getModifiedColor(rPrimitive.getOuterColor()))); + mpOutputDevice->SetLineColor(); + mpOutputDevice->DrawTransparent( + maCurrentTransformation, + basegfx::B2DPolyPolygon( + basegfx::utils::createPolygonFromRect(rPrimitive.getOutputRange())), + 0.0); + + // paint solid fill steps by providing callback as lambda + auto aCallback([&rPrimitive, this](const basegfx::B2DHomMatrix& rMatrix, + const basegfx::BColor& rColor) { + // create part polygon + basegfx::B2DPolygon aNewPoly(rPrimitive.getUnitPolygon()); + aNewPoly.transform(rMatrix); + + // create solid fill + mpOutputDevice->SetFillColor(Color(maBColorModifierStack.getModifiedColor(rColor))); + mpOutputDevice->DrawTransparent(maCurrentTransformation, + basegfx::B2DPolyPolygon(aNewPoly), 0.0); + }); + + // call value generator to trigger callbacks + rPrimitive.generateMatricesAndColors(aCallback); + } + else + { + // use the decompose + process(rPrimitive); + } + return; } + // try to use vcl - since vcl uses the old gradient paint mechanisms this may + // create wrong geometries. If so, add another case above for useDecompose GradientStyle eGradientStyle = convertGradientStyle(rFillGradient.getStyle()); Gradient aGradient(eGradientStyle, Color(rFillGradient.getColorStops().front().getStopColor()), diff --git a/drawinglayer/source/texture/texture.cxx b/drawinglayer/source/texture/texture.cxx index de0f02057b4e..1390ee3d82bf 100644 --- a/drawinglayer/source/texture/texture.cxx +++ b/drawinglayer/source/texture/texture.cxx @@ -167,16 +167,12 @@ namespace drawinglayer::texture } void GeoTexSvxGradientLinear::appendTransformationsAndColors( - std::vector< B2DHomMatrixAndBColor >& rEntries, - basegfx::BColor& rOuterColor) + std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)> aCallback) { // no color at all, done if (mnColorStops.empty()) return; - // fill in return parameter rOuterColor before returning - rOuterColor = mnColorStops.front().getStopColor(); - // only one color, done if (mnColorStops.size() < 2) return; @@ -217,9 +213,9 @@ namespace drawinglayer::texture const double fStripeWidth((fOffsetEnd - fOffsetStart) / nSteps); // for the 1st color range we do not need to create the 1st step - // since it will be equal to StartColor and thus rOuterColor, so + // since it will be equal to StartColor and thus OuterColor, so // will be painted by the 1st, always-created background polygon - // colored using rOuterColor. + // colored using OuterColor. // We *need* to create this though for all 'inner' color ranges // to get a correct start const sal_uInt32 nStartInnerLoop(cs_l == mnColorStops.begin() ? 1 : 0); @@ -244,11 +240,9 @@ namespace drawinglayer::texture aNew.translate(0.0, fPos); // set and add at target - B2DHomMatrixAndBColor aB2DHomMatrixAndBColor; - - aB2DHomMatrixAndBColor.maB2DHomMatrix = maGradientInfo.getTextureTransform() * aNew; - aB2DHomMatrixAndBColor.maBColor = interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)); - rEntries.push_back(aB2DHomMatrixAndBColor); + aCallback( + maGradientInfo.getTextureTransform() * aNew, + interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1))); } } @@ -312,16 +306,12 @@ namespace drawinglayer::texture } void GeoTexSvxGradientAxial::appendTransformationsAndColors( - std::vector< B2DHomMatrixAndBColor >& rEntries, - basegfx::BColor& rOuterColor) + std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)> aCallback) { // no color at all, done if (mnColorStops.empty()) return; - // fill in return parameter rOuterColor before returning - rOuterColor = mnColorStops.front().getStopColor(); - // only one color, done if (mnColorStops.size() < 2) return; @@ -374,11 +364,9 @@ namespace drawinglayer::texture aNew.scale(1.0, 1.0 - fPos); // set and add at target - B2DHomMatrixAndBColor aB2DHomMatrixAndBColor; - - aB2DHomMatrixAndBColor.maB2DHomMatrix = maGradientInfo.getTextureTransform() * aNew; - aB2DHomMatrixAndBColor.maBColor = interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)); - rEntries.push_back(aB2DHomMatrixAndBColor); + aCallback( + maGradientInfo.getTextureTransform() * aNew, + interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1))); } } @@ -429,16 +417,12 @@ namespace drawinglayer::texture } void GeoTexSvxGradientRadial::appendTransformationsAndColors( - std::vector< B2DHomMatrixAndBColor >& rEntries, - basegfx::BColor& rOuterColor) + std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)> aCallback) { // no color at all, done if (mnColorStops.empty()) return; - // fill in return parameter rOuterColor before returning - rOuterColor = mnColorStops.front().getStopColor(); - // only one color, done if (mnColorStops.size() < 2) return; @@ -475,11 +459,9 @@ namespace drawinglayer::texture const double fSize(1.0 - (fOffsetStart + (fStripeWidth * innerLoop))); // set and add at target - B2DHomMatrixAndBColor aB2DHomMatrixAndBColor; - - aB2DHomMatrixAndBColor.maB2DHomMatrix = maGradientInfo.getTextureTransform() * basegfx::utils::createScaleB2DHomMatrix(fSize, fSize); - aB2DHomMatrixAndBColor.maBColor = interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)); - rEntries.push_back(aB2DHomMatrixAndBColor); + aCallback( + maGradientInfo.getTextureTransform() * basegfx::utils::createScaleB2DHomMatrix(fSize, fSize), + interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1))); } } @@ -529,16 +511,12 @@ namespace drawinglayer::texture } void GeoTexSvxGradientElliptical::appendTransformationsAndColors( - std::vector< B2DHomMatrixAndBColor >& rEntries, - basegfx::BColor& rOuterColor) + std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)> aCallback) { // no color at all, done if (mnColorStops.empty()) return; - // fill in return parameter rOuterColor before returning - rOuterColor = mnColorStops.front().getStopColor(); - // only one color, done if (mnColorStops.size() < 2) return; @@ -579,14 +557,12 @@ namespace drawinglayer::texture const double fSize(fOffsetStart + (fStripeWidth * innerLoop)); // set and add at target - B2DHomMatrixAndBColor aB2DHomMatrixAndBColor; - - aB2DHomMatrixAndBColor.maB2DHomMatrix = maGradientInfo.getTextureTransform() + aCallback( + maGradientInfo.getTextureTransform() * basegfx::utils::createScaleB2DHomMatrix( 1.0 - (bMTO ? fSize / fAR : fSize), - 1.0 - (bMTO ? fSize : fSize * fAR)); - aB2DHomMatrixAndBColor.maBColor = interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)); - rEntries.push_back(aB2DHomMatrixAndBColor); + 1.0 - (bMTO ? fSize : fSize * fAR)), + interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1))); } } @@ -636,16 +612,12 @@ namespace drawinglayer::texture } void GeoTexSvxGradientSquare::appendTransformationsAndColors( - std::vector< B2DHomMatrixAndBColor >& rEntries, - basegfx::BColor& rOuterColor) + std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)> aCallback) { // no color at all, done if (mnColorStops.empty()) return; - // fill in return parameter rOuterColor before returning - rOuterColor = mnColorStops.front().getStopColor(); - // only one color, done if (mnColorStops.size() < 2) return; @@ -682,11 +654,9 @@ namespace drawinglayer::texture const double fSize(1.0 - (fOffsetStart + (fStripeWidth * innerLoop))); // set and add at target - B2DHomMatrixAndBColor aB2DHomMatrixAndBColor; - - aB2DHomMatrixAndBColor.maB2DHomMatrix = maGradientInfo.getTextureTransform() * basegfx::utils::createScaleB2DHomMatrix(fSize, fSize); - aB2DHomMatrixAndBColor.maBColor = interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)); - rEntries.push_back(aB2DHomMatrixAndBColor); + aCallback( + maGradientInfo.getTextureTransform() * basegfx::utils::createScaleB2DHomMatrix(fSize, fSize), + interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1))); } } @@ -736,16 +706,12 @@ namespace drawinglayer::texture } void GeoTexSvxGradientRect::appendTransformationsAndColors( - std::vector< B2DHomMatrixAndBColor >& rEntries, - basegfx::BColor& rOuterColor) + std::function<void(const basegfx::B2DHomMatrix& rMatrix, const basegfx::BColor& rColor)> aCallback) { // no color at all, done if (mnColorStops.empty()) return; - // fill in return parameter rOuterColor before returning - rOuterColor = mnColorStops.front().getStopColor(); - // only one color, done if (mnColorStops.size() < 2) return; @@ -786,14 +752,12 @@ namespace drawinglayer::texture const double fSize(fOffsetStart + (fStripeWidth * innerLoop)); // set and add at target - B2DHomMatrixAndBColor aB2DHomMatrixAndBColor; - - aB2DHomMatrixAndBColor.maB2DHomMatrix = maGradientInfo.getTextureTransform() + aCallback( + maGradientInfo.getTextureTransform() * basegfx::utils::createScaleB2DHomMatrix( 1.0 - (bMTO ? fSize / fAR : fSize), - 1.0 - (bMTO ? fSize : fSize * fAR)); - aB2DHomMatrixAndBColor.maBColor = interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1)); - rEntries.push_back(aB2DHomMatrixAndBColor); + 1.0 - (bMTO ? fSize : fSize * fAR)), + interpolate(aCStart, aCEnd, double(innerLoop) / double(nSteps - 1))); } } |