summaryrefslogtreecommitdiff
path: root/basegfx
diff options
context:
space:
mode:
authorArmin Le Grand (allotropia) <armin.le.grand.extern@allotropia.de>2023-06-05 17:15:34 +0200
committerArmin Le Grand <Armin.Le.Grand@me.com>2023-06-09 10:17:07 +0200
commita6e72e2b314e64f3199f3eaf1ecf78157446f6dd (patch)
treee830caf26f28e3090868159687e504779759ea3c /basegfx
parentbbf5f97967fb3cde25829e1c428ace31d7d5b8c7 (diff)
MCGR: tdf#155479 repair gradient SVG export for MCGR
Unfortunately SVG export is based on metafiles and thus there is (in principle) no way to get the BGradient/ColorStop/MCGR data transfered as needed. For that, using UNO API to read the model or using B2DPrimitives would help - as is better for the export respectively. Since there is not the time to re-design SVG export I added this 'compromize' as a fix. It gets the needed data transported over the metafile (that part is the compromize). It then exports the MCGR data to SVG (at least - as was already there - if it's a linear/axial gradient). This happens now with all Gradient Stops when there is a MCGR gradient. That part is/will hopefully be re-usable if SVG export gets redesigned. I also added a handling for StepCount feature, so when used (in LO, others do not have that) 'hard' color stops get generated to make the gradient look identical for SVG export. Had to make adding of that extra-information in metafiles dependent on exporting really to SVG. There are 51 cases which use 'MetaActionType::COMMENT' which would potentially have to be adapted. Also added code to solve the problem for TransparencePrimitive2D at VclMetafileProcessor2D::processTransparencePrimitive2D. This will now - also only for SVG export - directly create the needed MetaFloatTransparentAction and add additional MCGR information. This will be used on SVG export to write a 'Mask' as was done before. This is now capable of creating fill MCGR-Masks in the sense that any number of TransparencyStops will be supported. Change-Id: Ic6d022714eae96b8fbc09e60652851ac5799b757 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152623 Tested-by: Jenkins Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Diffstat (limited to 'basegfx')
-rw-r--r--basegfx/source/tools/bgradient.cxx137
1 files changed, 137 insertions, 0 deletions
diff --git a/basegfx/source/tools/bgradient.cxx b/basegfx/source/tools/bgradient.cxx
index b56ef0540d17..c96cd0b673cb 100644
--- a/basegfx/source/tools/bgradient.cxx
+++ b/basegfx/source/tools/bgradient.cxx
@@ -679,6 +679,117 @@ bool BColorStops::isSymmetrical() const
return aIter > aRIter;
}
+void BColorStops::doApplyAxial()
+{
+ // preapare new ColorStops
+ basegfx::BColorStops aNewColorStops;
+
+ // add gradient stops in reverse order, scaled to [0.0 .. 0.5]
+ basegfx::BColorStops::const_reverse_iterator aRevCurrColor(rbegin());
+
+ while (aRevCurrColor != rend())
+ {
+ aNewColorStops.emplace_back((1.0 - aRevCurrColor->getStopOffset()) * 0.5,
+ aRevCurrColor->getStopColor());
+ aRevCurrColor++;
+ }
+
+ // prepare non-reverse run
+ basegfx::BColorStops::const_iterator aCurrColor(begin());
+
+ if (basegfx::fTools::equalZero(aCurrColor->getStopOffset()))
+ {
+ // Caution: do not add 1st entry again, that would be double since it was
+ // already added as last element of the inverse run above. But only if
+ // the gradient has a start entry for 0.0 aka StartColor, else it is correct.
+ aCurrColor++;
+ }
+
+ // add gradient stops in non-reverse order, translated and scaled to [0.5 .. 1.0]
+ while (aCurrColor != end())
+ {
+ aNewColorStops.emplace_back((aCurrColor->getStopOffset() * 0.5) + 0.5,
+ aCurrColor->getStopColor());
+ aCurrColor++;
+ }
+
+ // apply color stops
+ *this = aNewColorStops;
+}
+
+void BColorStops::doApplySteps(sal_uInt16 nStepCount)
+{
+ // check for zero or invalid steps setting -> done
+ if (0 == nStepCount || nStepCount > 100)
+ return;
+
+ // no change needed if single color
+ BColor aSingleColor;
+ if (isSingleColor(aSingleColor))
+ return;
+
+ // prepare new color stops, get L/R iterators for segments
+ basegfx::BColorStops aNewColorStops;
+ basegfx::BColorStops::const_iterator aColorR(begin());
+ basegfx::BColorStops::const_iterator aColorL(aColorR++);
+
+ while (aColorR != end())
+ {
+ // get start/end color for segment
+ const double fStart(aColorL->getStopOffset());
+ const double fDelta(aColorR->getStopOffset() - fStart);
+
+ if (aNewColorStops.empty() || aNewColorStops.back() != *aColorL)
+ {
+ // add start color, but check if it is already there - which is the
+ // case from the 2nd segment on due to a new segment starting with
+ // the same color as the previous one ended
+ aNewColorStops.push_back(*aColorL);
+ }
+
+ if (!basegfx::fTools::equalZero(fDelta))
+ {
+ // create in-between steps, always two at the same positon to
+ // define a 'hard' color stop. Get start/end color for the segment
+ const basegfx::BColor& rStartColor(aColorL->getStopColor());
+ const basegfx::BColor& rEndColor(aColorR->getStopColor());
+
+ if (rStartColor != rEndColor)
+ {
+ // get relative single-step width
+ const double fSingleStep(1.0 / static_cast<double>(nStepCount));
+
+ for (sal_uInt16 a(1); a < nStepCount; a++)
+ {
+ // calculate position since being used twice
+ const double fPosition(fStart
+ + (fDelta * (static_cast<double>(a) * fSingleStep)));
+
+ // add start color of sub-segment
+ aNewColorStops.emplace_back(
+ fPosition, basegfx::interpolate(rStartColor, rEndColor,
+ static_cast<double>(a - 1) * fSingleStep));
+
+ // add end color of sub-segment
+ aNewColorStops.emplace_back(
+ fPosition, basegfx::interpolate(rStartColor, rEndColor,
+ static_cast<double>(a) * fSingleStep));
+ }
+ }
+ }
+
+ // always add end color of segment
+ aNewColorStops.push_back(*aColorR);
+
+ // next segment
+ aColorL++;
+ aColorR++;
+ }
+
+ // apply the change to color stops
+ *this = aNewColorStops;
+}
+
std::string BGradient::GradientStyleToString(css::awt::GradientStyle eStyle)
{
switch (eStyle)
@@ -1022,6 +1133,32 @@ void BGradient::tryToConvertToAxial()
SetColorStops(aAxialColorStops);
}
+
+void BGradient::tryToApplyAxial()
+{
+ // only need to do something if css::awt::GradientStyle_AXIAL, else done
+ if (GetGradientStyle() != css::awt::GradientStyle_AXIAL)
+ return;
+
+ // apply the change to color stops
+ aColorStops.doApplyAxial();
+
+ // set style to GradientStyle_LINEAR
+ SetGradientStyle(css::awt::GradientStyle_LINEAR);
+}
+
+void BGradient::tryToApplySteps()
+{
+ // check for zero or invalid steps setting -> done
+ if (0 == GetSteps() || GetSteps() > 100)
+ return;
+
+ // do the action
+ aColorStops.doApplySteps(GetSteps());
+
+ // set value to default
+ SetSteps(0);
+}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */