summaryrefslogtreecommitdiff
path: root/drawinglayer/source
diff options
context:
space:
mode:
authorArmin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de>2023-03-23 16:13:26 +0100
committerArmin Le Grand <Armin.Le.Grand@me.com>2023-03-23 17:14:04 +0000
commit462ebbd10bd537f42104fe991a0aeebcd563f178 (patch)
tree77ad4e2aa83424efa458f99a6e5deee5d321dfa0 /drawinglayer/source
parent7ecc9925f3b0d1cea4ee7201473dd6fbbb95c271 (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.cxx255
-rw-r--r--drawinglayer/source/processor2d/vclpixelprocessor2d.cxx84
-rw-r--r--drawinglayer/source/texture/texture.cxx92
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)));
}
}